diff --git a/autobuild.xml b/autobuild.xml index 88db33e3176a2767d77c08b4fbaa752049c27be8..b182b7ae5d6d35b7efe02e461b6d92f5ab1d80fd 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3138,9 +3138,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>42066e2447c7a3359784438d16510992</string> + <string>c5ab9d9d7482e48cd76f4bf391900a8c</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/40539/348124/viewer_manager-2.0.529188-darwin64-529188.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/43369/385585/viewer_manager-2.0.531000-darwin64-531000.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -3162,9 +3162,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>ca230428635ce13cb7ace0f9522f8546</string> + <string>6b10d7407686d9e12e63576256581e3e</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/40538/348130/viewer_manager-2.0.529188-windows-529188.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/43370/385592/viewer_manager-2.0.531000-windows-531000.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -3175,7 +3175,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>source_type</key> <string>hg</string> <key>version</key> - <string>2.0.529188</string> + <string>2.0.531000</string> </map> <key>vlc-bin</key> <map> diff --git a/doc/contributions.txt b/doc/contributions.txt index ca2e63cf9f8b6c73802bc00a596340e1ebc1ef75..c6ad23dc2c117dead9661ef346962959b832de50 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -347,6 +347,7 @@ Charles Courtois Charlie Sazaland Chaser Zaks BUG-225599 + BUG-227485 Cherry Cheevers ChickyBabes Zuzu Christopher Organiser diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 2b54cd41552485e882411ad79608b2b8b4933057..a5770c5528dd38ed50af1c45ae1e109f18788af7 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -186,12 +186,17 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") list(GET LL_BUILD_LIST "${sysroot_idx}" CMAKE_OSX_SYSROOT) message(STATUS "CMAKE_OSX_SYSROOT = '${CMAKE_OSX_SYSROOT}'") - set(XCODE_VERSION 7.0) - set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0") set(CMAKE_XCODE_ATTRIBUTE_GCC_STRICT_ALIASING NO) set(CMAKE_XCODE_ATTRIBUTE_GCC_FAST_MATH NO) set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS ssse3) + # we must hard code this to off for now. xcode's built in signing does not + # handle embedded app bundles such as CEF and others. Any signing for local + # development must be done after the build as we do in viewer_manifest.py for + # released builds + # https://stackoverflow.com/a/54296008 + # "-" represents "Sign to Run Locally" and empty string represents "Do Not Sign" + set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "") set(CMAKE_OSX_ARCHITECTURES "${ARCH}") string(REPLACE "i686" "i386" CMAKE_OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index 6ab61689fd0532a8f67c65576ed2cd0c7bfcda94..e7db84f6ab2783b048a778ae5f1ef551bfa012cd 100644 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -271,7 +271,7 @@ BOOL LLVorbisDecodeState::initDecode() mWAVBuffer.reserve(size_guess); mWAVBuffer.resize(WAV_HEADER_SIZE); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { LL_WARNS("AudioEngine") << "Out of memory when trying to alloc buffer: " << size_guess << LL_ENDL; delete mInFilep; diff --git a/indra/llcharacter/llgesture.cpp b/indra/llcharacter/llgesture.cpp index 1549c41e624e87b9f7a6b2a07d9501fbed7750d9..37904936d86a9eba74b76a7c2fbca6332ffd9f9d 100644 --- a/indra/llcharacter/llgesture.cpp +++ b/indra/llcharacter/llgesture.cpp @@ -107,11 +107,11 @@ BOOL LLGesture::trigger(const std::string& trigger_string) // NOT endian-neutral U8 *LLGesture::serialize(U8 *buffer) const { - htonmemcpy(buffer, &mKey, MVT_S8, 1); + htolememcpy(buffer, &mKey, MVT_S8, 1); buffer += sizeof(mKey); - htonmemcpy(buffer, &mMask, MVT_U32, 4); + htolememcpy(buffer, &mMask, MVT_U32, 4); buffer += sizeof(mMask); - htonmemcpy(buffer, mSoundItemID.mData, MVT_LLUUID, 16); + htolememcpy(buffer, mSoundItemID.mData, MVT_LLUUID, 16); buffer += 16; memcpy(buffer, mTrigger.c_str(), mTrigger.length() + 1); /* Flawfinder: ignore */ @@ -134,11 +134,11 @@ U8 *LLGesture::deserialize(U8 *buffer, S32 max_size) return buffer; } - htonmemcpy(&mKey, tmp, MVT_S8, 1); + htolememcpy(&mKey, tmp, MVT_S8, 1); tmp += sizeof(mKey); - htonmemcpy(&mMask, tmp, MVT_U32, 4); + htolememcpy(&mMask, tmp, MVT_U32, 4); tmp += sizeof(mMask); - htonmemcpy(mSoundItemID.mData, tmp, MVT_LLUUID, 16); + htolememcpy(mSoundItemID.mData, tmp, MVT_LLUUID, 16); tmp += 16; mTrigger.assign((char *)tmp); @@ -284,7 +284,7 @@ U8 *LLGestureList::serialize(U8 *buffer) const { // a single S32 serves as the header that tells us how many to read U32 count = mList.size(); - htonmemcpy(buffer, &count, MVT_S32, 4); + htolememcpy(buffer, &count, MVT_S32, 4); buffer += sizeof(count); for (S32 i = 0; i < count; i++) @@ -310,7 +310,7 @@ U8 *LLGestureList::deserialize(U8 *buffer, S32 max_size) return buffer; } - htonmemcpy(&count, tmp, MVT_S32, 4); + htolememcpy(&count, tmp, MVT_S32, 4); if (count > MAX_GESTURES) { diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index af41b9e460c75a609d213eae4f808734a9c4f80b..7e52a620dbcc899cf42fe3cd702fe22a027430b1 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -73,6 +73,7 @@ set(llcommon_SOURCE_FILES llinitparam.cpp llinitdestroyclass.cpp llinstancetracker.cpp + llkeybind.cpp llleap.cpp llleaplistener.cpp llliveappconfig.cpp @@ -183,6 +184,7 @@ set(llcommon_HEADER_FILES llinitdestroyclass.h llinitparam.h llinstancetracker.h + llkeybind.h llkeythrottle.h llleap.h llleaplistener.h diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 0fbf4b966b2becc9e4a68ec57e48c92b64d5abb0..ef29e7e5cd2460ca8634768a89543a389fb672c3 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -54,6 +54,17 @@ enum ETerrainBrushType E_LANDBRUSH_INVALID = 6 }; +enum EMouseClickType{ + CLICK_NONE = -1, + CLICK_LEFT = 0, + CLICK_MIDDLE, + CLICK_RIGHT, + CLICK_BUTTON4, + CLICK_BUTTON5, + CLICK_DOUBLELEFT, + CLICK_COUNT // 'size', CLICK_NONE does not counts +}; + // keys // Bit masks for various keyboard modifier keys. const MASK MASK_NONE = 0x0000; diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 29f0c7da9a39ee1ac9d6906a51519cf621dc44a3..984e90f37627116b3f7eb9f2b7ad132c280d830a 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -240,6 +240,64 @@ void _ll_apr_assert_status(apr_status_t status, const char* file, int line) llassert(! _ll_apr_warn_status(status, file, line)); } +//--------------------------------------------------------------------- +// +// Scope based pool access +// +//--------------------------------------------------------------------- + +class LLAPRFilePoolScope +{ +public: + LLAPRFilePoolScope() : pPool(NULL), mInitialized(false) {} + LLAPRFilePoolScope(LLVolatileAPRPool* poolp) : mInitialized(false) + { + setFilePool(poolp); + } + ~LLAPRFilePoolScope() + { + reset(); + } + apr_pool_t* getVolatileAPRPool(LLVolatileAPRPool* poolp = NULL) + { + if (!pPool) + { + setFilePool(poolp); + } + if (mInitialized) + { + // We need one clear per one get + // At the moment no need to support multiple calls + LL_ERRS() << "LLAPRFilePoolScope is not supposed to be initialized twice" << LL_ENDL; + } + mInitialized = true; + return pPool->getVolatileAPRPool(); + } + void reset() + { + if (mInitialized) + { + pPool->clearVolatileAPRPool(); + } + } + +private: + void setFilePool(LLVolatileAPRPool* poolp = NULL) + { + if (poolp) + { + pPool = poolp; + } + else + { + pPool = LLAPRFile::sAPRFilePoolp; + } + } + + LLVolatileAPRPool *pPool; + bool mInitialized; +}; + //--------------------------------------------------------------------- // // LLAPRFile functions @@ -287,9 +345,10 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLV //check if already open some file llassert_always(!mFile) ; llassert_always(!mCurrentFilePoolp) ; - - apr_pool_t* apr_pool = pool ? pool->getVolatileAPRPool() : NULL ; - s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(apr_pool)); + + mCurrentFilePoolp = pool ? pool : sAPRFilePoolp; + apr_pool_t* apr_pool = mCurrentFilePoolp->getVolatileAPRPool(); //paired with clear in close() + s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); if (s != APR_SUCCESS || !mFile) { @@ -314,14 +373,10 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLV *sizep = file_size; } - if(!mCurrentFilePoolp) + if (!mFile) { - mCurrentFilePoolp = pool ; - - if(!mFile) - { - close() ; - } + // It will clean pool + close() ; } return s ; @@ -348,17 +403,6 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOO return s; } -apr_pool_t* LLAPRFile::getAPRFilePool(apr_pool_t* pool) -{ - if(!pool) - { - mCurrentFilePoolp = sAPRFilePoolp ; - return mCurrentFilePoolp->getVolatileAPRPool() ; - } - - return pool ; -} - // File I/O S32 LLAPRFile::read(void *buf, S32 nbytes) { @@ -415,7 +459,7 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset) // //static -apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool) +apr_status_t LLAPRFile::close(apr_file_t* file_handle) { apr_status_t ret = APR_SUCCESS ; if(file_handle) @@ -424,29 +468,23 @@ apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool) file_handle = NULL ; } - if(pool) - { - pool->clearVolatileAPRPool() ; - } - return ret ; } //static -apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags) +apr_file_t* LLAPRFile::open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags) { apr_status_t s; apr_file_t* file_handle ; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool()); + s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); if (s != APR_SUCCESS || !file_handle) { ll_apr_warn_status(s); LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL; file_handle = NULL ; - close(file_handle, pool) ; + close(file_handle) ; return NULL; } @@ -489,8 +527,9 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset) S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) { //***************************************** - apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY); - //***************************************** + LLAPRFilePoolScope scope(pool); + apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), APR_READ|APR_BINARY); + //***************************************** if (!file_handle) { return 0; @@ -523,7 +562,7 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb } //***************************************** - close(file_handle, pool) ; + close(file_handle) ; //***************************************** return (S32)bytes_read; } @@ -537,9 +576,10 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n flags |= APR_APPEND; offset = 0; } - + //***************************************** - apr_file_t* file_handle = open(filename, pool, flags); + LLAPRFilePoolScope scope(pool); + apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), flags); //***************************************** if (!file_handle) { @@ -573,7 +613,7 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n } //***************************************** - LLAPRFile::close(file_handle, pool); + LLAPRFile::close(file_handle); //***************************************** return (S32)bytes_written; @@ -584,9 +624,8 @@ bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool) { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_remove(filename.c_str(), pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLAPRFilePoolScope scope(pool); + s = apr_file_remove(filename.c_str(), scope.getVolatileAPRPool()); if (s != APR_SUCCESS) { @@ -602,9 +641,8 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname, { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_rename(filename.c_str(), newname.c_str(), pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLAPRFilePoolScope scope(pool); + s = apr_file_rename(filename.c_str(), newname.c_str(), scope.getVolatileAPRPool()); if (s != APR_SUCCESS) { @@ -621,18 +659,16 @@ bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, ap apr_file_t* apr_file; apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool()); + LLAPRFilePoolScope scope(pool); + s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, scope.getVolatileAPRPool()); if (s != APR_SUCCESS || !apr_file) { - pool->clearVolatileAPRPool() ; return false; } else { apr_file_close(apr_file) ; - pool->clearVolatileAPRPool() ; return true; } } @@ -643,14 +679,12 @@ S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool) apr_file_t* apr_file; apr_finfo_t info; apr_status_t s; - - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool->getVolatileAPRPool()); + + LLAPRFilePoolScope scope(pool); + s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, scope.getVolatileAPRPool()); if (s != APR_SUCCESS || !apr_file) - { - pool->clearVolatileAPRPool() ; - + { return 0; } else @@ -658,7 +692,6 @@ S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool) apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); apr_file_close(apr_file) ; - pool->clearVolatileAPRPool() ; if (s == APR_SUCCESS) { @@ -676,9 +709,8 @@ bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool) { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLAPRFilePoolScope scope(pool); + s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, scope.getVolatileAPRPool()); if (s != APR_SUCCESS) { @@ -694,9 +726,8 @@ bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool) { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_remove(dirname.c_str(), pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLAPRFilePoolScope scope(pool); + s = apr_file_remove(dirname.c_str(), scope.getVolatileAPRPool()); if (s != APR_SUCCESS) { diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index da50dda103084fbd7d881459a12774a3ff36d264..0d6637f999539629468ea42c2fc7377195a9f065 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -180,9 +180,6 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable S32 write(const void* buf, S32 nbytes); apr_file_t* getFileHandle() {return mFile;} - -private: - apr_pool_t* getAPRFilePool(apr_pool_t* pool) ; // //******************************************************************************************************************************* @@ -192,8 +189,8 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist. private: - static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags); - static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ; + static apr_file_t* open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags); + static apr_status_t close(apr_file_t* file) ; static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset); public: // returns false if failure: diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 67e9fad1abf2b14e890624dfaee349f33ccd9350..cc775775bf26d357d32c6642ff9957fec51ba26d 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -347,7 +347,7 @@ void LLCoros::toplevel(coro::self& self, CoroData* data, const callable_t& calla // run the code the caller actually wants in the coroutine try { -#if LL_WINDOWS +#if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD winlevel(callable); #else callable(); diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ecfc289cb34270c8dd9eae5bf4b67b0890c78ce8 --- /dev/null +++ b/indra/llcommon/llkeybind.cpp @@ -0,0 +1,395 @@ +/** + * @file llkeybind.cpp + * @brief Information about key combinations. + * + * $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$ + */ + +#include "linden_common.h" + +#include "llkeybind.h" + +#include "llsd.h" +#include "llsdutil.h" + +LLKeyData::LLKeyData() + : + mMouse(CLICK_NONE), + mKey(KEY_NONE), + mMask(MASK_NONE), + mIgnoreMasks(false) +{ +} + +LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask) + : + mMouse(mouse), + mKey(key), + mMask(mask), + mIgnoreMasks(false) +{ +} + +LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask) + : + mMouse(mouse), + mKey(key), + mMask(MASK_NONE), + mIgnoreMasks(ignore_mask) +{ +} + +LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask) + : + mMouse(mouse), + mKey(key), + mMask(mask), + mIgnoreMasks(ignore_mask) +{ +} + +LLKeyData::LLKeyData(const LLSD &key_data) +{ + if (key_data.has("mouse")) + { + mMouse = (EMouseClickType)key_data["mouse"].asInteger(); + } + if (key_data.has("key")) + { + mKey = key_data["key"].asInteger(); + } + if (key_data.has("ignore_accelerators")) + { + mIgnoreMasks = key_data["ignore_accelerators"]; + } + if (key_data.has("mask")) + { + mMask = key_data["mask"].asInteger(); + } +} + +LLSD LLKeyData::asLLSD() const +{ + LLSD data; + data["mouse"] = (LLSD::Integer)mMouse; + data["key"] = (LLSD::Integer)mKey; + data["mask"] = (LLSD::Integer)mMask; + if (mIgnoreMasks) + { + data["ignore_accelerators"] = (LLSD::Boolean)mIgnoreMasks; + } + return data; +} + +bool LLKeyData::isEmpty() const +{ + return mMouse == CLICK_NONE && mKey == KEY_NONE; +} + +void LLKeyData::reset() +{ + mMouse = CLICK_NONE; + mKey = KEY_NONE; + mMask = MASK_NONE; + mIgnoreMasks = false; +} + +LLKeyData& LLKeyData::operator=(const LLKeyData& rhs) +{ + mMouse = rhs.mMouse; + mKey = rhs.mKey; + mMask = rhs.mMask; + mIgnoreMasks = rhs.mIgnoreMasks; + return *this; +} + +bool LLKeyData::operator==(const LLKeyData& rhs) +{ + if (mMouse != rhs.mMouse) return false; + if (mKey != rhs.mKey) return false; + if (mMask != rhs.mMask) return false; + if (mIgnoreMasks != rhs.mIgnoreMasks) return false; + return true; +} + +bool LLKeyData::operator!=(const LLKeyData& rhs) +{ + if (mMouse != rhs.mMouse) return true; + if (mKey != rhs.mKey) return true; + if (mMask != rhs.mMask) return true; + if (mIgnoreMasks != rhs.mIgnoreMasks) return true; + return false; +} + +bool LLKeyData::canHandle(const LLKeyData& data) const +{ + if (data.mKey == mKey + && data.mMouse == mMouse + && ((mIgnoreMasks && (data.mMask & mMask) == data.mMask) || data.mMask == mMask)) + { + return true; + } + return false; +} + +bool LLKeyData::canHandle(EMouseClickType mouse, KEY key, MASK mask) const +{ + if (mouse == mMouse + && key == mKey + && ((mIgnoreMasks && (mask & mMask) == mask) || mask == mMask)) + { + return true; + } + return false; +} + +// LLKeyBind + +LLKeyBind::LLKeyBind(const LLSD &key_bind) +{ + if (key_bind.isArray()) + { + for (LLSD::array_const_iterator data = key_bind.beginArray(), endLists = key_bind.endArray(); + data != endLists; + data++ + ) + { + mData.push_back(LLKeyData(*data)); + } + } +} + +bool LLKeyBind::operator==(const LLKeyBind& rhs) +{ + U32 size = mData.size(); + if (size != rhs.mData.size()) return false; + + for (U32 i = 0; i < size; i++) + { + if (mData[i] != rhs.mData[i]) return false; + } + + return true; +} + +bool LLKeyBind::operator!=(const LLKeyBind& rhs) +{ + U32 size = mData.size(); + if (size != rhs.mData.size()) return true; + + for (U32 i = 0; i < size; i++) + { + if (mData[i] != rhs.mData[i]) return true; + } + + return false; +} + +bool LLKeyBind::isEmpty() const +{ + for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) + { + if (!iter->isEmpty()) return false; + } + return true; +} + +LLSD LLKeyBind::asLLSD() const +{ + S32 last = mData.size() - 1; + while (mData[last].empty()) + { + last--; + } + + LLSD data; + for (S32 i = 0; i <= last; ++i) + { + // append even if empty to not affect visual representation + data.append(mData[i].asLLSD()); + } + return data; +} + +bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const +{ + if (mouse == CLICK_NONE && key == KEY_NONE) + { + // assume placeholder + return false; + } + + for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) + { + if (iter->canHandle(mouse, key, mask)) + { + return true; + } + } + return false; +} + +bool LLKeyBind::canHandleKey(KEY key, MASK mask) const +{ + return canHandle(CLICK_NONE, key, mask); +} + +bool LLKeyBind::canHandleMouse(EMouseClickType mouse, MASK mask) const +{ + return canHandle(mouse, KEY_NONE, mask); +} + +bool LLKeyBind::hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const +{ + if (mouse != CLICK_NONE || key != KEY_NONE) + { + for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) + { + if (iter->mKey == key + && iter->mMask == mask + && iter->mMouse == mouse + && iter->mIgnoreMasks == ignore) + { + return true; + } + } + } + return false; +} + +bool LLKeyBind::hasKeyData(const LLKeyData& data) const +{ + return hasKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks); +} + +bool LLKeyBind::hasKeyData(U32 index) const +{ + return mData.size() > index; +} + +S32 LLKeyBind::findKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const +{ + if (mouse != CLICK_NONE || key != KEY_NONE) + { + for (S32 i = 0; i < mData.size(); ++i) + { + if (mData[i].mKey == key + && mData[i].mMask == mask + && mData[i].mMouse == mouse + && mData[i].mIgnoreMasks == ignore) + { + return i; + } + } + } + return -1; +} + +S32 LLKeyBind::findKeyData(const LLKeyData& data) const +{ + return findKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks); +} + +LLKeyData LLKeyBind::getKeyData(U32 index) const +{ + if (mData.size() > index) + { + return mData[index]; + } + return LLKeyData(); +} + +bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) +{ + if (!hasKeyData(mouse, key, mask, ignore)) + { + mData.push_back(LLKeyData(mouse, key, mask, ignore)); + return true; + } + return false; +} + +bool LLKeyBind::addKeyData(const LLKeyData& data) +{ + if (!hasKeyData(data)) + { + mData.push_back(data); + return true; + } + return false; +} + +void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index) +{ + replaceKeyData(LLKeyData(mouse, key, mask, ignore), index); +} + +void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index) +{ + if (!data.isEmpty()) + { + // if both click and key are none (isEmpty()), we are inserting a placeholder, we don't want to reset anything + // otherwise reset identical key + for (data_vector_t::iterator iter = mData.begin(); iter != mData.end(); iter++) + { + if (iter->mKey == data.mKey + && iter->mMouse == data.mMouse + && iter->mIgnoreMasks == data.mIgnoreMasks + && iter->mMask == data.mMask) + { + // Replacing only fully equal combinations even in case 'ignore' is set + // Reason: Simplicity and user might decide to do a 'move' command as W and Shift+Ctrl+W, and 'run' as Shift+W + iter->reset(); + break; + } + } + } + if (mData.size() <= index) + { + mData.resize(index + 1); + } + mData[index] = data; +} + +void LLKeyBind::resetKeyData(S32 index) +{ + if (mData.size() > index) + { + mData[index].reset(); + } +} + +void LLKeyBind::trimEmpty() +{ + S32 last = mData.size() - 1; + while (last >= 0 && mData[last].empty()) + { + mData.erase(mData.begin() + last); + last--; + } +} + +U32 LLKeyBind::getDataCount() +{ + return mData.size(); +} + diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h new file mode 100644 index 0000000000000000000000000000000000000000..ad0ebec67cdbb0596e8ae993f78580c106fdc1ed --- /dev/null +++ b/indra/llcommon/llkeybind.h @@ -0,0 +1,106 @@ +/** + * @file llkeybind.h + * @brief Information about key combinations. + * + * $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$ + */ + +#ifndef LL_KEYBIND_H +#define LL_KEYBIND_H + +#include "indra_constants.h" + +// KeyData - single key combination (mouse/mask/keyboard) +class LL_COMMON_API LLKeyData +{ +public: + LLKeyData(); + LLKeyData(EMouseClickType mouse, KEY key, MASK mask); + LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask); + LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask); + LLKeyData(const LLSD &key_data); + + LLSD asLLSD() const; + bool isEmpty() const; + bool empty() const { return isEmpty(); }; + void reset(); + LLKeyData& operator=(const LLKeyData& rhs); + bool operator==(const LLKeyData& rhs); + bool operator!=(const LLKeyData& rhs); + + bool canHandle(const LLKeyData& data) const; + bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const; + + EMouseClickType mMouse; + KEY mKey; + MASK mMask; + // Either to expect exact match or ignore not expected masks + bool mIgnoreMasks; +}; + +// One function can bind to multiple Key options +class LLKeyBind +{ +public: + LLKeyBind() {} + LLKeyBind(const LLSD &key_bind); + + bool operator==(const LLKeyBind& rhs); + bool operator!=(const LLKeyBind& rhs); + bool isEmpty() const; + bool empty() const { return isEmpty(); }; + + LLSD asLLSD() const; + + bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const; + bool canHandleKey(KEY key, MASK mask) const; + bool canHandleMouse(EMouseClickType mouse, MASK mask) const; + + // contains specified combination + bool hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const; + bool hasKeyData(const LLKeyData& data) const; + bool hasKeyData(U32 index) const; + + // index of contained LLKeyData + S32 findKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const; + S32 findKeyData(const LLKeyData& data) const; + + LLKeyData getKeyData(U32 index) const; + + // these methods enshure there will be no repeats + bool addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore); + bool addKeyData(const LLKeyData& data); + void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index); + void replaceKeyData(const LLKeyData& data, U32 index); + void resetKeyData(S32 index); + void clear() { mData.clear(); } + // if there any empty LLKeyData in the end of the array, remove them + void trimEmpty(); + U32 getDataCount(); + +private: + typedef std::vector<LLKeyData> data_vector_t; + data_vector_t mData; +}; + + +#endif // LL_KEYBIND_H diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 1aaff5628f2658ab89e9d733b2b6dc5bbb1b6b7c..0bae59ef4c76538197772d2d41db9d10e1748089 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -2241,7 +2241,7 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, return ZR_SIZE_ERROR; } #endif - catch (std::bad_alloc) + catch (std::bad_alloc&) { free(result); return ZR_MEM_ERROR; diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index 0b72b5318601f92834dadb93df0cfd968838576e..34268d94f64969b4746f302530a14e196fe3c72d 100644 --- a/indra/llcorehttp/_httpservice.cpp +++ b/indra/llcorehttp/_httpservice.cpp @@ -318,7 +318,7 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread) { LOG_UNHANDLED_EXCEPTION(""); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { LLMemory::logMemoryInfo(TRUE); diff --git a/indra/llcorehttp/bufferarray.cpp b/indra/llcorehttp/bufferarray.cpp index be534b3ce4f2fd67d11ef9158bf1f076e1565c8f..e0b2876a0016167b6dc007da55e8eef869f54287 100644 --- a/indra/llcorehttp/bufferarray.cpp +++ b/indra/llcorehttp/bufferarray.cpp @@ -147,7 +147,7 @@ size_t BufferArray::append(const void * src, size_t len) { block = Block::alloc(BLOCK_ALLOC_SIZE); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { LLMemory::logMemoryInfo(TRUE); diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 9dea87611423e5ccfdeac6ac7354cd1df4f4f230..7a0c8cd8f57eab57ec105a6b208dc22fffc7b5a7 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -2168,19 +2168,27 @@ bool LLImageFormatted::load(const std::string &filename, int load_size) } bool res; U8 *data = allocateData(load_size); - apr_size_t bytes_read = load_size; - apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read - if (s != APR_SUCCESS || (S32) bytes_read != load_size) + if (data) { - deleteData(); - setLastError("Unable to read file",filename); - res = false; + apr_size_t bytes_read = load_size; + apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read + if (s != APR_SUCCESS || (S32) bytes_read != load_size) + { + deleteData(); + setLastError("Unable to read file",filename); + res = false; + } + else + { + res = updateData(); + } } else { - res = updateData(); + setLastError("Allocation failure", filename); + res = false; } - + return res; } diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp index 3b1b060c023b4ffe4146bcb8f972bf20644d5852..ead9a37fb89592633c24079c908e79e3063dc5e1 100644 --- a/indra/llimage/llimagejpeg.cpp +++ b/indra/llimage/llimagejpeg.cpp @@ -315,7 +315,7 @@ bool LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) jpeg_destroy_decompress(&cinfo); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { setLastError( "Out of memory"); jpeg_destroy_decompress(&cinfo); diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index f298764cc0743a8a5856c741a7645673e920961f..f7dc6272cf94cc7c5ad4319669781eb7f63f9080 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -210,7 +210,7 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf releaseResources(); return (FALSE); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { mErrorMessage = "LLPngWrapper"; releaseResources(); diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index e7a8ca2f9d79221b48d495cede4db11e408a03ac..ac02364a67be6dd6e412aadc4bbdff13d5746f77 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2400,9 +2400,9 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) { //face has no geometry, continue face.resizeIndices(3); face.resizeVertices(1); - memset(face.mPositions, 0, sizeof(LLVector4a)); - memset(face.mNormals, 0, sizeof(LLVector4a)); - memset(face.mTexCoords, 0, sizeof(LLVector2)); + face.mPositions->clear(); + face.mNormals->clear(); + face.mTexCoords->setZero(); memset(face.mIndices, 0, sizeof(U16)*3); continue; } @@ -2490,7 +2490,11 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) } else { - memset(norm_out, 0, sizeof(LLVector4a)*num_verts); + for (U32 j = 0; j < num_verts; ++j) + { + norm_out->clear(); + norm_out++; // or just norm_out[j].clear(); + } } } @@ -2520,7 +2524,11 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) } else { - memset(tc_out, 0, sizeof(LLVector2)*num_verts); + for (U32 j = 0; j < num_verts; j += 2) + { + tc_out->clear(); + tc_out++; + } } } @@ -5252,7 +5260,7 @@ bool LLVolumeFace::cacheOptimize() triangle_data.resize(mNumIndices / 3); vertex_data.resize(mNumVertices); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { LL_WARNS("LLVOLUME") << "Resize failed" << LL_ENDL; return false; @@ -5406,7 +5414,7 @@ bool LLVolumeFace::cacheOptimize() { new_idx.resize(mNumVertices, -1); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { ll_aligned_free<64>(pos); ll_aligned_free_16(wght); @@ -6914,11 +6922,16 @@ void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVe { //LLVector4a *tan1 = new LLVector4a[vertexCount * 2]; LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a)); + // new(tan1) LLVector4a; LLVector4a* tan2 = tan1 + vertexCount; - memset(tan1, 0, vertexCount*2*sizeof(LLVector4a)); - + U32 count = vertexCount * 2; + for (U32 i = 0; i < count; i++) + { + tan1[i].clear(); + } + for (U32 a = 0; a < triangleCount; a++) { U32 i1 = *index_array++; diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 24387fbffd7bf869175b098557e94594eaac696b..0eae6d98263a30f27e51febc085c8ae4210759f0 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -597,7 +597,7 @@ LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: { bas >> jsonRoot; } - catch (std::runtime_error e) + catch (std::runtime_error& e) { // deserialization failed. Record the reason and pass back an empty map for markup. status = LLCore::HttpStatus(499, std::string(e.what())); return result; @@ -625,7 +625,7 @@ LLSD HttpCoroJSONHandler::parseBody(LLCore::HttpResponse *response, bool &succes { bas >> jsonRoot; } - catch (std::runtime_error e) + catch (std::runtime_error&) { success = false; return LLSD(); diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 3510f93805daa66c2ad0ac724c16217e7ce1b5dd..6cf6af6437df9eab442b324a2c2e0306404ec62b 100644 --- a/indra/llmessage/lldatapacker.cpp +++ b/indra/llmessage/lldatapacker.cpp @@ -186,7 +186,7 @@ BOOL LLDataPackerBinaryBuffer::packString(const std::string& value, const char * if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.c_str(), MVT_VARIABLE, length); + htolememcpy(mCurBufferp, value.c_str(), MVT_VARIABLE, length); } mCurBufferp += length; return success; @@ -213,12 +213,12 @@ BOOL LLDataPackerBinaryBuffer::packBinaryData(const U8 *value, S32 size, const c if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &size, MVT_S32, 4); + htolememcpy(mCurBufferp, &size, MVT_S32, 4); } mCurBufferp += 4; if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value, MVT_VARIABLE, size); + htolememcpy(mCurBufferp, value, MVT_VARIABLE, size); } mCurBufferp += size; return success; @@ -229,12 +229,12 @@ BOOL LLDataPackerBinaryBuffer::unpackBinaryData(U8 *value, S32 &size, const char { BOOL success = TRUE; success &= verifyLength(4, name); - htonmemcpy(&size, mCurBufferp, MVT_S32, 4); + htolememcpy(&size, mCurBufferp, MVT_S32, 4); mCurBufferp += 4; success &= verifyLength(size, name); if (success) { - htonmemcpy(value, mCurBufferp, MVT_VARIABLE, size); + htolememcpy(value, mCurBufferp, MVT_VARIABLE, size); mCurBufferp += size; } else @@ -253,7 +253,7 @@ BOOL LLDataPackerBinaryBuffer::packBinaryDataFixed(const U8 *value, S32 size, co if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value, MVT_VARIABLE, size); + htolememcpy(mCurBufferp, value, MVT_VARIABLE, size); } mCurBufferp += size; return success; @@ -264,7 +264,7 @@ BOOL LLDataPackerBinaryBuffer::unpackBinaryDataFixed(U8 *value, S32 size, const { BOOL success = TRUE; success &= verifyLength(size, name); - htonmemcpy(value, mCurBufferp, MVT_VARIABLE, size); + htolememcpy(value, mCurBufferp, MVT_VARIABLE, size); mCurBufferp += size; return success; } @@ -302,7 +302,7 @@ BOOL LLDataPackerBinaryBuffer::packU16(const U16 value, const char *name) if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &value, MVT_U16, 2); + htolememcpy(mCurBufferp, &value, MVT_U16, 2); } mCurBufferp += 2; return success; @@ -314,7 +314,7 @@ BOOL LLDataPackerBinaryBuffer::unpackU16(U16 &value, const char *name) BOOL success = TRUE; success &= verifyLength(sizeof(U16), name); - htonmemcpy(&value, mCurBufferp, MVT_U16, 2); + htolememcpy(&value, mCurBufferp, MVT_U16, 2); mCurBufferp += 2; return success; } @@ -327,7 +327,7 @@ BOOL LLDataPackerBinaryBuffer::packU32(const U32 value, const char *name) if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &value, MVT_U32, 4); + htolememcpy(mCurBufferp, &value, MVT_U32, 4); } mCurBufferp += 4; return success; @@ -339,7 +339,7 @@ BOOL LLDataPackerBinaryBuffer::unpackU32(U32 &value, const char *name) BOOL success = TRUE; success &= verifyLength(sizeof(U32), name); - htonmemcpy(&value, mCurBufferp, MVT_U32, 4); + htolememcpy(&value, mCurBufferp, MVT_U32, 4); mCurBufferp += 4; return success; } @@ -352,7 +352,7 @@ BOOL LLDataPackerBinaryBuffer::packS32(const S32 value, const char *name) if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &value, MVT_S32, 4); + htolememcpy(mCurBufferp, &value, MVT_S32, 4); } mCurBufferp += 4; return success; @@ -364,7 +364,7 @@ BOOL LLDataPackerBinaryBuffer::unpackS32(S32 &value, const char *name) BOOL success = TRUE; success &= verifyLength(sizeof(S32), name); - htonmemcpy(&value, mCurBufferp, MVT_S32, 4); + htolememcpy(&value, mCurBufferp, MVT_S32, 4); mCurBufferp += 4; return success; } @@ -377,7 +377,7 @@ BOOL LLDataPackerBinaryBuffer::packF32(const F32 value, const char *name) if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &value, MVT_F32, 4); + htolememcpy(mCurBufferp, &value, MVT_F32, 4); } mCurBufferp += 4; return success; @@ -389,7 +389,7 @@ BOOL LLDataPackerBinaryBuffer::unpackF32(F32 &value, const char *name) BOOL success = TRUE; success &= verifyLength(sizeof(F32), name); - htonmemcpy(&value, mCurBufferp, MVT_F32, 4); + htolememcpy(&value, mCurBufferp, MVT_F32, 4); mCurBufferp += 4; return success; } @@ -402,7 +402,7 @@ BOOL LLDataPackerBinaryBuffer::packColor4(const LLColor4 &value, const char *nam if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); + htolememcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); } mCurBufferp += 16; return success; @@ -414,7 +414,7 @@ BOOL LLDataPackerBinaryBuffer::unpackColor4(LLColor4 &value, const char *name) BOOL success = TRUE; success &= verifyLength(16, name); - htonmemcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); + htolememcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); mCurBufferp += 16; return success; } @@ -427,7 +427,7 @@ BOOL LLDataPackerBinaryBuffer::packColor4U(const LLColor4U &value, const char *n if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.mV, MVT_VARIABLE, 4); + htolememcpy(mCurBufferp, value.mV, MVT_VARIABLE, 4); } mCurBufferp += 4; return success; @@ -439,7 +439,7 @@ BOOL LLDataPackerBinaryBuffer::unpackColor4U(LLColor4U &value, const char *name) BOOL success = TRUE; success &= verifyLength(4, name); - htonmemcpy(value.mV, mCurBufferp, MVT_VARIABLE, 4); + htolememcpy(value.mV, mCurBufferp, MVT_VARIABLE, 4); mCurBufferp += 4; return success; } @@ -453,8 +453,8 @@ BOOL LLDataPackerBinaryBuffer::packVector2(const LLVector2 &value, const char *n if (mWriteEnabled) { - htonmemcpy(mCurBufferp, &value.mV[0], MVT_F32, 4); - htonmemcpy(mCurBufferp+4, &value.mV[1], MVT_F32, 4); + htolememcpy(mCurBufferp, &value.mV[0], MVT_F32, 4); + htolememcpy(mCurBufferp+4, &value.mV[1], MVT_F32, 4); } mCurBufferp += 8; return success; @@ -466,8 +466,8 @@ BOOL LLDataPackerBinaryBuffer::unpackVector2(LLVector2 &value, const char *name) BOOL success = TRUE; success &= verifyLength(8, name); - htonmemcpy(&value.mV[0], mCurBufferp, MVT_F32, 4); - htonmemcpy(&value.mV[1], mCurBufferp+4, MVT_F32, 4); + htolememcpy(&value.mV[0], mCurBufferp, MVT_F32, 4); + htolememcpy(&value.mV[1], mCurBufferp+4, MVT_F32, 4); mCurBufferp += 8; return success; } @@ -480,7 +480,7 @@ BOOL LLDataPackerBinaryBuffer::packVector3(const LLVector3 &value, const char *n if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.mV, MVT_LLVector3, 12); + htolememcpy(mCurBufferp, value.mV, MVT_LLVector3, 12); } mCurBufferp += 12; return success; @@ -492,7 +492,7 @@ BOOL LLDataPackerBinaryBuffer::unpackVector3(LLVector3 &value, const char *name) BOOL success = TRUE; success &= verifyLength(12, name); - htonmemcpy(value.mV, mCurBufferp, MVT_LLVector3, 12); + htolememcpy(value.mV, mCurBufferp, MVT_LLVector3, 12); mCurBufferp += 12; return success; } @@ -504,7 +504,7 @@ BOOL LLDataPackerBinaryBuffer::packVector4(const LLVector4 &value, const char *n if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); + htolememcpy(mCurBufferp, value.mV, MVT_LLVector4, 16); } mCurBufferp += 16; return success; @@ -516,7 +516,7 @@ BOOL LLDataPackerBinaryBuffer::unpackVector4(LLVector4 &value, const char *name) BOOL success = TRUE; success &= verifyLength(16, name); - htonmemcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); + htolememcpy(value.mV, mCurBufferp, MVT_LLVector4, 16); mCurBufferp += 16; return success; } @@ -528,7 +528,7 @@ BOOL LLDataPackerBinaryBuffer::packUUID(const LLUUID &value, const char *name) if (mWriteEnabled) { - htonmemcpy(mCurBufferp, value.mData, MVT_LLUUID, 16); + htolememcpy(mCurBufferp, value.mData, MVT_LLUUID, 16); } mCurBufferp += 16; return success; @@ -540,7 +540,7 @@ BOOL LLDataPackerBinaryBuffer::unpackUUID(LLUUID &value, const char *name) BOOL success = TRUE; success &= verifyLength(16, name); - htonmemcpy(value.mData, mCurBufferp, MVT_LLUUID, 16); + htolememcpy(value.mData, mCurBufferp, MVT_LLUUID, 16); mCurBufferp += 16; return success; } diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index 04b34a296c13c4961498a4f58f6dccdf014689f2..6fd17c91549b59adce034624f8b9f4f25fb15c70 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -125,7 +125,7 @@ void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) cons { response->result(simpleGet()); } - catch (NotImplemented) + catch (NotImplemented&) { response->methodNotAllowed(); } @@ -138,7 +138,7 @@ void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, cons { response->result(simplePut(input)); } - catch (NotImplemented) + catch (NotImplemented&) { response->methodNotAllowed(); } @@ -151,7 +151,7 @@ void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, con { response->result(simplePost(input)); } - catch (NotImplemented) + catch (NotImplemented&) { response->methodNotAllowed(); } @@ -164,7 +164,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons { response->result(simpleDel(context)); } - catch (NotImplemented) + catch (NotImplemented&) { response->methodNotAllowed(); } diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index 134154aa6ce900d52e73dee372052801a060c55b..fcda2a85f622bd51d09f41f90881b7da9196fccb 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -373,7 +373,7 @@ std::string LLMail::encryptIMEmailAddress(const LLUUID& from_agent_id, // Convert input data into a binary blob std::vector<U8> data; data.resize(data_size); - // *NOTE: This may suffer from endian issues. Could be htonmemcpy. + // *NOTE: This may suffer from endian issues. Could be htolememcpy. memcpy(&data[0], &time, 4); memcpy(&data[4], &from_agent_id.mData[0], UUID_BYTES); memcpy(&data[4 + UUID_BYTES], &to_agent_id.mData[0], UUID_BYTES); diff --git a/indra/llmessage/llmessagetemplate.cpp b/indra/llmessage/llmessagetemplate.cpp index c4c7e667034b24003bf0ea57000d16724bb0daae..e70e25943644f748e314007295ae5538ae828953 100644 --- a/indra/llmessage/llmessagetemplate.cpp +++ b/indra/llmessage/llmessagetemplate.cpp @@ -47,7 +47,7 @@ void LLMsgVarData::addData(const void *data, S32 size, EMsgVariableType type, S3 { delete[] mData; // Delete it if it already exists mData = new U8[size]; - htonmemcpy(mData, data, mType, size); + htolememcpy(mData, data, mType, size); } } diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp index 8d7c4c028268a85ff185a4aff5a771c52bb7c746..5ac5f6c580305aff5db5e7074929d79dc117a90e 100644 --- a/indra/llmessage/lltemplatemessagebuilder.cpp +++ b/indra/llmessage/lltemplatemessagebuilder.cpp @@ -689,14 +689,14 @@ static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* templat { case 1: sizeb = size; - htonmemcpy(&buffer[result], &sizeb, MVT_U8, 1); + htolememcpy(&buffer[result], &sizeb, MVT_U8, 1); break; case 2: sizeh = size; - htonmemcpy(&buffer[result], &sizeh, MVT_U16, 2); + htolememcpy(&buffer[result], &sizeh, MVT_U16, 2); break; case 4: - htonmemcpy(&buffer[result], &size, MVT_S32, 4); + htolememcpy(&buffer[result], &size, MVT_S32, 4); break; default: LL_ERRS() << "Attempting to build variable field with unknown size of " << size << LL_ENDL; diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 4e0c53c37e3b23ca3a1fe607feb33e02caf44e21..6d5ad0ba089a30324f517b91acfaf9c379f36752 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -645,15 +645,15 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender switch(data_size) { case 1: - htonmemcpy(&tsizeb, &buffer[decode_pos], MVT_U8, 1); + htolememcpy(&tsizeb, &buffer[decode_pos], MVT_U8, 1); tsize = tsizeb; break; case 2: - htonmemcpy(&tsizeh, &buffer[decode_pos], MVT_U16, 2); + htolememcpy(&tsizeh, &buffer[decode_pos], MVT_U16, 2); tsize = tsizeh; break; case 4: - htonmemcpy(&tsize, &buffer[decode_pos], MVT_U32, 4); + htolememcpy(&tsize, &buffer[decode_pos], MVT_U32, 4); break; default: LL_ERRS() << "Attempting to read variable field with unknown size of " << data_size << LL_ENDL; diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index c8b9d5d19fad4971547c52632fc4236951a78614..32e0e2cc3b2b8da4045c78c86c32da39c5e93d03 100644 --- a/indra/llmessage/llxfer.cpp +++ b/indra/llmessage/llxfer.cpp @@ -245,7 +245,7 @@ void LLXfer::sendPacket(S32 packet_num) num_copy); } fdata_size += sizeof(S32); - htonmemcpy(fdata_buf,&mXferSize, MVT_S32, sizeof(S32)); + htolememcpy(fdata_buf,&mXferSize, MVT_S32, sizeof(S32)); } S32 encoded_packetnum = encodePacketNum(packet_num,last_packet); diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index f6c5d9e228d8087ddbb0f985aa18f895d91b2973..0af5a1b96dba0bf0b3a61f8c148c1e65708af023 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -860,10 +860,10 @@ void null_message_callback(LLMessageSystem *msg, void **data); // #if !defined( LL_BIG_ENDIAN ) && !defined( LL_LITTLE_ENDIAN ) -#error Unknown endianness for htonmemcpy. Did you miss a common include? +#error Unknown endianness for htolememcpy. Did you miss a common include? #endif -static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, size_t n) +static inline void *htolememcpy(void *vs, const void *vct, EMsgVariableType type, size_t n) { char *s = (char *)vs; const char *ct = (const char *)vct; @@ -886,7 +886,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_S16: if (n != 2) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN *(s + 1) = *(ct); @@ -901,7 +901,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_F32: if (n != 4) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN *(s + 3) = *(ct); @@ -918,7 +918,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_F64: if (n != 8) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN *(s + 7) = *(ct); @@ -938,12 +938,12 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_LLQuaternion: // We only send x, y, z and infer w (we set x, y, z to ensure that w >= 0) if (n != 12) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN - htonmemcpy(s + 8, ct + 8, MVT_F32, 4); - htonmemcpy(s + 4, ct + 4, MVT_F32, 4); - return(htonmemcpy(s, ct, MVT_F32, 4)); + htolememcpy(s + 8, ct + 8, MVT_F32, 4); + htolememcpy(s + 4, ct + 4, MVT_F32, 4); + return(htolememcpy(s, ct, MVT_F32, 4)); #else return(memcpy(s,ct,n)); /* Flawfinder: ignore */ #endif @@ -951,12 +951,12 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_LLVector3d: if (n != 24) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN - htonmemcpy(s + 16, ct + 16, MVT_F64, 8); - htonmemcpy(s + 8, ct + 8, MVT_F64, 8); - return(htonmemcpy(s, ct, MVT_F64, 8)); + htolememcpy(s + 16, ct + 16, MVT_F64, 8); + htolememcpy(s + 8, ct + 8, MVT_F64, 8); + return(htolememcpy(s, ct, MVT_F64, 8)); #else return(memcpy(s,ct,n)); /* Flawfinder: ignore */ #endif @@ -964,13 +964,13 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_LLVector4: if (n != 16) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN - htonmemcpy(s + 12, ct + 12, MVT_F32, 4); - htonmemcpy(s + 8, ct + 8, MVT_F32, 4); - htonmemcpy(s + 4, ct + 4, MVT_F32, 4); - return(htonmemcpy(s, ct, MVT_F32, 4)); + htolememcpy(s + 12, ct + 12, MVT_F32, 4); + htolememcpy(s + 8, ct + 8, MVT_F32, 4); + htolememcpy(s + 4, ct + 4, MVT_F32, 4); + return(htolememcpy(s, ct, MVT_F32, 4)); #else return(memcpy(s,ct,n)); /* Flawfinder: ignore */ #endif @@ -978,12 +978,12 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_U16Vec3: if (n != 6) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN - htonmemcpy(s + 4, ct + 4, MVT_U16, 2); - htonmemcpy(s + 2, ct + 2, MVT_U16, 2); - return(htonmemcpy(s, ct, MVT_U16, 2)); + htolememcpy(s + 4, ct + 4, MVT_U16, 2); + htolememcpy(s + 2, ct + 2, MVT_U16, 2); + return(htolememcpy(s, ct, MVT_U16, 2)); #else return(memcpy(s,ct,n)); /* Flawfinder: ignore */ #endif @@ -991,13 +991,13 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_U16Quat: if (n != 8) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN - htonmemcpy(s + 6, ct + 6, MVT_U16, 2); - htonmemcpy(s + 4, ct + 4, MVT_U16, 2); - htonmemcpy(s + 2, ct + 2, MVT_U16, 2); - return(htonmemcpy(s, ct, MVT_U16, 2)); + htolememcpy(s + 6, ct + 6, MVT_U16, 2); + htolememcpy(s + 4, ct + 4, MVT_U16, 2); + htolememcpy(s + 2, ct + 2, MVT_U16, 2); + return(htolememcpy(s, ct, MVT_U16, 2)); #else return(memcpy(s,ct,n)); /* Flawfinder: ignore */ #endif @@ -1005,15 +1005,15 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_S16Array: if (n % 2) { - LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; + LL_ERRS() << "Size argument passed to htolememcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN length = n % 2; for (i = 1; i < length; i++) { - htonmemcpy(s + i*2, ct + i*2, MVT_S16, 2); + htolememcpy(s + i*2, ct + i*2, MVT_S16, 2); } - return(htonmemcpy(s, ct, MVT_S16, 2)); + return(htolememcpy(s, ct, MVT_S16, 2)); #else return(memcpy(s,ct,n)); #endif @@ -1025,7 +1025,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, inline void *ntohmemcpy(void *s, const void *ct, EMsgVariableType type, size_t n) { - return(htonmemcpy(s,ct,type, n)); + return(htolememcpy(s,ct,type, n)); } inline const LLHost& LLMessageSystem::getReceivingInterface() const {return mLastReceivingIF;} diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 78b148381025a9c0c18ac9af79bb8edff91d8ffd..85197d1272713a88e34f0058443a133241bf0705 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -664,12 +664,14 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie return result; } -void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) +void LLPluginClassMedia::scrollEvent(int x, int y, int clicks_x, int clicks_y, MASK modifiers) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); message.setValueS32("x", x); message.setValueS32("y", y); + message.setValueS32("clicks_x", clicks_x); + message.setValueS32("clicks_y", clicks_y); message.setValue("modifiers", translateModifiers(modifiers)); sendMessage(message); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 4f52afb31741dd72712014b0c8522b8a277b6f8c..9d11ee0421d92f4b2efdaa28a8f800195be9aaa4 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -118,7 +118,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); - void scrollEvent(int x, int y, MASK modifiers); + void scrollEvent(int x, int y, int clicks_x, int clicks_y, MASK modifiers); // enable/disable media plugin debugging messages and info spam void enableMediaPluginDebugging( bool enable ); diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index e24d222cb66e8eaf7063e1a4c785c74dcf7f7544..8fb3054eacec737720154e1c58190d45d8c58074 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -33,7 +33,7 @@ #include "llpluginmessagepipe.h" #include "llpluginmessageclasses.h" -static const F32 GOODBYE_SECONDS = 20.0f; +static const F32 GOODBYE_SECONDS = 12.0f; // Do not set it to be bigger than mPluginLockupTimeout or parent will kill LLPluginProcessChild static const F32 HEARTBEAT_SECONDS = 1.0f; static const F32 PLUGIN_IDLE_SECONDS = 1.0f / 100.0f; // Each call to idle will give the plugin this much time. @@ -218,6 +218,11 @@ void LLPluginProcessChild::idle(void) if (mWaitGoodbye.hasExpired()) { LL_WARNS() << "Wait for goodbye expired. Advancing to UNLOADED" << LL_ENDL; + if (mInstance != NULL) + { + // Something went wrong, at least make sure plugin will terminate + sendMessageToPlugin(LLPluginMessage("base", "force_exit")); + } setState(STATE_UNLOADED); } break; diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index a0987b35d86270d3d86a62da71a7e567e424d40e..bc5dd62f457f69e6c25d8b25fe043aa62e3b5d10 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1013,7 +1013,7 @@ S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_fa U64 exception_faces; U8 *start_loc = cur_ptr; - htonmemcpy(cur_ptr,data_ptr + (last_face_index * data_size), type, data_size); + htolememcpy(cur_ptr,data_ptr + (last_face_index * data_size), type, data_size); cur_ptr += data_size; for (face_index = last_face_index-1; face_index >= 0; face_index--) @@ -1072,7 +1072,7 @@ S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_fa *cur_ptr++ = (U8)(exception_faces & 0x7F); - htonmemcpy(cur_ptr,data_ptr + (face_index * data_size), type, data_size); + htolememcpy(cur_ptr,data_ptr + (face_index * data_size), type, data_size); cur_ptr += data_size; } } @@ -1083,7 +1083,7 @@ S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 dat { U8 *start_loc = cur_ptr; U64 i; - htonmemcpy(data_ptr,cur_ptr, type,data_size); + htolememcpy(data_ptr,cur_ptr, type,data_size); cur_ptr += data_size; for (i = 1; i < face_count; i++) @@ -1108,7 +1108,7 @@ S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 dat { if (i & 0x01) { - htonmemcpy(data_ptr+(j*data_size),cur_ptr,type,data_size); + htolememcpy(data_ptr+(j*data_size),cur_ptr,type,data_size); LL_DEBUGS("TEFieldDecode") << "Assigning " ; char foo[64]; sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1)); diff --git a/indra/llprimitive/lltextureanim.cpp b/indra/llprimitive/lltextureanim.cpp index 031a315d62273bf3c08fccc586b9e8a6d7ef4ca0..7c48e57a1a1a2eac954782bc624430df324e632f 100644 --- a/indra/llprimitive/lltextureanim.cpp +++ b/indra/llprimitive/lltextureanim.cpp @@ -94,9 +94,9 @@ void LLTextureAnim::packTAMessage(LLMessageSystem *mesgsys) const data[1] = mFace; data[2] = mSizeX; data[3] = mSizeY; - htonmemcpy(data + 4, &mStart, MVT_F32, sizeof(F32)); - htonmemcpy(data + 8, &mLength, MVT_F32, sizeof(F32)); - htonmemcpy(data + 12, &mRate, MVT_F32, sizeof(F32)); + htolememcpy(data + 4, &mStart, MVT_F32, sizeof(F32)); + htolememcpy(data + 8, &mLength, MVT_F32, sizeof(F32)); + htolememcpy(data + 12, &mRate, MVT_F32, sizeof(F32)); mesgsys->addBinaryDataFast(_PREHASH_TextureAnim, data, TA_BLOCK_SIZE); } @@ -109,9 +109,9 @@ void LLTextureAnim::packTAMessage(LLDataPacker &dp) const data[1] = mFace; data[2] = mSizeX; data[3] = mSizeY; - htonmemcpy(data + 4, &mStart, MVT_F32, sizeof(F32)); - htonmemcpy(data + 8, &mLength, MVT_F32, sizeof(F32)); - htonmemcpy(data + 12, &mRate, MVT_F32, sizeof(F32)); + htolememcpy(data + 4, &mStart, MVT_F32, sizeof(F32)); + htolememcpy(data + 8, &mLength, MVT_F32, sizeof(F32)); + htolememcpy(data + 12, &mRate, MVT_F32, sizeof(F32)); dp.packBinaryData(data, TA_BLOCK_SIZE, "TextureAnimation"); } @@ -146,9 +146,9 @@ void LLTextureAnim::unpackTAMessage(LLMessageSystem *mesgsys, const S32 block_nu mSizeX = llmax((U8)1, data[2]); mSizeY = llmax((U8)1, data[3]); } - htonmemcpy(&mStart, data + 4, MVT_F32, sizeof(F32)); - htonmemcpy(&mLength, data + 8, MVT_F32, sizeof(F32)); - htonmemcpy(&mRate, data + 12, MVT_F32, sizeof(F32)); + htolememcpy(&mStart, data + 4, MVT_F32, sizeof(F32)); + htolememcpy(&mLength, data + 8, MVT_F32, sizeof(F32)); + htolememcpy(&mRate, data + 12, MVT_F32, sizeof(F32)); } void LLTextureAnim::unpackTAMessage(LLDataPacker &dp) @@ -170,9 +170,9 @@ void LLTextureAnim::unpackTAMessage(LLDataPacker &dp) mFace = data[1]; mSizeX = data[2]; mSizeY = data[3]; - htonmemcpy(&mStart, data + 4, MVT_F32, sizeof(F32)); - htonmemcpy(&mLength, data + 8, MVT_F32, sizeof(F32)); - htonmemcpy(&mRate, data + 12, MVT_F32, sizeof(F32)); + htolememcpy(&mStart, data + 4, MVT_F32, sizeof(F32)); + htolememcpy(&mLength, data + 8, MVT_F32, sizeof(F32)); + htolememcpy(&mRate, data + 12, MVT_F32, sizeof(F32)); } LLSD LLTextureAnim::asLLSD() const diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index c0f0cec80b2c5e9fc6d84a7d6b0113f980d7784e..bcc702d31f1590b03c7c3d495258276480f00e8e 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -49,6 +49,10 @@ #include "llglheaders.h" #include "llglslshader.h" +#if LL_WINDOWS +#include "lldxhardware.h" +#endif + #ifdef _DEBUG //#define GL_STATE_VERIFY #endif @@ -394,6 +398,8 @@ PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL; PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL; #if LL_WINDOWS +PFNWGLGETGPUIDSAMDPROC wglGetGPUIDsAMD = NULL; +PFNWGLGETGPUINFOAMDPROC wglGetGPUInfoAMD = NULL; PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; #endif @@ -413,6 +419,7 @@ LLGLManager::LLGLManager() : mHasMultitexture(FALSE), mHasATIMemInfo(FALSE), + mHasAMDAssociations(FALSE), mHasNVXMemInfo(FALSE), mNumTextureUnits(1), mHasMipMapGeneration(FALSE), @@ -497,7 +504,16 @@ void LLGLManager::initWGL() { LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL; } - + + // For retreiving information per AMD adapter, + // because we can't trust curently selected/default one when there are multiple + mHasAMDAssociations = ExtensionExists("WGL_AMD_gpu_association", gGLHExts.mSysExts); + if (mHasAMDAssociations) + { + GLH_EXT_NAME(wglGetGPUIDsAMD) = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD"); + GLH_EXT_NAME(wglGetGPUInfoAMD) = (PFNWGLGETGPUINFOAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUInfoAMD"); + } + if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts)) { GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT"); @@ -683,23 +699,78 @@ bool LLGLManager::initGL() stop_glerror(); S32 old_vram = mVRAM; + mVRAM = 0; - if (mHasATIMemInfo) +#if LL_WINDOWS + if (mHasAMDAssociations) + { + GLuint gl_gpus_count = wglGetGPUIDsAMD(0, 0); + if (gl_gpus_count > 0) + { + GLuint* ids = new GLuint[gl_gpus_count]; + wglGetGPUIDsAMD(gl_gpus_count, ids); + + GLuint mem_mb = 0; + for (U32 i = 0; i < gl_gpus_count; i++) + { + wglGetGPUInfoAMD(ids[i], + WGL_GPU_RAM_AMD, + GL_UNSIGNED_INT, + sizeof(GLuint), + &mem_mb); + if (mVRAM < mem_mb) + { + // basically pick the best AMD and trust driver/OS to know to switch + mVRAM = mem_mb; + } + } + } + if (mVRAM != 0) + { + LL_WARNS("RenderInit") << "VRAM Detected (AMDAssociations):" << mVRAM << LL_ENDL; + } + } +#endif + + if (mHasATIMemInfo && mVRAM == 0) { //ask the gl how much vram is free at startup and attempt to use no more than half of that S32 meminfo[4]; glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); - mVRAM = meminfo[0]/1024; + mVRAM = meminfo[0] / 1024; + LL_WARNS("RenderInit") << "VRAM Detected (ATIMemInfo):" << mVRAM << LL_ENDL; } - else if (mHasNVXMemInfo) + + if (mHasNVXMemInfo && mVRAM == 0) { S32 dedicated_memory; glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated_memory); mVRAM = dedicated_memory/1024; + LL_WARNS("RenderInit") << "VRAM Detected (NVXMemInfo):" << mVRAM << LL_ENDL; } +#if LL_WINDOWS if (mVRAM < 256) - { //something likely went wrong using the above extensions, fall back to old method + { + // Something likely went wrong using the above extensions + // try WMI first and fall back to old method (from dxdiag) if all else fails + // Function will check all GPUs WMI knows of and will pick up the one with most + // memory. We need to check all GPUs because system can switch active GPU to + // weaker one, to preserve power when not under load. + S32 mem = LLDXHardware::getMBVideoMemoryViaWMI(); + if (mem != 0) + { + mVRAM = mem; + LL_WARNS("RenderInit") << "VRAM Detected (WMI):" << mVRAM<< LL_ENDL; + } + } +#endif + + if (mVRAM < 256 && old_vram > 0) + { + // fall back to old method + // Note: on Windows value will be from LLDXHardware. + // Either received via dxdiag or via WMI by id from dxdiag. mVRAM = old_vram; } @@ -961,7 +1032,7 @@ void LLGLManager::initExtensions() mHasTextureRectangle = FALSE; #else // LL_MESA_HEADLESS //important, gGLHExts.mSysExts is uninitialized until after glh_init_extensions is called mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); - mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); + mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); //Basic AMD method, also see mHasAMDAssociations mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color"); mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic"); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 4c4302d05ba3e101c2cc6081ebe69b6fc428648a..6db1fe9c90a783120b64e4c5235257d0828bc4a4 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -78,6 +78,7 @@ class LLGLManager // Extensions used by everyone BOOL mHasMultitexture; BOOL mHasATIMemInfo; + BOOL mHasAMDAssociations; BOOL mHasNVXMemInfo; S32 mNumTextureUnits; BOOL mHasMipMapGeneration; diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 722dd9050bc1819fb31c72382226805e04f5593b..36fbb381bb13425096a5713b1e692298f96d6879 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -618,6 +618,8 @@ extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI; extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI; extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI; +extern PFNWGLGETGPUIDSAMDPROC wglGetGPUIDsAMD; +extern PFNWGLGETGPUINFOAMDPROC wglGetGPUInfoAMD; extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; // GL_ARB_occlusion_query diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 42802cd339cfece764cf1f62079919bcef0ebb86..e3bb36192c907c3b1efed33ee4442b84d6b52d06 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -37,6 +37,7 @@ #include "lluictrlfactory.h" #include "llbutton.h" #include "llcheckboxctrl.h" +#include "llcriticaldamp.h" // LLSmoothInterpolation #include "lldir.h" #include "lldraghandle.h" #include "llfloaterreg.h" @@ -64,6 +65,10 @@ // use this to control "jumping" behavior when Ctrl-Tabbing const S32 TABBED_FLOATER_OFFSET = 0; +const F32 LLFloater::CONTEXT_CONE_IN_ALPHA = 0.0f; +const F32 LLFloater::CONTEXT_CONE_OUT_ALPHA = 1.f; +const F32 LLFloater::CONTEXT_CONE_FADE_TIME = 0.08f; + namespace LLInitParam { void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues() @@ -2116,6 +2121,70 @@ void LLFloater::updateTitleButtons() } } +void LLFloater::drawConeToOwner(F32 &context_cone_opacity, + F32 max_cone_opacity, + LLView *owner_view, + F32 fade_time, + F32 contex_cone_in_alpha, + F32 contex_cone_out_alpha) +{ + if (owner_view + && owner_view->isInVisibleChain() + && hasFocus() + && context_cone_opacity > 0.001f + && gFocusMgr.childHasKeyboardFocus(this)) + { + // draw cone of context pointing back to owner (e.x. texture swatch) + LLRect owner_rect; + owner_view->localRectToOtherView(owner_view->getLocalRect(), &owner_rect, this); + LLRect local_rect = getLocalRect(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLEnable(GL_CULL_FACE); + gGL.begin(LLRender::QUADS); + { + gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); + gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); + gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mRight, local_rect.mTop); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); + gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); + gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); + + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mRight, local_rect.mBottom); + gGL.vertex2i(local_rect.mRight, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); + gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); + gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); + + + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.vertex2i(local_rect.mRight, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); + gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); + gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); + } + gGL.end(); + } + + if (gFocusMgr.childHasMouseCapture(getDragHandle())) + { + context_cone_opacity = lerp(context_cone_opacity, max_cone_opacity, LLSmoothInterpolation::getInterpolant(fade_time)); + } + else + { + context_cone_opacity = lerp(context_cone_opacity, 0.f, LLSmoothInterpolation::getInterpolant(fade_time)); + } +} + void LLFloater::buildButtons(const Params& floater_params) { static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0); diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 165f67499be11baeb175569e05c1c41e32599046..f8c04e8a2fc18c5e1a5d462c5edccfda12d2006c 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -395,6 +395,15 @@ class LLFloater : public LLPanel, public LLInstanceTracker<LLFloater> virtual void updateTitleButtons(); + // Draws a cone from this floater to parent floater or view (owner) + // Modifies context_cone_opacity (interpolates according to fade time and returns new value) + void drawConeToOwner(F32 &context_cone_opacity, + F32 max_cone_opacity, + LLView *owner_view, + F32 context_fade_time = CONTEXT_CONE_FADE_TIME, + F32 contex_cone_in_alpha = CONTEXT_CONE_IN_ALPHA, + F32 contex_cone_out_alpha = CONTEXT_CONE_OUT_ALPHA); + private: void setForeground(BOOL b); // called only by floaterview void cleanupHandles(); // remove handles to dead floaters @@ -424,6 +433,10 @@ class LLFloater : public LLPanel, public LLInstanceTracker<LLFloater> void updateTransparency(LLView* view, ETypeTransparency transparency_type); public: + static const F32 CONTEXT_CONE_IN_ALPHA; + static const F32 CONTEXT_CONE_OUT_ALPHA; + static const F32 CONTEXT_CONE_FADE_TIME; + // Called when floater is opened, passes mKey // Public so external views or floaters can watch for this floater opening commit_signal_t mOpenSignal; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 200dd2fdca6498230d441daad8aa5f1aa5ce1c6f..1e18396184162cc4d7f806df470e6bcc6efc2496 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -212,6 +212,12 @@ LLSD LLMenuItemGL::getValue() const return getLabel(); } +//virtual +bool LLMenuItemGL::hasAccelerator(const KEY &key, const MASK &mask) const +{ + return (mAcceleratorKey == key) && (mAcceleratorMask == mask); +} + //virtual BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask) { @@ -263,13 +269,13 @@ BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask) // This function checks to see if the accelerator key is already in use; // if not, it will be added to the list -BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp) +BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp) { - LLKeyBinding *accelerator = NULL; + LLMenuKeyboardBinding *accelerator = NULL; if (mAcceleratorKey != KEY_NONE) { - std::list<LLKeyBinding*>::iterator list_it; + std::list<LLMenuKeyboardBinding*>::iterator list_it; for (list_it = listp->begin(); list_it != listp->end(); ++list_it) { accelerator = *list_it; @@ -293,7 +299,7 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp) } if (!accelerator) { - accelerator = new LLKeyBinding; + accelerator = new LLMenuKeyboardBinding; if (accelerator) { accelerator->mKey = mAcceleratorKey; @@ -788,6 +794,12 @@ void LLMenuItemCallGL::initFromParams(const Params& p) { setEnabledControlVariable(control); } + else + { + LL_WARNS() << "Failed to assign 'enabled' control variable to menu " << getName() + << ": control " << p.on_enable.control_name() + << " does not exist." << LL_ENDL; + } } } if (p.on_click.isProvided()) @@ -1011,6 +1023,11 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask) return TRUE; } +bool LLMenuItemBranchGL::hasAccelerator(const KEY &key, const MASK &mask) const +{ + return getBranch() && getBranch()->hasAccelerator(key, mask); +} + BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask) { return getBranch() && getBranch()->handleAcceleratorKey(key, mask); @@ -1018,7 +1035,7 @@ BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask) // This function checks to see if the accelerator key is already in use; // if not, it will be added to the list -BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLKeyBinding*> *listp) +BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp) { LLMenuGL* branch = getBranch(); if (!branch) @@ -2995,6 +3012,27 @@ void LLMenuGL::updateParent(LLView* parentp) } } +bool LLMenuGL::hasAccelerator(const KEY &key, const MASK &mask) const +{ + if (key == KEY_NONE) + { + return false; + } + // Note: checking this way because mAccelerators seems to be broken + // mAccelerators probably needs to be cleaned up or fixed + // It was used for dupplicate accelerator avoidance. + item_list_t::const_iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + LLMenuItemGL* itemp = *item_iter; + if (itemp->hasAccelerator(key, mask)) + { + return true; + } + } + return false; +} + BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask) { // don't handle if not enabled diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 78f688642ea5d0a57b746b21811abe7c1a11b7ca..f3844af507439bf6f699e310c6050e86f3f2a341 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -42,6 +42,13 @@ extern S32 MENU_BAR_HEIGHT; extern S32 MENU_BAR_WIDTH; +class LLMenuKeyboardBinding +{ +public: + KEY mKey; + MASK mMask; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemGL // @@ -91,6 +98,7 @@ class LLMenuItemGL: public LLUICtrl, public ll::ui::SearchableControl /*virtual*/ void setValue(const LLSD& value); /*virtual*/ LLSD getValue() const; + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; virtual BOOL handleAcceleratorKey(KEY key, MASK mask); LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } @@ -109,7 +117,7 @@ class LLMenuItemGL: public LLUICtrl, public ll::ui::SearchableControl virtual void setBriefItem(BOOL brief); virtual BOOL isBriefItem() const; - virtual BOOL addToAcceleratorList(std::list<LLKeyBinding*> *listp); + virtual BOOL addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp); void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } @@ -436,7 +444,8 @@ class LLMenuGL /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); /*virtual*/ void removeChild( LLView* ctrl); /*virtual*/ BOOL postBuild(); - + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; virtual BOOL handleAcceleratorKey(KEY key, MASK mask); LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; @@ -625,10 +634,11 @@ class LLMenuItemBranchGL : public LLMenuItemGL virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; virtual BOOL handleAcceleratorKey(KEY key, MASK mask); // check if we've used these accelerators already - virtual BOOL addToAcceleratorList(std::list <LLKeyBinding*> *listp); + virtual BOOL addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp); // called to rebuild the draw label virtual void buildDrawLabel( void ); @@ -794,7 +804,7 @@ class LLMenuBarGL : public LLMenuGL void checkMenuTrigger(); - std::list <LLKeyBinding*> mAccelerators; + std::list <LLMenuKeyboardBinding*> mAccelerators; BOOL mAltKeyTrigger; }; diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 9fc6c05ead9d5a70dcf1a52ff6c396432e2c1826..6a7075301bea873a472c71d21fb0538d79ae1d49 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -68,7 +68,8 @@ LLNotificationForm::FormIgnore::FormIgnore() control("control"), invert_control("invert_control", false), save_option("save_option", false), - session_only("session_only", false) + session_only("session_only", false), + checkbox_only("checkbox_only", false) {} LLNotificationForm::FormButton::FormButton() @@ -195,10 +196,15 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica { if (p.ignore.isProvided()) { + // For all cases but IGNORE_CHECKBOX_ONLY this is name for use in preferences mIgnoreMsg = p.ignore.text; LLUI *ui_inst = LLUI::getInstance(); - if (!p.ignore.save_option) + if (p.ignore.checkbox_only) + { + mIgnore = IGNORE_CHECKBOX_ONLY; + } + else if (!p.ignore.save_option) { mIgnore = p.ignore.session_only ? IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY : IGNORE_WITH_DEFAULT_RESPONSE; } @@ -215,7 +221,7 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica mIgnoreSetting = ui_inst->mSettingGroups["config"]->getControl(p.ignore.control); mInvertSetting = p.ignore.invert_control; } - else + else if (mIgnore > IGNORE_NO) { ui_inst->mSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT); mIgnoreSetting = ui_inst->mSettingGroups["ignores"]->getControl(name); @@ -389,13 +395,12 @@ LLControlVariablePtr LLNotificationForm::getIgnoreSetting() bool LLNotificationForm::getIgnored() { bool show = true; - if (mIgnore != LLNotificationForm::IGNORE_NO + if (mIgnore > LLNotificationForm::IGNORE_NO && mIgnoreSetting) { show = mIgnoreSetting->getValue().asBoolean(); if (mInvertSetting) show = !show; } - return !show; } @@ -696,7 +701,7 @@ void LLNotification::respond(const LLSD& response) mTemporaryResponder = false; } - if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + if (mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) { mForm->setIgnored(mIgnored); if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 15094469208151af209dd380ae03503842edc111..62cf41256bfd3984837f2ab7252114fd3df77158 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -180,6 +180,7 @@ class LLNotificationForm Optional<std::string> control; Optional<bool> invert_control; Optional<bool> session_only; + Optional<bool> checkbox_only; FormIgnore(); }; @@ -232,7 +233,8 @@ class LLNotificationForm typedef enum e_ignore_type { - IGNORE_NO, + IGNORE_CHECKBOX_ONLY = -1, // ignore won't be handled, will set value/checkbox only + IGNORE_NO = 0, IGNORE_WITH_DEFAULT_RESPONSE, IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY, IGNORE_WITH_LAST_RESPONSE, diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index b3a79bc1ebf4475549c522d1c26a92aaed4f2a2d..fde6de49219bc6acc031d1293bf462ac054651fd 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -408,6 +408,16 @@ BOOL LLScrollbar::handleScrollWheel(S32 x, S32 y, S32 clicks) return handled; } +BOOL LLScrollbar::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + BOOL handled = FALSE; + if (LLScrollbar::HORIZONTAL == mOrientation) + { + handled = changeLine(clicks * mStepSize, TRUE); + } + return handled; +} + BOOL LLScrollbar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg) { diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index e2bf52c14bce6463fef574a699f73b324a2a81e2..5f2f490d811884d2b3d6fe14bd5151dd5312d0d9 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -88,6 +88,7 @@ class LLScrollbar virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg); diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 6135cc56ad76197ed382d254134293613f25ac60..3db38bbfacf56e2bb6bee810757771fd7041427f 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -272,6 +272,25 @@ BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks ) return FALSE; } +BOOL LLScrollContainer::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + if (LLUICtrl::handleScrollHWheel(x,y,clicks)) + { + return TRUE; + } + + LLScrollbar* horizontal = mScrollbar[HORIZONTAL]; + if (horizontal->getVisible() + && horizontal->getEnabled() + && horizontal->handleScrollHWheel( 0, 0, clicks ) ) + { + updateScroll(); + return TRUE; + } + + return FALSE; +} + BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index e6c78913975c706a80e40e4fe22dec603c1ef354..c14099dbd5361f409905827eb5269396f72d37e2 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -107,6 +107,7 @@ class LLScrollContainer : public LLUICtrl virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleUnicodeCharHere(llwchar uni_char); virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + virtual BOOL handleScrollHWheel( S32 x, S32 y, S32 clicks ); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index 8000efad0e2c31927092168f7c90e283707b66bf..13839da400e504f3e369d034cf916e9d6c163eec 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -50,6 +50,10 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_ { cell = new LLScrollListDate(cell_p); } + else if (cell_p.type() == "icontext") + { + cell = new LLScrollListIconText(cell_p); + } else // default is "text" { cell = new LLScrollListText(cell_p); @@ -168,7 +172,7 @@ U32 LLScrollListText::sCount = 0; LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p) : LLScrollListCell(p), - mText(p.value().asString()), + mText(p.label.isProvided() ? p.label() : p.value().asString()), mFont(p.font), mColor(p.color), mUseColor(p.color.isProvided()), @@ -192,7 +196,7 @@ LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p) void LLScrollListText::highlightText(S32 offset, S32 num_chars) { mHighlightOffset = offset; - mHighlightCount = num_chars; + mHighlightCount = llmax(0, num_chars); } //virtual @@ -292,11 +296,12 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col if (mHighlightCount > 0) { + // Highlight text S32 left = 0; switch(mFontAlignment) { case LLFontGL::LEFT: - left = mFont->getWidth(mText.getString(), 0, mHighlightOffset); + left = mFont->getWidth(mText.getString(), 1, mHighlightOffset); break; case LLFontGL::RIGHT: left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX); @@ -319,7 +324,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col switch(mFontAlignment) { case LLFontGL::LEFT: - start_x = 0.f; + start_x = 1.f; break; case LLFontGL::RIGHT: start_x = (F32)getWidth(); @@ -435,3 +440,139 @@ const LLSD LLScrollListDate::getValue() const { return mDate; } + +// +// LLScrollListIconText +// +LLScrollListIconText::LLScrollListIconText(const LLScrollListCell::Params& p) + : LLScrollListText(p), + mIcon(p.value().isUUID() ? LLUI::getUIImageByID(p.value().asUUID()) : LLUI::getUIImage(p.value().asString())), + mPad(4) +{ + mTextWidth = getWidth() - mPad /*padding*/ - mFont->getLineHeight(); +} + +LLScrollListIconText::~LLScrollListIconText() +{ +} + +const LLSD LLScrollListIconText::getValue() const +{ + if (mIcon.isNull()) + { + return LLStringUtil::null; + } + return mIcon->getName(); +} + +void LLScrollListIconText::setValue(const LLSD& value) +{ + if (value.isUUID()) + { + // don't use default image specified by LLUUID::null, use no image in that case + LLUUID image_id = value.asUUID(); + mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL); + } + else + { + std::string value_string = value.asString(); + if (LLUUID::validate(value_string)) + { + setValue(LLUUID(value_string)); + } + else if (!value_string.empty()) + { + mIcon = LLUI::getUIImage(value.asString()); + } + else + { + mIcon = NULL; + } + } +} + +void LLScrollListIconText::setWidth(S32 width) +{ + LLScrollListCell::setWidth(width); + // Assume that iamge height and width is identical to font height and width + mTextWidth = width - mPad /*padding*/ - mFont->getLineHeight(); +} + + +void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color) const +{ + LLColor4 display_color; + if (mUseColor) + { + display_color = mColor; + } + else + { + display_color = color; + } + + S32 icon_height = mFont->getLineHeight(); + S32 icon_space = mIcon ? (icon_height + mPad) : 0; + + if (mHighlightCount > 0) + { + S32 left = 0; + switch (mFontAlignment) + { + case LLFontGL::LEFT: + left = mFont->getWidth(mText.getString(), icon_space + 1, mHighlightOffset); + break; + case LLFontGL::RIGHT: + left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX) - icon_space; + break; + case LLFontGL::HCENTER: + left = (getWidth() - mFont->getWidth(mText.getString()) - icon_space) / 2; + break; + } + LLRect highlight_rect(left - 2, + mFont->getLineHeight() + 1, + left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1, + 1); + mRoundedRectImage->draw(highlight_rect, highlight_color); + } + + // Try to draw the entire string + F32 right_x; + U32 string_chars = mText.length(); + F32 start_text_x = 0.f; + S32 start_icon_x = 0; + switch (mFontAlignment) + { + case LLFontGL::LEFT: + start_text_x = icon_space + 1; + start_icon_x = 1; + break; + case LLFontGL::RIGHT: + start_text_x = (F32)getWidth(); + start_icon_x = getWidth() - mFont->getWidth(mText.getString()) - icon_space; + break; + case LLFontGL::HCENTER: + F32 center = (F32)getWidth()* 0.5f; + start_text_x = center + ((F32)icon_space * 0.5f); + start_icon_x = center - (((F32)icon_space + mFont->getWidth(mText.getString())) * 0.5f); + break; + } + mFont->render(mText.getWString(), 0, + start_text_x, 0.f, + display_color, + mFontAlignment, + LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + string_chars, + getTextWidth(), + &right_x, + TRUE); + + if (mIcon) + { + mIcon->draw(start_icon_x, 0, icon_height, icon_height, mColor); + } +} + + diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h index d625ebddccacc025f33671fe40a765ac32c22b73..19576fb247adf131a06e44c6e34cb06dbf74f368 100644 --- a/indra/llui/llscrolllistcell.h +++ b/indra/llui/llscrolllistcell.h @@ -59,7 +59,8 @@ class LLScrollListCell visible; Optional<void*> userdata; - Optional<LLSD> value; + Optional<LLSD> value; // state of checkbox, icon id/name, date + Optional<std::string> label; // description or text Optional<std::string> tool_tip; Optional<const LLFontGL*> font; @@ -75,6 +76,7 @@ class LLScrollListCell enabled("enabled", true), visible("visible", true), value("value"), + label("label"), tool_tip("tool_tip", ""), font("font", LLFontGL::getFontSansSerifSmall()), font_color("font_color", LLColor4::black), @@ -152,11 +154,12 @@ class LLScrollListText : public LLScrollListCell void setText(const LLStringExplicit& text); void setFontStyle(const U8 font_style); -private: +protected: LLUIString mText; S32 mTextWidth; const LLFontGL* mFont; LLColor4 mColor; + LLColor4 mHighlightColor; U8 mUseColor; LLFontGL::HAlign mFontAlignment; BOOL mVisible; @@ -169,7 +172,7 @@ class LLScrollListText : public LLScrollListCell }; /* - * Cell displaying an image. + * Cell displaying an image. AT the moment, this is specifically UI image */ class LLScrollListIcon : public LLScrollListCell { @@ -223,4 +226,26 @@ class LLScrollListDate : public LLScrollListText LLDate mDate; }; +/* +* Cell displaying icon and text. +*/ + +class LLScrollListIconText : public LLScrollListText +{ +public: + LLScrollListIconText(const LLScrollListCell::Params& p); + /*virtual*/ ~LLScrollListIconText(); + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ const LLSD getValue() const; + /*virtual*/ void setValue(const LLSD& value); + + + S32 getIconWidth() const; + /*virtual*/ void setWidth(S32 width);/* { LLScrollListCell::setWidth(width); mTextWidth = width - ; }*/ + +private: + LLPointer<LLUIImage> mIcon; + S32 mPad; +}; + #endif diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index f4028057e8565b66078f4b9abc706c30910923e4..94b130e28d6fcd17d4d0ad75e8043633333c4ed2 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -115,6 +115,13 @@ struct SortScrollListItem // LLScrollListCtrl //--------------------------------------------------------------------------- +void LLScrollListCtrl::SelectionTypeNames::declareValues() +{ + declare("row", LLScrollListCtrl::ROW); + declare("cell", LLScrollListCtrl::CELL); + declare("header", LLScrollListCtrl::HEADER); +} + LLScrollListCtrl::Contents::Contents() : columns("column"), rows("row") @@ -128,8 +135,10 @@ LLScrollListCtrl::Params::Params() has_border("draw_border"), draw_heading("draw_heading"), search_column("search_column", 0), + selection_type("selection_type", ROW), sort_column("sort_column", -1), sort_ascending("sort_ascending", true), + can_sort("can_sort", true), mouse_wheel_opaque("mouse_wheel_opaque", false), commit_on_keyboard_movement("commit_on_keyboard_movement", true), heading_height("heading_height"), @@ -163,8 +172,10 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mCommitOnKeyboardMovement(p.commit_on_keyboard_movement), mCommitOnSelectionChange(false), mSelectionChanged(false), + mSelectionType(p.selection_type), mNeedsScroll(false), mCanSelect(true), + mCanSort(p.can_sort), mColumnsDirty(false), mMaxItemCount(INT_MAX), mBorderThickness( 2 ), @@ -819,7 +830,15 @@ BOOL LLScrollListCtrl::selectFirstItem() { if (!itemp->getSelected()) { - selectItem(itemp); + switch (mSelectionType) + { + case CELL: + selectItem(itemp, 0); + break; + case HEADER: + case ROW: + selectItem(itemp, -1); + } } success = TRUE; mOriginalSelection = 0; @@ -878,7 +897,8 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index ) { if( itemp->getEnabled() ) { - selectItem(itemp, FALSE); + // TODO: support range selection for cells + selectItem(itemp, -1, FALSE); success = TRUE; } } @@ -1004,10 +1024,14 @@ void LLScrollListCtrl::clearHighlightedItems() void LLScrollListCtrl::mouseOverHighlightNthItem(S32 target_index) { - if (mHighlightedItem != target_index) - { - mHighlightedItem = target_index; - } + if (mHighlightedItem != target_index) + { + if (mHighlightedItem >= 0 && mHighlightedItem < mItemList.size()) + { + mItemList[mHighlightedItem]->setHoverCell(-1); + } + mHighlightedItem = target_index; + } } S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids ) @@ -1022,7 +1046,8 @@ S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids ) { if (item->getEnabled() && (item->getUUID() == (*iditr))) { - selectItem(item,FALSE); + // TODO: support multiple selection for cells + selectItem(item, -1, FALSE); ++count; break; } @@ -1095,7 +1120,7 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection) { if (prev_item) { - selectItem(prev_item, !extend_selection); + selectItem(prev_item, cur_item->getSelectedCell(), !extend_selection); } else { @@ -1139,7 +1164,7 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection) { if (next_item) { - selectItem(next_item, !extend_selection); + selectItem(next_item, cur_item->getSelectedCell(), !extend_selection); } else { @@ -1210,7 +1235,7 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen bool found = NULL != item; if(found) { - selectItem(item); + selectItem(item, -1); } if (mCommitOnSelectionChange) @@ -1278,7 +1303,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE; if (select) { - selectItem(item); + selectItem(item, -1); found = TRUE; break; } @@ -1318,7 +1343,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen // find offset of matching text (might have leading whitespace) S32 offset = item_label.find(target_trimmed); cellp->highlightText(offset, target_trimmed.size()); - selectItem(item); + selectItem(item, -1); found = TRUE; break; } @@ -1384,7 +1409,7 @@ BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected) { if (selected) { - selectItem(item); + selectItem(item, -1); } else { @@ -1464,7 +1489,7 @@ void LLScrollListCtrl::drawItems() S32 max_columns = 0; - LLColor4 highlight_color = LLColor4::white; + LLColor4 highlight_color = LLColor4::white; // ex: text inside cells static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0); highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout(), 0.4f, 0.f); @@ -1490,7 +1515,8 @@ void LLScrollListCtrl::drawItems() max_columns = llmax(max_columns, item->getNumColumns()); LLColor4 fg_color; - LLColor4 bg_color(LLColor4::transparent); + LLColor4 hover_color(LLColor4::transparent); + LLColor4 select_color(LLColor4::transparent); if( mScrollLines <= line && line < mScrollLines + num_page_lines ) { @@ -1499,44 +1525,44 @@ void LLScrollListCtrl::drawItems() { if(item->getHighlighted()) // if it's highlighted, average the colors { - bg_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f); + select_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f); } else // otherwise just select-highlight it { - bg_color = mBgSelectedColor.get(); + select_color = mBgSelectedColor.get(); } fg_color = (item->getEnabled() ? mFgSelectedColor.get() : mFgDisabledColor.get()); } - else if (mHighlightedItem == line && mCanSelect) + if (mHighlightedItem == line && mCanSelect) { if(item->getHighlighted()) // if it's highlighted, average the colors { - bg_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f); + hover_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f); } else // otherwise just hover-highlight it { - bg_color = mHoveredColor.get(); + hover_color = mHoveredColor.get(); } } else if (item->getHighlighted()) { - bg_color = mHighlightedColor.get(); + hover_color = mHighlightedColor.get(); } else { if (mDrawStripes && (line % 2 == 0) && (max_columns > 1)) { - bg_color = mBgStripeColor.get(); + hover_color = mBgStripeColor.get(); } } if (!item->getEnabled()) { - bg_color = mBgReadOnlyColor.get(); + hover_color = mBgReadOnlyColor.get(); } - item->draw(item_rect, fg_color % alpha, bg_color% alpha, highlight_color % alpha, mColumnPadding); + item->draw(item_rect, fg_color % alpha, hover_color% alpha, select_color% alpha, highlight_color % alpha, mColumnPadding); cur_y -= mLineHeight; } @@ -1601,6 +1627,20 @@ BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks) return handled; } +BOOL LLScrollListCtrl::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + BOOL handled = FALSE; + // Pretend the mouse is over the scrollbar + handled = mScrollbar->handleScrollHWheel( 0, 0, clicks ); + + if (mMouseWheelOpaque) + { + return TRUE; + } + + return handled; +} + // *NOTE: Requires a valid row_index and column_index LLRect LLScrollListCtrl::getCellRect(S32 row_index, S32 column_index) { @@ -1674,7 +1714,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) { if (mLastSelected == NULL) { - selectItem(hit_item); + selectItem(hit_item, getColumnIndexFromOffset(x)); } else { @@ -1698,7 +1738,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) LLScrollListItem *item = *itor; if (item == hit_item || item == lastSelected) { - selectItem(item, FALSE); + selectItem(item, getColumnIndexFromOffset(x), FALSE); selecting = !selecting; if (hit_item == lastSelected) { @@ -1708,7 +1748,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) } if (selecting) { - selectItem(item, FALSE); + selectItem(item, getColumnIndexFromOffset(x), FALSE); } } } @@ -1723,7 +1763,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) { if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable)) { - selectItem(hit_item, FALSE); + selectItem(hit_item, getColumnIndexFromOffset(x), FALSE); } else { @@ -1737,12 +1777,12 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) else { deselectAllItems(TRUE); - selectItem(hit_item); + selectItem(hit_item, getColumnIndexFromOffset(x)); } } else { - selectItem(hit_item); + selectItem(hit_item, getColumnIndexFromOffset(x)); } selection_changed = mSelectionChanged; @@ -2110,8 +2150,29 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask) { LLScrollListItem* item = hitItem(x, y); if (item) - { - mouseOverHighlightNthItem(getItemIndex(item)); + { + mouseOverHighlightNthItem(getItemIndex(item)); + switch (mSelectionType) + { + case CELL: + item->setHoverCell(getColumnIndexFromOffset(x)); + break; + case HEADER: + { + S32 cell = getColumnIndexFromOffset(x); + if (cell > 0) + { + item->setHoverCell(cell); + } + else + { + item->setHoverCell(-1); + } + break; + } + case ROW: + break; + } } else { @@ -2159,6 +2220,52 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask ) handled = TRUE; } break; + case KEY_LEFT: + if (mAllowKeyboardMovement || hasFocus()) + { + // TODO: support multi-select + LLScrollListItem *item = getFirstSelected(); + S32 cell = item->getSelectedCell(); + switch (mSelectionType) + { + case CELL: + if (cell < mColumns.size()) cell++; + break; + case HEADER: + if (cell == -1) cell = 1; + else if (cell > 1 && cell < mColumns.size()) cell++; // skip header + break; + case ROW: + cell = -1; + break; + } + item->setSelectedCell(cell); + handled = TRUE; + } + break; + case KEY_RIGHT: + if (mAllowKeyboardMovement || hasFocus()) + { + // TODO: support multi-select + LLScrollListItem *item = getFirstSelected(); + S32 cell = item->getSelectedCell(); + switch (mSelectionType) + { + case CELL: + if (cell >= 0) cell--; + break; + case HEADER: + if (cell > 1) cell--; + else if (cell == 1) cell = -1; // skip header + break; + case ROW: + cell = -1; + break; + } + item->setSelectedCell(cell); + handled = TRUE; + } + break; case KEY_PAGE_UP: if (mAllowKeyboardMovement || hasFocus()) { @@ -2327,7 +2434,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char) LLWString item_label = utf8str_to_wstring(cellp->getValue().asString()); if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char) { - selectItem(item); + selectItem(item, -1); mNeedsScroll = true; cellp->highlightText(0, 1); mSearchTimer.reset(); @@ -2379,7 +2486,7 @@ BOOL LLScrollListCtrl::isRepeatedChars(const LLWString& string) const return TRUE; } -void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_item) +void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, BOOL select_single_item) { if (!itemp) return; @@ -2398,6 +2505,18 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_it deselectAllItems(TRUE); } itemp->setSelected(TRUE); + switch (mSelectionType) + { + case CELL: + itemp->setSelectedCell(cell); + break; + case HEADER: + itemp->setSelectedCell(cell <= 0 ? -1 : cell); + break; + case ROW: + itemp->setSelectedCell(-1); + break; + } mLastSelected = itemp; mSelectionChanged = true; } @@ -2658,7 +2777,7 @@ void LLScrollListCtrl::selectAll() LLScrollListItem *itemp = *iter; if( itemp->getEnabled() ) { - selectItem(itemp, FALSE); + selectItem(itemp, -1, FALSE); } } @@ -2787,6 +2906,8 @@ void LLScrollListCtrl::onClickColumn(void *userdata) LLScrollListCtrl *parent = info->mParentCtrl; if (!parent) return; + if (!parent->mCanSort) return; + S32 column_index = info->mIndex; LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex]; diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index b35a8608e70d82e2b9ec8f9ab7fb0d764ad329b2..bf1055c8dc07e8e5a4ed0224ac8ce349ddd20ddd 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -54,6 +54,18 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, public LLCtrlListInterface, public LLCtrlScrollInterface { public: + typedef enum e_selection_type + { + ROW, // default + CELL, // does not support multi-selection + HEADER, // when pointing to cells in column 0 will highlight whole row, otherwise cell, no multi-select + } ESelectionType; + + struct SelectionTypeNames : public LLInitParam::TypeValuesHelper<LLScrollListCtrl::ESelectionType, SelectionTypeNames> + { + static void declareValues(); + }; + struct Contents : public LLInitParam::Block<Contents> { Multiple<LLScrollListColumn::Params> columns; @@ -99,6 +111,8 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, commit_on_keyboard_movement, mouse_wheel_opaque; + Optional<ESelectionType, SelectionTypeNames> selection_type; + // display flags Optional<bool> has_border, draw_heading, @@ -114,7 +128,8 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, // sort and search behavior Optional<S32> search_column, sort_column; - Optional<bool> sort_ascending; + Optional<bool> sort_ascending, + can_sort; // whether user is allowed to sort // colors Optional<LLUIColor> fg_unselected_color, @@ -317,6 +332,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); /*virtual*/ void setEnabled(BOOL enabled); /*virtual*/ void setFocus( BOOL b ); @@ -428,7 +444,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, void updateLineHeightInsert(LLScrollListItem* item); void reportInvalidInput(); BOOL isRepeatedChars(const LLWString& string) const; - void selectItem(LLScrollListItem* itemp, BOOL single_select = TRUE); + void selectItem(LLScrollListItem* itemp, S32 cell, BOOL single_select = TRUE); void deselectItem(LLScrollListItem* itemp); void commitIfChanged(); BOOL setSort(S32 column, BOOL ascending); @@ -453,9 +469,11 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, bool mCommitOnKeyboardMovement; bool mCommitOnSelectionChange; bool mSelectionChanged; + ESelectionType mSelectionType; bool mNeedsScroll; bool mMouseWheelOpaque; bool mCanSelect; + bool mCanSort; // Whether user is allowed to sort bool mDisplayColumnHeaders; bool mColumnsDirty; bool mColumnWidthsDirty; diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp index df22c88afb428ec6c21348825a24ee19adff81df..51c615dd0037e23f0f5620ee07196c8470ce95f2 100644 --- a/indra/llui/llscrolllistitem.cpp +++ b/indra/llui/llscrolllistitem.cpp @@ -40,6 +40,8 @@ LLScrollListItem::LLScrollListItem( const Params& p ) : mSelected(FALSE), mHighlighted(FALSE), + mHoverIndex(-1), + mSelectedIndex(-1), mEnabled(p.enabled), mUserdata(p.userdata), mItemValue(p.value) @@ -53,6 +55,28 @@ LLScrollListItem::~LLScrollListItem() mColumns.clear(); } +void LLScrollListItem::setSelected(BOOL b) +{ + mSelected = b; + mSelectedIndex = -1; +} + +void LLScrollListItem::setHighlighted(BOOL b) +{ + mHighlighted = b; + mHoverIndex = -1; +} + +void LLScrollListItem::setHoverCell(S32 cell) +{ + mHoverIndex = cell; +} + +void LLScrollListItem::setSelectedCell(S32 cell) +{ + mSelectedIndex = cell; +} + void LLScrollListItem::addColumn(const LLScrollListCell::Params& p) { mColumns.push_back(LLScrollListCell::create(p)); @@ -120,12 +144,21 @@ std::string LLScrollListItem::getContentsCSV() const } -void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding) +void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& hover_color, const LLColor4& select_color, const LLColor4& highlight_color, S32 column_padding) { // draw background rect gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLRect bg_rect = rect; - gl_rect_2d( bg_rect, bg_color ); + if (mSelectedIndex < 0 && getSelected()) + { + // Whole item is highlighted/selected + gl_rect_2d(bg_rect, select_color); + } + else if (mHoverIndex < 0) + { + // Whole item is highlighted/selected + gl_rect_2d(bg_rect, hover_color); + } S32 cur_x = rect.mLeft; S32 num_cols = getNumColumns(); @@ -141,6 +174,25 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const { LLUI::translate((F32) cur_x, (F32) rect.mBottom); + if (mSelectedIndex == cur_col) + { + // select specific cell + LLRect highlight_rect(0, + cell->getHeight(), + cell->getWidth(), + 0); + gl_rect_2d(highlight_rect, select_color); + } + else if (mHoverIndex == cur_col) + { + // highlight specific cell + LLRect highlight_rect(0, + cell->getHeight(), + cell->getWidth() , + 0); + gl_rect_2d(highlight_rect, hover_color); + } + cell->draw( fg_color, highlight_color ); } LLUI::popMatrix(); diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h index 13655b5873b9f5cf8e35938e6e0ea92442632f9b..d2c3dd7721b2c54fafd02b48cc0de7b9985f5e27 100644 --- a/indra/llui/llscrolllistitem.h +++ b/indra/llui/llscrolllistitem.h @@ -77,15 +77,21 @@ class LLScrollListItem virtual ~LLScrollListItem(); - void setSelected( BOOL b ) { mSelected = b; } + void setSelected( BOOL b ); BOOL getSelected() const { return mSelected; } void setEnabled( BOOL b ) { mEnabled = b; } BOOL getEnabled() const { return mEnabled; } - void setHighlighted( BOOL b ) { mHighlighted = b; } + void setHighlighted( BOOL b ); BOOL getHighlighted() const { return mHighlighted; } + void setSelectedCell( S32 cell ); + S32 getSelectedCell() const { return mSelectedIndex; } + + void setHoverCell( S32 cell ); + S32 getHoverCell() const { return mHoverIndex; } + void setUserdata( void* userdata ) { mUserdata = userdata; } void* getUserdata() const { return mUserdata; } @@ -107,14 +113,21 @@ class LLScrollListItem std::string getContentsCSV() const; - virtual void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding); + virtual void draw(const LLRect& rect, + const LLColor4& fg_color, + const LLColor4& hover_color, // highlight/hover selection of whole item or cell + const LLColor4& select_color, // highlight/hover selection of whole item or cell + const LLColor4& highlight_color, // highlights contents of cells (ex: text) + S32 column_padding); protected: LLScrollListItem( const Params& ); private: BOOL mSelected; - BOOL mHighlighted; + BOOL mHighlighted; + S32 mHoverIndex; + S32 mSelectedIndex; BOOL mEnabled; void* mUserdata; LLSD mItemValue; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 22635f734e6fa213dd09751a672e7b802161a1ec..e64078828b813e8a6fa0ddc3f9ecc65a2da1b9f3 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -3113,6 +3113,7 @@ BOOL LLTextSegment::handleRightMouseUp(S32 x, S32 y, MASK mask) { return FALSE; BOOL LLTextSegment::handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; } BOOL LLTextSegment::handleHover(S32 x, S32 y, MASK mask) { return FALSE; } BOOL LLTextSegment::handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; } +BOOL LLTextSegment::handleScrollHWheel(S32 x, S32 y, S32 clicks) { return FALSE; } BOOL LLTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { return FALSE; } const std::string& LLTextSegment::getName() const { diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 9831c35858f5253d81f8f8a2f5695a575d868cbf..4239cdf43c52109c4c68974052bd03eede43d891 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -103,6 +103,7 @@ class LLTextSegment /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); /*virtual*/ const std::string& getName() const; /*virtual*/ void onMouseCaptureLost(); diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index df74e113e9bc954f56f526e29427cc2c34da3547..c98da0d41043dec1367871be9313a24f4b4030e8 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -137,13 +137,29 @@ void LLUICtrl::initFromParams(const Params& p) { LLControlVariable* control = findControl(p.enabled_controls.enabled); if (control) + { setEnabledControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign 'enabled' control variable to " << getName() + << ": control " << p.enabled_controls.enabled() + << " does not exist." << LL_ENDL; + } } else if(p.enabled_controls.disabled.isChosen()) { LLControlVariable* control = findControl(p.enabled_controls.disabled); if (control) + { setDisabledControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign 'disabled' control variable to " << getName() + << ": control " << p.enabled_controls.disabled() + << " does not exist." << LL_ENDL; + } } } if(p.controls_visibility.isProvided()) @@ -152,13 +168,29 @@ void LLUICtrl::initFromParams(const Params& p) { LLControlVariable* control = findControl(p.controls_visibility.visible); if (control) + { setMakeVisibleControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign visibility control variable to " << getName() + << ": control " << p.controls_visibility.visible() + << " does not exist." << LL_ENDL; + } } else if (p.controls_visibility.invisible.isChosen()) { LLControlVariable* control = findControl(p.controls_visibility.invisible); if (control) + { setMakeInvisibleControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign invisibility control variable to " << getName() + << ": control " << p.controls_visibility.invisible() + << " does not exist." << LL_ENDL; + } } } @@ -497,6 +529,11 @@ void LLUICtrl::setControlName(const std::string& control_name, LLView *context) if (!control_name.empty()) { LLControlVariable* control = context->findControl(control_name); + if (!control) + { + LL_WARNS() << "Failed to assign control variable to " << getName() + << ": control "<< control_name << " does not exist." << LL_ENDL; + } setControlVariable(control); } } diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 03d946f1b7729e6cc9808ba78529e5abc06b0877..f740f14e4d99b0f5728c5a5c4337469fcea04e3d 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -160,8 +160,8 @@ class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory> LLXMLNodePtr root_node; if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node)) - { - LL_WARNS() << "Couldn't parse XUI file: " << instance().getCurFileName() << LL_ENDL; + { + LL_WARNS() << "Couldn't parse XUI from path: " << instance().getCurFileName() << ", from filename: " << filename << LL_ENDL; goto fail; } diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 63ed427ab582334d7c8fe2f94c1466c6ec7f1179..333d03f208da6ee44e86357946d133f40c534163 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -454,13 +454,13 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const } // -// LLUrlEntrySeconlifeURL Describes *secondlife.com/ and *lindenlab.com/ urls to substitute icon 'hand.png' before link +// LLUrlEntrySeconlifeURL Describes *secondlife.com/ *lindenlab.com/ and *tilia-inc.com/ urls to substitute icon 'hand.png' before link // LLUrlEntrySecondlifeURL::LLUrlEntrySecondlifeURL() { - mPattern = boost::regex("((http://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com)" + mPattern = boost::regex("((http://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com)" "|" - "(https://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?))" + "(https://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(:\\d{1,5})?))" "\\/\\S*", boost::regex::perl|boost::regex::icase); @@ -495,11 +495,11 @@ std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const } // -// LLUrlEntrySimpleSecondlifeURL Describes *secondlife.com and *lindenlab.com urls to substitute icon 'hand.png' before link +// LLUrlEntrySimpleSecondlifeURL Describes *secondlife.com *lindenlab.com and *tilia-inc.com urls to substitute icon 'hand.png' before link // LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL() { - mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)", + mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(?!\\S)", boost::regex::perl|boost::regex::icase); mIcon = "Hand"; diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 2a190365b3e4d94a6230af95ba6a3ebe8aa31cf4..771d32d2fcddf48c4553442c47e7c173964d274a 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -875,10 +875,16 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask) F32 timeout = LLToolTipMgr::instance().toolTipVisible() ? LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipFastDelay" ) : LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipDelay" ); - LLToolTipMgr::instance().show(LLToolTip::Params() - .message(tooltip) - .sticky_rect(calcScreenRect()) - .delay_time(timeout)); + + // Even if we don't show tooltips, consume the event, nothing below should show tooltip + bool allow_ui_tooltips = LLUI::sSettingGroups["config"]->getBOOL( "BasicUITooltips" ); + if (allow_ui_tooltips) + { + LLToolTipMgr::instance().show(LLToolTip::Params() + .message(tooltip) + .sticky_rect(calcScreenRect()) + .delay_time(timeout)); + } handled = TRUE; } @@ -1054,6 +1060,11 @@ BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks) return childrenHandleScrollWheel( x, y, clicks ) != NULL; } +BOOL LLView::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + return childrenHandleScrollHWheel( x, y, clicks ) != NULL; +} + BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask) { return childrenHandleRightMouseDown( x, y, mask ) != NULL; @@ -1079,6 +1090,11 @@ LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks) return childrenHandleMouseEvent(&LLView::handleScrollWheel, x, y, clicks, false); } +LLView* LLView::childrenHandleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + return childrenHandleMouseEvent(&LLView::handleScrollHWheel, x, y, clicks, false); +} + // Called during downward traversal LLView* LLView::childrenHandleKey(KEY key, MASK mask) { diff --git a/indra/llui/llview.h b/indra/llui/llview.h index e36ca7c8c691a4abb83d92677bc678d8e7012de7..db81900aaff267e0d149d76ab712159bd3edc704 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -426,6 +426,7 @@ class LLView /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); @@ -556,6 +557,7 @@ class LLView LLView* childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask); LLView* childrenHandleDoubleClick(S32 x, S32 y, MASK mask); LLView* childrenHandleScrollWheel(S32 x, S32 y, S32 clicks); + LLView* childrenHandleScrollHWheel(S32 x, S32 y, S32 clicks); LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask); LLView* childrenHandleRightMouseUp(S32 x, S32 y, MASK mask); LLView* childrenHandleToolTip(S32 x, S32 y, MASK mask); diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index 119cbebc8146f693a69fcacef545605a28a9a1ff..3c34fd269eb7ef418491e14d44a9c4d7305f7609 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -36,6 +36,11 @@ #include <boost/regex.hpp> +#if LL_WINDOWS +// because something pulls in window and lldxdiag dependencies which in turn need wbemuuid.lib + #pragma comment(lib, "wbemuuid.lib") +#endif + // namespace LLExperienceCache // { diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index d4790f9f294bca55a2112b6dd50511acf6fcca4c..12a6baa3e694d57c41075d1588970768322dbbe7 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -61,7 +61,7 @@ typedef BOOL ( WINAPI* PfnCoSetProxyBlanket )( IUnknown* pProxy, DWORD dwAuthnSv OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel, RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities ); -HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) +HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam) { HRESULT hr; bool bGotMemory = false; @@ -149,21 +149,26 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) if ( !pVideoControllers[iController] ) continue; - pPropName = SysAllocString( L"PNPDeviceID" ); - hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); + // if strInputDeviceID is set find this specific device and return memory or specific device + // if strInputDeviceID is not set return the best device + if (strInputDeviceID) + { + pPropName = SysAllocString( L"PNPDeviceID" ); + hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); #ifdef PRINTF_DEBUGGING - if( FAILED( hr ) ) - wprintf( L"WMI: pVideoControllers[iController]->Get PNPDeviceID failed: 0x%0.8x\n", hr ); + if( FAILED( hr ) ) + wprintf( L"WMI: pVideoControllers[iController]->Get PNPDeviceID failed: 0x%0.8x\n", hr ); #endif - if( SUCCEEDED( hr ) ) - { - if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 ) - bFound = true; + if( SUCCEEDED( hr ) && strInputDeviceID) + { + if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 ) + bFound = true; + } + VariantClear( &var ); + if( pPropName ) SysFreeString( pPropName ); } - VariantClear( &var ); - if( pPropName ) SysFreeString( pPropName ); - if( bFound ) + if( bFound || !strInputDeviceID ) { pPropName = SysAllocString( L"AdapterRAM" ); hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); @@ -175,13 +180,18 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) if( SUCCEEDED( hr ) ) { bGotMemory = true; - *pdwAdapterRam = var.ulVal; + *pdwAdapterRam = llmax(var.ulVal, *pdwAdapterRam); } VariantClear( &var ); if( pPropName ) SysFreeString( pPropName ); - break; } + SAFE_RELEASE( pVideoControllers[iController] ); + + if (bFound) + { + break; + } } } } @@ -207,6 +217,17 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) return E_FAIL; } +//static +S32 LLDXHardware::getMBVideoMemoryViaWMI() +{ + DWORD vram = 0; + if (SUCCEEDED(GetVideoMemoryViaWMI(NULL, &vram))) + { + return vram / (1024 * 1024);; + } + return 0; +} + //Getting the version of graphics controller driver via WMI std::string LLDXHardware::getDriverVersionWMI() { @@ -613,6 +634,9 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) IDxDiagContainer *device_containerp = NULL; IDxDiagContainer *file_containerp = NULL; IDxDiagContainer *driver_containerp = NULL; + DWORD dw_device_count; + + mVRAM = 0; // CoCreate a IDxDiagProvider* LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; @@ -663,10 +687,21 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); if(FAILED(hr) || !devices_containerp) { + // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp + devices_containerp = NULL; goto LCleanup; } + // make sure there is something inside + hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count); + if (FAILED(hr) || dw_device_count == 0) + { + goto LCleanup; + } + // Get device 0 + // By default 0 device is the primary one, howhever in case of various hybrid graphics + // like itegrated AMD and PCI AMD GPUs system might switch. LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL; hr = devices_containerp->GetChildContainer(L"0", &device_containerp); if(FAILED(hr) || !device_containerp) @@ -679,12 +714,27 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) WCHAR deviceID[512]; get_wstring(device_containerp, L"szDeviceID", deviceID, 512); - + // Example: searches id like 1F06 in pnp string (aka VEN_10DE&DEV_1F06) + // doesn't seem to work on some systems since format is unrecognizable + // but in such case keyDeviceID works if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID, &vram))) { mVRAM = vram/(1024*1024); } else + { + get_wstring(device_containerp, L"szKeyDeviceID", deviceID, 512); + LL_WARNS() << "szDeviceID" << deviceID << LL_ENDL; + // '+9' to avoid ENUM\\PCI\\ prefix + // Returns string like Enum\\PCI\\VEN_10DE&DEV_1F06&SUBSYS... + // and since GetVideoMemoryViaWMI searches by PNPDeviceID it is sufficient + if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID + 9, &vram))) + { + mVRAM = vram / (1024 * 1024); + } + } + + if (mVRAM == 0) { // Get the English VRAM string std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish"); @@ -872,6 +922,7 @@ LLSD LLDXHardware::getDisplayInfo() IDxDiagContainer *device_containerp = NULL; IDxDiagContainer *file_containerp = NULL; IDxDiagContainer *driver_containerp = NULL; + DWORD dw_device_count; // CoCreate a IDxDiagProvider* LL_INFOS() << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; @@ -922,9 +973,18 @@ LLSD LLDXHardware::getDisplayInfo() hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); if(FAILED(hr) || !devices_containerp) { + // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp + devices_containerp = NULL; goto LCleanup; } + // make sure there is something inside + hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count); + if (FAILED(hr) || dw_device_count == 0) + { + goto LCleanup; + } + // Get device 0 LL_INFOS() << "devices_containerp->GetChildContainer" << LL_ENDL; hr = devices_containerp->GetChildContainer(L"0", &device_containerp); @@ -976,6 +1036,10 @@ LLSD LLDXHardware::getDisplayInfo() } LCleanup: + if (ret.emptyMap()) + { + LL_INFOS() << "Failed to get data, cleaning up" << LL_ENDL; + } SAFE_RELEASE(file_containerp); SAFE_RELEASE(driver_containerp); SAFE_RELEASE(device_containerp); diff --git a/indra/llwindow/lldxhardware.h b/indra/llwindow/lldxhardware.h index cf33db8b3726231804b4a95faf33d726e7e0b167..1cb687e3b6d5794f71c13d088eb336649688b92b 100644 --- a/indra/llwindow/lldxhardware.h +++ b/indra/llwindow/lldxhardware.h @@ -94,6 +94,10 @@ class LLDXHardware LLSD getDisplayInfo(); + // Will get memory of best GPU in MB, return memory on sucsess, 0 on failure + // Note: WMI is not accurate in some cases + static S32 getMBVideoMemoryViaWMI(); + // Find a particular device that matches the following specs. // Empty strings indicate that you don't care. // You can separate multiple devices with '|' chars to indicate you want diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index f6f6c3931cb16073b2c43ffb1fa9773fa2cbd404..5404ac50e5c5baefe53ec7e2f65bf6b5d0604388 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -327,7 +327,7 @@ BOOL LLKeyboard::keyFromString(const std::string& str, KEY *key) // static -std::string LLKeyboard::stringFromKey(KEY key) +std::string LLKeyboard::stringFromKey(KEY key, bool translate) { std::string res = get_if_there(sKeysToNames, key, std::string()); if (res.empty()) @@ -338,16 +338,60 @@ std::string LLKeyboard::stringFromKey(KEY key) res = std::string(buffer); } - LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; - if (trans != NULL) + if (translate) { - res = trans(res.c_str()); + LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; + if (trans != NULL) + { + res = trans(res.c_str()); + } } return res; } +//static +std::string LLKeyboard::stringFromAccelerator(MASK accel_mask) +{ + std::string res; + + LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; + + if (trans == NULL) + { + LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL; + return res; + } + // Append any masks +#ifdef LL_DARWIN + // Standard Mac names for modifier keys in menu equivalents + // We could use the symbol characters, but they only exist in certain fonts. + if (accel_mask & MASK_CONTROL) + { + if (accel_mask & MASK_MAC_CONTROL) + { + res.append(trans("accel-mac-control")); + } + else + { + res.append(trans("accel-mac-command")); // Symbol would be "\xE2\x8C\x98" + } + } + if (accel_mask & MASK_ALT) + res.append(trans("accel-mac-option")); // Symbol would be "\xE2\x8C\xA5" + if (accel_mask & MASK_SHIFT) + res.append(trans("accel-mac-shift")); // Symbol would be "\xE2\x8C\xA7" +#else + if (accel_mask & MASK_CONTROL) + res.append(trans("accel-win-control")); + if (accel_mask & MASK_ALT) + res.append(trans("accel-win-alt")); + if (accel_mask & MASK_SHIFT) + res.append(trans("accel-win-shift")); +#endif + return res; +} //static std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key ) { @@ -359,41 +403,7 @@ std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key ) return res; } - LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; - - if( trans == NULL ) - { - LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL; - return res; - } - - // Append any masks -#ifdef LL_DARWIN - // Standard Mac names for modifier keys in menu equivalents - // We could use the symbol characters, but they only exist in certain fonts. - if( accel_mask & MASK_CONTROL ) - { - if ( accel_mask & MASK_MAC_CONTROL ) - { - res.append( trans("accel-mac-control") ); - } - else - { - res.append( trans("accel-mac-command") ); // Symbol would be "\xE2\x8C\x98" - } - } - if( accel_mask & MASK_ALT ) - res.append( trans("accel-mac-option") ); // Symbol would be "\xE2\x8C\xA5" - if( accel_mask & MASK_SHIFT ) - res.append( trans("accel-mac-shift") ); // Symbol would be "\xE2\x8C\xA7" -#else - if( accel_mask & MASK_CONTROL ) - res.append( trans("accel-win-control") ); - if( accel_mask & MASK_ALT ) - res.append( trans("accel-win-alt") ); - if( accel_mask & MASK_SHIFT ) - res.append( trans("accel-win-shift") ); -#endif + res.append(stringFromAccelerator(accel_mask)); std::string key_string = LLKeyboard::stringFromKey(key); if ((accel_mask & MASK_NORMALKEYS) && (key_string[0] == '-' || key_string[0] == '=' || key_string[0] == '+')) diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index 6f2dc87317a0ed62768475182883efd347b0c625..36bd8bcbed54784c4721f793f8e05dc19aeb2313 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -38,10 +38,10 @@ enum EKeystate { KEYSTATE_DOWN, KEYSTATE_LEVEL, - KEYSTATE_UP + KEYSTATE_UP }; -typedef boost::function<void(EKeystate keystate)> LLKeyFunc; +typedef boost::function<bool(EKeystate keystate)> LLKeyFunc; typedef std::string (LLKeyStringTranslatorFunc)(const char *label); enum EKeyboardInsertMode @@ -50,15 +50,6 @@ enum EKeyboardInsertMode LL_KIM_OVERWRITE }; -class LLKeyBinding -{ -public: - KEY mKey; - MASK mMask; -// const char *mName; // unused - LLKeyFunc mFunction; -}; - class LLWindowCallbacks; class LLKeyboard @@ -103,7 +94,8 @@ class LLKeyboard static BOOL maskFromString(const std::string& str, MASK *mask); // False on failure static BOOL keyFromString(const std::string& str, KEY *key); // False on failure - static std::string stringFromKey(KEY key); + static std::string stringFromKey(KEY key, bool translate = true); + static std::string stringFromAccelerator( MASK accel_mask ); // separated for convinience, returns with "+": "Shift+" or "Shift+Alt+"... static std::string stringFromAccelerator( MASK accel_mask, KEY key ); void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; } diff --git a/indra/llwindow/llmousehandler.cpp b/indra/llwindow/llmousehandler.cpp index bea66e763c21cee23b736f471aa679b935f6643c..e41ebd42f352ea11dc0b7022c1715ffc4112b86d 100644 --- a/indra/llwindow/llmousehandler.cpp +++ b/indra/llwindow/llmousehandler.cpp @@ -27,7 +27,7 @@ #include "llmousehandler.h" //virtual -BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down) +BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL handled = FALSE; if (down) @@ -38,6 +38,10 @@ BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType cli case CLICK_RIGHT: handled = handleRightMouseDown(x, y, mask); break; case CLICK_MIDDLE: handled = handleMiddleMouseDown(x, y, mask); break; case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; + case CLICK_BUTTON4: + case CLICK_BUTTON5: + LL_INFOS() << "Handle mouse button " << clicktype + 1 << " down." << LL_ENDL; + break; default: LL_WARNS() << "Unhandled enum." << LL_ENDL; } @@ -50,6 +54,10 @@ BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType cli case CLICK_RIGHT: handled = handleRightMouseUp(x, y, mask); break; case CLICK_MIDDLE: handled = handleMiddleMouseUp(x, y, mask); break; case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; + case CLICK_BUTTON4: + case CLICK_BUTTON5: + LL_INFOS() << "Handle mouse button " << clicktype + 1 << " up." << LL_ENDL; + break; default: LL_WARNS() << "Unhandled enum." << LL_ENDL; } diff --git a/indra/llwindow/llmousehandler.h b/indra/llwindow/llmousehandler.h index d825a3424c0bb2524b718ad87a75fa3fc2bccf16..d221dd117c89ff9c4183bc6193f7b69b19d0892d 100644 --- a/indra/llwindow/llmousehandler.h +++ b/indra/llwindow/llmousehandler.h @@ -29,6 +29,7 @@ #include "linden_common.h" #include "llrect.h" +#include "indra_constants.h" // Mostly-abstract interface. // Intended for use via multiple inheritance. @@ -46,14 +47,7 @@ class LLMouseHandler SHOW_ALWAYS, } EShowToolTip; - typedef enum { - CLICK_LEFT, - CLICK_MIDDLE, - CLICK_RIGHT, - CLICK_DOUBLELEFT - } EClickType; - - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) = 0; @@ -64,6 +58,7 @@ class LLMouseHandler virtual BOOL handleHover(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) = 0; + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks) = 0; virtual BOOL handleToolTip(S32 x, S32 y, MASK mask) = 0; virtual const std::string& getName() const = 0; diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 1990499459d966dcea3bb2c2760354469a1f06e7..5b9dce02c4bae01ff49dd2f0e13034d51f31264e 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -444,7 +444,7 @@ attributedStringInfo getSegments(NSAttributedString *str) NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; mMousePos[0] = mPoint.x; mMousePos[1] = mPoint.y; - callMiddleMouseDown(mMousePos, [theEvent modifierFlags]); + callOtherMouseDown(mMousePos, [theEvent modifierFlags], [theEvent buttonNumber]); } - (void) otherMouseUp:(NSEvent *)theEvent @@ -452,7 +452,7 @@ attributedStringInfo getSegments(NSAttributedString *str) NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; mMousePos[0] = mPoint.x; mMousePos[1] = mPoint.y; - callMiddleMouseUp(mMousePos, [theEvent modifierFlags]); + callOtherMouseUp(mMousePos, [theEvent modifierFlags], [theEvent buttonNumber]); } - (void) rightMouseDragged:(NSEvent *)theEvent @@ -467,7 +467,7 @@ attributedStringInfo getSegments(NSAttributedString *str) - (void) scrollWheel:(NSEvent *)theEvent { - callScrollMoved(-[theEvent deltaY]); + callScrollMoved(-[theEvent deltaX], -[theEvent deltaY]); } - (void) mouseExited:(NSEvent *)theEvent @@ -816,7 +816,7 @@ attributedStringInfo getSegments(NSAttributedString *str) [super setMarkedText:aString selectedRange:selectedRange replacementRange:replacementRange]; if ([aString length] == 0) // this means Input Widow becomes empty { - [_window orderOut:_window]; // Close this to avoid empty Input Window + [self.window orderOut:self.window]; // Close this to avoid empty Input Window } } @@ -840,7 +840,7 @@ attributedStringInfo getSegments(NSAttributedString *str) (mKeyPressed >= 0xF700 && mKeyPressed <= 0xF8FF)) { // this is case a) of above comment - [_window orderOut:_window]; // to avoid empty Input Window + [self.window orderOut:self.window]; // to avoid empty Input Window } } diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 94c725fc7ebb74fc67d1c9b8d6cbbddb14f3b50d..be61e1e16c62fd4db5b04e67bb92a612fe170f3b 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -98,6 +98,16 @@ BOOL LLWindowCallbacks::handleMiddleMouseUp(LLWindow *window, const LLCoordGL po return FALSE; } +BOOL LLWindowCallbacks::handleOtherMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) +{ + return FALSE; +} + +BOOL LLWindowCallbacks::handleOtherMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) +{ + return FALSE; +} + BOOL LLWindowCallbacks::handleActivate(LLWindow *window, BOOL activated) { return FALSE; @@ -120,6 +130,10 @@ void LLWindowCallbacks::handleScrollWheel(LLWindow *window, S32 clicks) { } +void LLWindowCallbacks::handleScrollHWheel(LLWindow *window, S32 clicks) +{ +} + void LLWindowCallbacks::handleResize(LLWindow *window, const S32 width, const S32 height) { } diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 4d753024fec52ff3ab07e48b2317f8bfdfa23f7c..3b186481388cc8d290a5a5a2788665b77a7a5807 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -49,11 +49,14 @@ class LLWindowCallbacks virtual BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); virtual BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); virtual BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + virtual BOOL handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); + virtual BOOL handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); virtual BOOL handleActivate(LLWindow *window, BOOL activated); virtual BOOL handleActivateApp(LLWindow *window, BOOL activating); virtual void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); virtual void handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask); virtual void handleScrollWheel(LLWindow *window, S32 clicks); + virtual void handleScrollHWheel(LLWindow *window, S32 clicks); virtual void handleResize(LLWindow *window, S32 width, S32 height); virtual void handleFocus(LLWindow *window); virtual void handleFocusLost(LLWindow *window); diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index 99af16110289c47d38327994d0a095fc91b0e80f..44fd4127ce5a06b0e1694828b1eb9fe0b00c7f92 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -142,7 +142,7 @@ void callDoubleClick(float *pos, unsigned int mask); void callResize(unsigned int width, unsigned int height); void callMouseMoved(float *pos, unsigned int mask); void callMouseDragged(float *pos, unsigned int mask); -void callScrollMoved(float delta); +void callScrollMoved(float deltaX, float deltaY); void callMouseExit(); void callWindowFocus(); void callWindowUnfocus(); @@ -150,8 +150,8 @@ void callWindowHide(); void callWindowUnhide(); void callWindowDidChangeScreen(); void callDeltaUpdate(float *delta, unsigned int mask); -void callMiddleMouseDown(float *pos, unsigned int mask); -void callMiddleMouseUp(float *pos, unsigned int mask); +void callOtherMouseDown(float *pos, unsigned int mask, int button); +void callOtherMouseUp(float *pos, unsigned int mask, int button); void callFocus(); void callFocusLost(); void callModifier(unsigned int mask); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 3554f90be8c558f600888849b26c2f616cfa1321..2604a23c85107a5aaffa11373938ec4c547e4275 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -356,9 +356,13 @@ void callMouseDragged(float *pos, MASK mask) gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); } -void callScrollMoved(float delta) +void callScrollMoved(float deltaX, float deltaY) { - gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, delta); + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleScrollHWheel(gWindowImplementation, deltaX); + gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, deltaY); + } } void callMouseExit() @@ -417,7 +421,7 @@ void callDeltaUpdate(float *delta, MASK mask) gWindowImplementation->updateMouseDeltas(delta); } -void callMiddleMouseDown(float *pos, MASK mask) +void callOtherMouseDown(float *pos, MASK mask, int button) { LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); @@ -426,10 +430,18 @@ void callMiddleMouseDown(float *pos, MASK mask) gWindowImplementation->getMouseDeltas(deltas); outCoords.mX += deltas[0]; outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMiddleMouseDown(gWindowImplementation, outCoords, mask); + + if (button == 2) + { + gWindowImplementation->getCallbacks()->handleMiddleMouseDown(gWindowImplementation, outCoords, mask); + } + else + { + gWindowImplementation->getCallbacks()->handleOtherMouseDown(gWindowImplementation, outCoords, mask, button + 1); + } } -void callMiddleMouseUp(float *pos, MASK mask) +void callOtherMouseUp(float *pos, MASK mask, int button) { LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); @@ -437,8 +449,15 @@ void callMiddleMouseUp(float *pos, MASK mask) float deltas[2]; gWindowImplementation->getMouseDeltas(deltas); outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMiddleMouseUp(gWindowImplementation, outCoords, mask); + outCoords.mY += deltas[1]; + if (button == 2) + { + gWindowImplementation->getCallbacks()->handleMiddleMouseUp(gWindowImplementation, outCoords, mask); + } + else + { + gWindowImplementation->getCallbacks()->handleOtherMouseUp(gWindowImplementation, outCoords, mask, button + 1); + } } void callModifier(MASK mask) diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index e05f5075067a406c941094a337fb8805a12b3d86..0b3936f8a5c12b805955824c31aa183d17513a14 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -741,17 +741,27 @@ void LLWindowWin32::restore() SetFocus(mWindowHandle); } +// See SL-12170 +// According to callstack "c0000005 Access violation" happened inside __try block, +// deep in DestroyWindow and crashed viewer, which shouldn't be possible. +// I tried manually causing this exception and it was caught without issues, so +// I'm turning off optimizations for this part to be sure code executes as intended +// (it is a straw, but I have no idea why else __try can get overruled) +#pragma optimize("", off) bool destroy_window_handler(HWND &hWnd) { + bool res; __try { - return DestroyWindow(hWnd); + res = DestroyWindow(hWnd); } __except (EXCEPTION_EXECUTE_HANDLER) { - return false; + res = false; } + return res; } +#pragma optimize("", on) // close() destroys all OS-specific code associated with a window. // Usually called from LLWindowManager::destroyWindow() @@ -2539,6 +2549,72 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } } break; + case WM_XBUTTONDOWN: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN"); + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + S32 button = GET_XBUTTON_WPARAM(w_param); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + // Because we move the cursor position in tllviewerhe app, we need to query + // to find out where the cursor at the time the event is handled. + // If we don't do this, many clicks could get buffered up, and if the + // first click changes the cursor position, all subsequent clicks + // will occur at the wrong location. JC + if (window_imp->mMousePositionModified) + { + LLCoordWindow cursor_coord_window; + window_imp->getCursorPosition(&cursor_coord_window); + gl_coord = cursor_coord_window.convert(); + } + else + { + gl_coord = window_coord.convert(); + } + MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); + // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 + if (window_imp->mCallbacks->handleOtherMouseDown(window_imp, gl_coord, mask, button + 3)) + { + return 0; + } + } + break; + + case WM_XBUTTONUP: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP"); + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + S32 button = GET_XBUTTON_WPARAM(w_param); + // Because we move the cursor position in the llviewer app, we need to query + // to find out where the cursor at the time the event is handled. + // If we don't do this, many clicks could get buffered up, and if the + // first click changes the cursor position, all subsequent clicks + // will occur at the wrong location. JC + if (window_imp->mMousePositionModified) + { + LLCoordWindow cursor_coord_window; + window_imp->getCursorPosition(&cursor_coord_window); + gl_coord = cursor_coord_window.convert(); + } + else + { + gl_coord = window_coord.convert(); + } + MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); + // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 + if (window_imp->mCallbacks->handleOtherMouseUp(window_imp, gl_coord, mask, button + 3)) + { + return 0; + } + } + break; case WM_MOUSEWHEEL: { @@ -2596,6 +2672,42 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ return 0; } */ + case WM_MOUSEHWHEEL: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEHWHEEL"); + static short h_delta = 0; + + RECT client_rect; + + // eat scroll events that occur outside our window, since we use mouse position to direct scroll + // instead of keyboard focus + // NOTE: mouse_coord is in *window* coordinates for scroll events + POINT mouse_coord = {(S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)}; + + if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) + && GetClientRect(window_imp->mWindowHandle, &client_rect)) + { + // we have a valid mouse point and client rect + if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x + || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) + { + // mouse is outside of client rect, so don't do anything + return 0; + } + } + + S16 incoming_h_delta = HIWORD(w_param); + h_delta += incoming_h_delta; + + // If the user rapidly spins the wheel, we can get messages with + // large deltas, like 480 or so. Thus we need to scroll more quickly. + if (h_delta <= -WHEEL_DELTA || WHEEL_DELTA <= h_delta) + { + window_imp->mCallbacks->handleScrollHWheel(window_imp, h_delta / WHEEL_DELTA); + h_delta = 0; + } + return 0; + } // Handle mouse movement within the window case WM_MOUSEMOVE: { diff --git a/indra/llxml/CMakeLists.txt b/indra/llxml/CMakeLists.txt index 17400a203e8485bb46b62f4011c60e1fe93fad36..013a422d35b07863647a3d6309cc94db869e571d 100644 --- a/indra/llxml/CMakeLists.txt +++ b/indra/llxml/CMakeLists.txt @@ -28,7 +28,6 @@ set(llxml_HEADER_FILES CMakeLists.txt llcontrol.h - llcontrolgroupreader.h llxmlnode.h llxmlparser.h llxmltree.h diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index de0d366492fcf475d60695955d8976e975fdd54a..9312bbc91ac71603b7f0cc82f6221251b496fd94 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -34,8 +34,6 @@ #include "llrefcount.h" #include "llinstancetracker.h" -#include "llcontrolgroupreader.h" - #include <vector> // *NOTE: boost::visit_each<> generates warning 4675 on .net 2003 diff --git a/indra/llxml/llcontrolgroupreader.h b/indra/llxml/llcontrolgroupreader.h deleted file mode 100644 index 6a27a65499ba226715f610c960127fb993129a1d..0000000000000000000000000000000000000000 --- a/indra/llxml/llcontrolgroupreader.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file llcontrolgroupreader.h - * @brief Interface providing readonly access to LLControlGroup (intended for unit testing) - * - * $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$ - */ - -#ifndef LL_LLCONTROLGROUPREADER_H -#define LL_LLCONTROLGROUPREADER_H - -#include "stdtypes.h" -#include <string> - -#include "v3math.h" -#include "v3dmath.h" -#include "v3color.h" -#include "v4color.h" -#include "llrect.h" - -class LLControlGroupReader -{ -public: - LLControlGroupReader() {} - virtual ~LLControlGroupReader() {} - - virtual std::string getString(const std::string& name) { return ""; } - virtual LLWString getWString(const std::string& name) { return LLWString(); } - virtual std::string getText(const std::string& name) { return ""; } - virtual LLVector3 getVector3(const std::string& name) { return LLVector3(); } - virtual LLVector3d getVector3d(const std::string& name) { return LLVector3d(); } - virtual LLRect getRect(const std::string& name) { return LLRect(); } - virtual BOOL getBOOL(const std::string& name) { return FALSE; } - virtual S32 getS32(const std::string& name) { return 0; } - virtual F32 getF32(const std::string& name) {return 0.0f; } - virtual U32 getU32(const std::string& name) {return 0; } - virtual LLSD getLLSD(const std::string& name) { return LLSD(); } - - virtual LLColor4 getColor(const std::string& name) { return LLColor4(); } - virtual LLColor4 getColor4(const std::string& name) { return LLColor4(); } - virtual LLColor3 getColor3(const std::string& name) { return LLColor3(); } - - virtual void setBOOL(const std::string& name, BOOL val) {} - virtual void setS32(const std::string& name, S32 val) {} - virtual void setF32(const std::string& name, F32 val) {} - virtual void setU32(const std::string& name, U32 val) {} - virtual void setString(const std::string& name, const std::string& val) {} - virtual void setVector3(const std::string& name, const LLVector3 &val) {} - virtual void setVector3d(const std::string& name, const LLVector3d &val) {} - virtual void setRect(const std::string& name, const LLRect &val) {} - virtual void setColor4(const std::string& name, const LLColor4 &val) {} - virtual void setLLSD(const std::string& name, const LLSD& val) {} -}; - -#endif /* LL_LLCONTROLGROUPREADER_H */ - - - - - - - diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index eead92fd8e8f6e555d3e123fe5b97e300f2506b6..cff21b13c476d4ae6e625e18e1e3d5ce8bb920ce 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -241,6 +241,7 @@ void MediaPluginCEF::onRequestExitCallback() LLPluginMessage message("base", "goodbye"); sendMessage(message); + // Will trigger delete on next staticReceiveMessage() mDeleteMe = true; } @@ -437,9 +438,13 @@ void MediaPluginCEF::receiveMessage(const char* message_string) } else if (message_name == "cleanup") { - mVolumeCatcher.setVolume(0); + mVolumeCatcher.setVolume(0); // Hack: masks CEF exit issues mCEFLib->requestExit(); } + else if (message_name == "force_exit") + { + mDeleteMe = true; + } else if (message_name == "shm_added") { SharedSegmentInfo info; @@ -655,12 +660,18 @@ void MediaPluginCEF::receiveMessage(const char* message_string) } else if (message_name == "scroll_event") { - S32 x = message_in.getValueS32("x"); - S32 y = message_in.getValueS32("y"); + // Mouse coordinates for cef to be able to scroll 'containers' + //S32 x = message_in.getValueS32("x"); + //S32 y = message_in.getValueS32("y"); + // Wheel's clicks + S32 delta_x = message_in.getValueS32("clicks_x"); + S32 delta_y = message_in.getValueS32("clicks_y"); const int scaling_factor = 40; - y *= -scaling_factor; + delta_x *= -scaling_factor; + delta_y *= -scaling_factor; - mCEFLib->mouseWheel(x, y); + // mCEFLib->mouseWheel(x, y, delta_x, delta_y); + mCEFLib->mouseWheel(delta_x, delta_y); } else if (message_name == "text_event") { diff --git a/indra/media_plugins/example/media_plugin_example.cpp b/indra/media_plugins/example/media_plugin_example.cpp index c296a0413de5daaea3c4e3a4b0629a131a838270..650685fb945ac4cc7954d13dbeea56e82dcd08a9 100644 --- a/indra/media_plugins/example/media_plugin_example.cpp +++ b/indra/media_plugins/example/media_plugin_example.cpp @@ -128,6 +128,10 @@ void mediaPluginExample::receiveMessage(const char* message_string) mDeleteMe = true; } + else if (message_name == "force_exit") + { + mDeleteMe = true; + } else if (message_name == "shm_added") { SharedSegmentInfo info; diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp index 80702a10797229208690e1b2a557284d28aa2fb7..f7d35b33c281becebf0053bbb8a550b2ea1f4f07 100644 --- a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp +++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp @@ -495,6 +495,10 @@ void MediaPluginLibVLC::receiveMessage(const char* message_string) { resetVLC(); } + else if (message_name == "force_exit") + { + mDeleteMe = true; + } else if (message_name == "shm_added") { SharedSegmentInfo info; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 694e89ab99bfcfaa67222e341e74ff3f1186c0ed..5a872f2aac9932edd085231250cbebcf359b22e9 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -246,6 +246,7 @@ set(viewer_SOURCE_FILES llfloaterexperiences.cpp llfloaterflickr.cpp llfloaterfonttest.cpp + llfloaterforgetuser.cpp llfloatergesture.cpp llfloatergodtools.cpp llfloatergotoline.cpp @@ -375,6 +376,7 @@ set(viewer_SOURCE_FILES llinventoryobserver.cpp llinventorypanel.cpp lljoystickbutton.cpp + llkeyconflict.cpp lllandmarkactions.cpp lllandmarklist.cpp lllistbrowser.cpp @@ -548,6 +550,7 @@ set(viewer_SOURCE_FILES llsecapi.cpp llsechandler_basic.cpp llselectmgr.cpp + llsetkeybinddialog.cpp llshareavatarhandler.cpp llsidepanelappearance.cpp llsidepanelinventory.cpp @@ -651,7 +654,7 @@ set(viewer_SOURCE_FILES llviewerjointattachment.cpp llviewerjointmesh.cpp llviewerjoystick.cpp - llviewerkeyboard.cpp + llviewerinput.cpp llviewerlayer.cpp llviewermedia.cpp llviewermedia_streamingaudio.cpp @@ -663,6 +666,7 @@ set(viewer_SOURCE_FILES llviewerobject.cpp llviewerobjectlist.cpp llvieweroctree.cpp + llviewerparcelaskplay.cpp llviewerparcelmedia.cpp llviewerparcelmediaautoplay.cpp llviewerparcelmgr.cpp @@ -871,6 +875,7 @@ set(viewer_HEADER_FILES llfloaterexperiences.h llfloaterflickr.h llfloaterfonttest.h + llfloaterforgetuser.h llfloatergesture.h llfloatergodtools.h llfloatergotoline.h @@ -1001,6 +1006,7 @@ set(viewer_HEADER_FILES llinventoryobserver.h llinventorypanel.h lljoystickbutton.h + llkeyconflict.h lllandmarkactions.h lllandmarklist.h lllightconstants.h @@ -1165,6 +1171,7 @@ set(viewer_HEADER_FILES llsecapi.h llsechandler_basic.h llselectmgr.h + llsetkeybinddialog.h llsidepanelappearance.h llsidepanelinventory.h llsidepanelinventorysubpanel.h @@ -1270,7 +1277,7 @@ set(viewer_HEADER_FILES llviewerjointattachment.h llviewerjointmesh.h llviewerjoystick.h - llviewerkeyboard.h + llviewerinput.h llviewerlayer.h llviewermedia.h llviewermediafocus.h @@ -1282,6 +1289,7 @@ set(viewer_HEADER_FILES llviewerobject.h llviewerobjectlist.h llvieweroctree.h + llviewerparcelaskplay.h llviewerparcelmedia.h llviewerparcelmediaautoplay.h llviewerparcelmgr.h @@ -1656,7 +1664,7 @@ set(viewer_APPSETTINGS_FILES app_settings/grass.xml app_settings/high_graphics.xml app_settings/ignorable_dialogs.xml - app_settings/keys.xml + app_settings/key_bindings.xml app_settings/keywords_lsl_default.xml app_settings/logcontrol.xml app_settings/low_graphics.xml diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index cab0c523b2300fd335e77843f59c1259bfea8e98..dae397a3b6c74ed90134f34afa4bcaf0bc75813b 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -150,16 +150,6 @@ is_running_function="Floater.IsOpen" is_running_parameters="moveview" /> - <command name="outbox" - available_in_toybox="false" - icon="Command_Outbox_Icon" - label_ref="Command_Outbox_Label" - tooltip_ref="Command_Outbox_Tooltip" - execute_function="Floater.ToggleOrBringToFront" - execute_parameters="outbox" - is_running_function="Floater.IsOpen" - is_running_parameters="outbox" - /> <command name="people" available_in_toybox="true" icon="Command_People_Icon" diff --git a/indra/newview/app_settings/keys.xml b/indra/newview/app_settings/key_bindings.xml similarity index 64% rename from indra/newview/app_settings/keys.xml rename to indra/newview/app_settings/key_bindings.xml index a8037fec05a663e610807aaafb8ea214754d7e3f..dd7429364472c4be3e7e27697844b91cae61010c 100644 --- a/indra/newview/app_settings/keys.xml +++ b/indra/newview/app_settings/key_bindings.xml @@ -28,34 +28,12 @@ <binding key="PAD_ENTER" mask="NONE" command="start_chat"/> <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/> - <binding key="A" mask="SHIFT" command="slide_left"/> - <binding key="D" mask="SHIFT" command="slide_right"/> - <binding key="W" mask="SHIFT" command="push_forward"/> - <binding key="S" mask="SHIFT" command="push_backward"/> - <binding key="E" mask="SHIFT" command="jump"/> - <binding key="C" mask="SHIFT" command="push_down"/> - <binding key="F" mask="SHIFT" command="toggle_fly"/> - <binding key="SPACE" mask="NONE" command="stop_moving"/> <binding key="ENTER" mask="NONE" command="start_chat"/> <binding key="DIVIDE" mask="NONE" command="start_gesture"/> - <binding key="LEFT" mask="SHIFT" command="slide_left"/> - <binding key="RIGHT" mask="SHIFT" command="slide_right"/> - <binding key="UP" mask="SHIFT" command="push_forward"/> - <binding key="DOWN" mask="SHIFT" command="push_backward"/> - <binding key="PGUP" mask="SHIFT" command="jump"/> - <binding key="PGDN" mask="SHIFT" command="push_down"/> - - <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/> - <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/> - <binding key="PAD_UP" mask="SHIFT" command="push_forward"/> - <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/> - <binding key="PAD_PGUP" mask="SHIFT" command="jump"/> - <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/> - <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/> - <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/> - <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/> + <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/> + <binding key="" mask="NONE" mouse="LMB" command="walk_to"/> </first_person> <third_person> <binding key="A" mask="NONE" command="turn_left"/> @@ -64,15 +42,10 @@ <binding key="D" mask="SHIFT" command="slide_right"/> <binding key="W" mask="NONE" command="push_forward"/> <binding key="S" mask="NONE" command="push_backward"/> - <binding key="W" mask="SHIFT" command="push_forward"/> - <binding key="S" mask="SHIFT" command="push_backward"/> <binding key="E" mask="NONE" command="jump"/> <binding key="C" mask="NONE" command="push_down"/> - <binding key="E" mask="SHIFT" command="jump"/> - <binding key="C" mask="SHIFT" command="push_down"/> <binding key="F" mask="NONE" command="toggle_fly"/> - <binding key="F" mask="SHIFT" command="toggle_fly"/> <binding key="SPACE" mask="NONE" command="stop_moving"/> <binding key="ENTER" mask="NONE" command="start_chat"/> @@ -84,13 +57,8 @@ <binding key="RIGHT" mask="SHIFT" command="slide_right"/> <binding key="UP" mask="NONE" command="push_forward"/> <binding key="DOWN" mask="NONE" command="push_backward"/> - <binding key="UP" mask="SHIFT" command="push_forward"/> - <binding key="DOWN" mask="SHIFT" command="push_backward"/> <binding key="PGUP" mask="NONE" command="jump"/> <binding key="PGDN" mask="NONE" command="push_down"/> - <binding key="PGUP" mask="SHIFT" command="jump"/> - <binding key="PGDN" mask="SHIFT" command="push_down"/> - <binding key="HOME" mask="SHIFT" command="toggle_fly"/> <binding key="HOME" mask="NONE" command="toggle_fly"/> <binding key="PAD_LEFT" mask="NONE" command="turn_left"/> @@ -99,20 +67,12 @@ <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/> <binding key="PAD_UP" mask="NONE" command="push_forward"/> <binding key="PAD_DOWN" mask="NONE" command="push_backward"/> - <binding key="PAD_UP" mask="SHIFT" command="push_forward"/> - <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/> <binding key="PAD_PGUP" mask="NONE" command="jump"/> <binding key="PAD_PGDN" mask="NONE" command="push_down"/> - <binding key="PAD_PGUP" mask="SHIFT" command="jump"/> - <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/> <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/> - <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/> <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/> - <binding key="PAD_CENTER" mask="SHIFT" command="stop_moving"/> <binding key="PAD_ENTER" mask="NONE" command="start_chat"/> - <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/> <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/> - <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/> <!--Camera controls in third person on Alt--> <binding key="LEFT" mask="ALT" command="spin_around_cw"/> @@ -139,28 +99,14 @@ <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/> <!--mimic alt zoom behavior with keyboard only--> - <binding key="A" mask="CTL_ALT" command="spin_around_cw"/> - <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/> <binding key="W" mask="CTL_ALT" command="spin_over"/> <binding key="S" mask="CTL_ALT" command="spin_under"/> - <binding key="E" mask="CTL_ALT" command="spin_over"/> - <binding key="C" mask="CTL_ALT" command="spin_under"/> - <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/> - <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/> <binding key="UP" mask="CTL_ALT" command="spin_over"/> <binding key="DOWN" mask="CTL_ALT" command="spin_under"/> - <binding key="PGUP" mask="CTL_ALT" command="spin_over"/> - <binding key="PGDN" mask="CTL_ALT" command="spin_under"/> - <binding key="PAD_LEFT" mask="CTL_ALT" command="spin_around_cw"/> - <binding key="PAD_RIGHT" mask="CTL_ALT" command="spin_around_ccw"/> <binding key="PAD_UP" mask="CTL_ALT" command="spin_over"/> <binding key="PAD_DOWN" mask="CTL_ALT" command="spin_under"/> - <binding key="PAD_PGUP" mask="CTL_ALT" command="spin_over"/> - <binding key="PAD_PGDN" mask="CTL_ALT" command="spin_under"/> - <binding key="PAD_ENTER" mask="CTL_ALT" command="start_chat"/> - <binding key="PAD_DIVIDE" mask="CTL_ALT" command="start_gesture"/> <!--Therefore pan on Alt-Shift--> <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/> @@ -179,63 +125,10 @@ <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/> <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/> <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/> - </third_person> - <!-- Basic editing camera control --> - <edit> - <binding key="A" mask="NONE" command="spin_around_cw"/> - <binding key="D" mask="NONE" command="spin_around_ccw"/> - <binding key="W" mask="NONE" command="move_forward"/> - <binding key="S" mask="NONE" command="move_backward"/> - <binding key="E" mask="NONE" command="spin_over"/> - <binding key="C" mask="NONE" command="spin_under"/> - <binding key="ENTER" mask="NONE" command="start_chat"/> - <binding key="DIVIDE" mask="NONE" command="start_gesture"/> - <binding key="PAD_ENTER" mask="NONE" command="start_chat"/> - <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/> - - <binding key="LEFT" mask="NONE" command="spin_around_cw"/> - <binding key="RIGHT" mask="NONE" command="spin_around_ccw"/> - <binding key="UP" mask="NONE" command="move_forward"/> - <binding key="DOWN" mask="NONE" command="move_backward"/> - <binding key="PGUP" mask="NONE" command="spin_over"/> - <binding key="PGDN" mask="NONE" command="spin_under"/> - - <binding key="A" mask="SHIFT" command="pan_left"/> - <binding key="D" mask="SHIFT" command="pan_right"/> - <binding key="W" mask="SHIFT" command="pan_up"/> - <binding key="S" mask="SHIFT" command="pan_down"/> - - <binding key="LEFT" mask="SHIFT" command="pan_left"/> - <binding key="RIGHT" mask="SHIFT" command="pan_right"/> - <binding key="UP" mask="SHIFT" command="pan_up"/> - <binding key="DOWN" mask="SHIFT" command="pan_down"/> - - <!--Walking works with ALT held down.--> - <binding key="A" mask="ALT" command="slide_left"/> - <binding key="D" mask="ALT" command="slide_right"/> - <binding key="W" mask="ALT" command="push_forward"/> - <binding key="S" mask="ALT" command="push_backward"/> - <binding key="E" mask="ALT" command="jump"/> - <binding key="C" mask="ALT" command="push_down"/> - - <binding key="LEFT" mask="ALT" command="slide_left"/> - <binding key="RIGHT" mask="ALT" command="slide_right"/> - <binding key="UP" mask="ALT" command="push_forward"/> - <binding key="DOWN" mask="ALT" command="push_backward"/> - <binding key="PGUP" mask="ALT" command="jump"/> - <binding key="PGDN" mask="ALT" command="push_down"/> - <binding key="HOME" mask="ALT" command="toggle_fly"/> - - <binding key="PAD_LEFT" mask="ALT" command="slide_left"/> - <binding key="PAD_RIGHT" mask="ALT" command="slide_right"/> - <binding key="PAD_UP" mask="ALT" command="push_forward"/> - <binding key="PAD_DOWN" mask="ALT" command="push_backward"/> - <binding key="PAD_PGUP" mask="ALT" command="jump"/> - <binding key="PAD_PGDN" mask="ALT" command="push_down"/> - <binding key="PAD_ENTER" mask="ALT" command="start_chat"/> - <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/> - </edit> + <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/> + <binding key="" mask="NONE" mouse="LMB" command="walk_to"/> + </third_person> <sitting> <binding key="A" mask="ALT" command="spin_around_cw"/> <binding key="D" mask="ALT" command="spin_around_ccw"/> @@ -251,15 +144,11 @@ <binding key="PGUP" mask="ALT" command="spin_over"/> <binding key="PGDN" mask="ALT" command="spin_under"/> - <binding key="A" mask="CTL_ALT" command="spin_around_cw"/> - <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/> <binding key="W" mask="CTL_ALT" command="spin_over"/> <binding key="S" mask="CTL_ALT" command="spin_under"/> <binding key="E" mask="CTL_ALT" command="spin_over"/> <binding key="C" mask="CTL_ALT" command="spin_under"/> - <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/> - <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/> <binding key="UP" mask="CTL_ALT" command="spin_over"/> <binding key="DOWN" mask="CTL_ALT" command="spin_under"/> <binding key="PGUP" mask="CTL_ALT" command="spin_over"/> @@ -294,23 +183,23 @@ <binding key="A" mask="SHIFT" command="slide_left"/> <binding key="D" mask="SHIFT" command="slide_right"/> <binding key="W" mask="SHIFT" command="move_forward_sitting"/> - <binding key="S" mask="SHIFT" command="move_backward_sitting"/> - <binding key="E" mask="SHIFT" command="spin_over_sitting"/> - <binding key="C" mask="SHIFT" command="spin_under_sitting"/> + <binding key="S" mask="SHIFT" command="move_backward_sitting"/> + <binding key="E" mask="SHIFT" command="spin_over_sitting"/> + <binding key="C" mask="SHIFT" command="spin_under_sitting"/> <binding key="LEFT" mask="SHIFT" command="slide_left"/> <binding key="RIGHT" mask="SHIFT" command="slide_right"/> <binding key="UP" mask="SHIFT" command="move_forward_sitting"/> - <binding key="DOWN" mask="SHIFT" command="move_backward_sitting"/> - <binding key="PGUP" mask="SHIFT" command="spin_over_sitting"/> - <binding key="PGDN" mask="SHIFT" command="spin_under_sitting"/> + <binding key="DOWN" mask="SHIFT" command="move_backward_sitting"/> + <binding key="PGUP" mask="SHIFT" command="spin_over_sitting"/> + <binding key="PGDN" mask="SHIFT" command="spin_under_sitting"/> <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/> <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/> <binding key="PAD_UP" mask="SHIFT" command="move_forward_sitting"/> - <binding key="PAD_DOWN" mask="SHIFT" command="move_backward_sitting"/> - <binding key="PAD_PGUP" mask="SHIFT" command="spin_over_sitting"/> - <binding key="PAD_PGDN" mask="SHIFT" command="spin_under_sitting"/> + <binding key="PAD_DOWN" mask="SHIFT" command="move_backward_sitting"/> + <binding key="PAD_PGUP" mask="SHIFT" command="spin_over_sitting"/> + <binding key="PAD_PGDN" mask="SHIFT" command="spin_under_sitting"/> <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/> <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/> @@ -334,6 +223,9 @@ <binding key="ENTER" mask="NONE" command="start_chat"/> <binding key="DIVIDE" mask="NONE" command="start_gesture"/> + + <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/> + <binding key="" mask="NONE" mouse="LMB" command="walk_to"/> </sitting> <edit_avatar> <!--Avatar editing camera controls--> @@ -359,5 +251,7 @@ <binding key="PAD_PGDN" mask="NONE" command="edit_avatar_spin_under"/> <binding key="PAD_ENTER" mask="NONE" command="start_chat"/> <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/> + + <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/> </edit_avatar> -</keys> \ No newline at end of file +</keys> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 49601ae98f6fc992923710d30b31a0ad6934fa17..bbac65ef61bbde7ee153106ae7f1858339574524 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3494,7 +3494,7 @@ <key>DoubleClickAutoPilot</key> <map> <key>Comment</key> - <string>Enable double-click auto pilot</string> + <string>(Obsolete)Enable double-click auto pilot</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -3505,13 +3505,13 @@ <key>DoubleClickTeleport</key> <map> <key>Comment</key> - <string>Enable double-click to teleport where allowed</string> + <string>Enable double-click to teleport where allowed (afects minimap and people panel)</string> <key>Persist</key> <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>0</integer> + <integer>1</integer> </map> <key>DoubleClickShowWorldMap</key> <map> @@ -4913,7 +4913,7 @@ <key>InventoryOutboxDisplayBoth</key> <map> <key>Comment</key> - <string>Show the legacy Merchant Outbox UI as well as the Marketplace Listings UI</string> + <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> @@ -5304,7 +5304,7 @@ <key>Type</key> <string>String</string> <key>Value</key> - <string>https://secondlife-status.statuspage.io/history.atom</string> + <string>https://status.secondlifegrid.net/history.atom</string> </map> <key>GridStatusUpdateDelay</key> <map> @@ -7494,11 +7494,11 @@ <key>ParcelMediaAutoPlayEnable</key> <map> <key>Comment</key> - <string>Auto play parcel media when available</string> + <string>Auto play parcel media when available. 0 - Do not autoplay; 1- Autoplay; 2 - Ask</string> <key>Persist</key> <integer>1</integer> <key>Type</key> - <string>Boolean</string> + <string>S32</string> <key>Value</key> <integer>1</integer> </map> @@ -8184,7 +8184,7 @@ <key>PushToTalkButton</key> <map> <key>Comment</key> - <string>Which button or keyboard key is used for push-to-talk</string> + <string>(Obsolete)Which button or keyboard key is used for push-to-talk</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -8434,6 +8434,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>RememberUser</key> + <map> + <key>Comment</key> + <string>Keep user name for next login</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>RememberPassword</key> <map> <key>Comment</key> @@ -9276,7 +9287,7 @@ <key>RenderShadowResolutionScale</key> <map> <key>Comment</key> - <string>Scale of shadow map resolution vs. screen resolution</string> + <string>Scale of shadow map resolution vs. screen resolution (only positivie values are allowed)</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -11219,6 +11230,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>BasicUITooltips</key> + <map> + <key>Comment</key> + <string>Show tooltips for various 2D UI elements like buttons or checkboxes, won't supress tooltips like drag'n'drop, inworld, links or media</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>ShowHoverTips</key> <map> <key>Comment</key> @@ -13133,6 +13155,17 @@ <key>Value</key> <real>3</real> </map> + <key>HUDScaleFactor</key> + <map> + <key>Comment</key> + <string>Scale of HUD attachments</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.0</real> + </map> <key>UIScaleFactor</key> <map> <key>Comment</key> @@ -15331,7 +15364,7 @@ <key>ClickToWalk</key> <map> <key>Comment</key> - <string>Click in world to walk to location</string> + <string>(obsolete)Click in world to walk to location</string> <key>Persist</key> <integer>1</integer> <key>Type</key> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 31b8b9051887cc0c1984709a23ae772d1fbeefae..0e43af91df11d17aba42279f16186f63974e7bfc 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -829,6 +829,17 @@ bool LLAgent::enableFlying() return !sitting; } +// static +bool LLAgent::isSitting() +{ + BOOL sitting = FALSE; + if (isAgentAvatarValid()) + { + sitting = gAgentAvatarp->isSitting(); + } + return sitting; +} + void LLAgent::standUp() { setControlFlags(AGENT_CONTROL_STAND_UP); @@ -2022,6 +2033,14 @@ U8 LLAgent::getRenderState() //----------------------------------------------------------------------------- void LLAgent::endAnimationUpdateUI() { + if (LLApp::isExiting() + || !gViewerWindow + || !gMenuBarView + || !gToolBarView + || !gStatusBar) + { + return; + } if (gAgentCamera.getCameraMode() == gAgentCamera.getLastCameraMode()) { // We're already done endAnimationUpdateUI for this transition. diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 5ba1083d8efc345b2b7f48b138972da50758a7df..a5d37ef4969f502fa2ce087b269a8e9934a78bf7 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -343,6 +343,7 @@ class LLAgent : public LLOldEvents::LLObservable static void toggleFlying(); static bool enableFlying(); BOOL canFly(); // Does this parcel allow you to fly? + static bool isSitting(); //-------------------------------------------------------------------- // Voice diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 0b4b848014e400fe14b882f4caa619f64c3e280f..c55c12e67058f916ce8fbc7ba4501e686390f227 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -282,6 +282,11 @@ LLAgentCamera::~LLAgentCamera() //----------------------------------------------------------------------------- void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera) { + if (gDisconnected) + { + return; + } + if (gAgent.getAutoPilot()) { gAgent.stopAutoPilot(TRUE); @@ -807,6 +812,12 @@ void LLAgentCamera::setCameraZoomFraction(F32 fraction) startCameraAnimation(); } +F32 LLAgentCamera::getAgentHUDTargetZoom() +{ + static LLCachedControl<F32> hud_scale_factor(gSavedSettings, "HUDScaleFactor"); + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + return (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD) ? hud_scale_factor*gAgentCamera.mHUDTargetZoom : hud_scale_factor; +} //----------------------------------------------------------------------------- // cameraOrbitAround() diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index d087de1e2ff5d55227ea3bb700faf579b818f139..a4bc8434b0c982892ff99b8710e6a4d721ed9d4f 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -266,6 +266,7 @@ class LLAgentCamera F32 getCameraZoomFraction(); // Get camera zoom as fraction of minimum and maximum zoom void setCameraZoomFraction(F32 fraction); // Set camera zoom as fraction of minimum and maximum zoom F32 calcCameraFOVZoomFactor(); + F32 getAgentHUDTargetZoom(); //-------------------------------------------------------------------- // Pan diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 7325ec598a17ed1977a8b49b8694c7056569da69..fb864f18c1568731d4846baaa92fbf03bd1d8b78 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1713,6 +1713,24 @@ void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_ LLInventoryModel::item_array_t* items; LLSD contents = LLSD::emptyArray(); gInventory.getDirectDescendentsOf(src_id, cats, items); + if (!cats || !items) + { + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + LLViewerInventoryCategory* category = gInventory.getCategory(src_id); + if (category) + { + LL_WARNS() << "Category '" << category->getName() << "' descendents corrupted, linking content failed." << LL_ENDL; + } + else + { + LL_WARNS() << "Category could not be retrieved, linking content failed." << LL_ENDL; + } + llassert(cats != NULL && items != NULL); + + return; + } + LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); iter != items->end(); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ff897ef9624739691e3550988c885aff3368d4ec..3e33815b206b3d891835b66400ae3255aa99d1a5 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -61,13 +61,16 @@ #include "llallocator.h" #include "llcalc.h" #include "llconversationlog.h" +#if LL_WINDOWS #include "lldxhardware.h" +#endif #include "lltexturestats.h" #include "lltrace.h" #include "lltracethreadrecorder.h" #include "llviewerwindow.h" #include "llviewerdisplay.h" #include "llviewermedia.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewermediafocus.h" #include "llviewermessage.h" @@ -145,7 +148,7 @@ #include "llapr.h" #include <boost/lexical_cast.hpp> -#include "llviewerkeyboard.h" +#include "llviewerinput.h" #include "lllfsthread.h" #include "llworkerthread.h" #include "lltexturecache.h" @@ -994,20 +997,15 @@ bool LLAppViewer::init() gGLManager.getGLInfo(gDebugInfo); gGLManager.printGLInfoString(); - // Load Default bindings - std::string key_bindings_file = gDirUtilp->findFile("keys.xml", - gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), - gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - - - if (!gViewerKeyboard.loadBindingsXML(key_bindings_file)) + // Load User's bindings + std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml"); + if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) { - std::string key_bindings_file = gDirUtilp->findFile("keys.ini", - gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), - gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - if (!gViewerKeyboard.loadBindings(key_bindings_file)) + // Failed to load custom bindings, try default ones + key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml"); + if (!gViewerInput.loadBindingsXML(key_bindings_file)) { - LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL; + LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; } } @@ -1128,7 +1126,7 @@ bool LLAppViewer::init() try { initializeSecHandler(); } - catch (LLProtectedDataException ex) + catch (LLProtectedDataException&) { LLNotificationsUtil::add("CorruptedProtectedDataStore"); } @@ -1341,7 +1339,7 @@ bool LLAppViewer::frame() { LOG_UNHANDLED_EXCEPTION(""); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { LLMemory::logMemoryInfo(TRUE); LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking"); @@ -1438,6 +1436,7 @@ bool LLAppViewer::doFrame() { joystick->scanJoystick(); gKeyboard->scanKeyboard(); + gViewerInput.scanMouse(); } // Update state based on messages, user input, object idle. @@ -1708,6 +1707,11 @@ bool LLAppViewer::cleanup() disconnectViewer(); LL_INFOS() << "Viewer disconnected" << LL_ENDL; + + if (gKeyboard) + { + gKeyboard->resetKeys(); + } display_cleanup(); @@ -1923,6 +1927,11 @@ bool LLAppViewer::cleanup() { gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); LL_INFOS() << "Saved settings" << LL_ENDL; + + if (LLViewerParcelAskPlay::instanceExists()) + { + LLViewerParcelAskPlay::getInstance()->saveSettings(); + } } std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings")); @@ -2125,6 +2134,9 @@ void watchdog_llerrs_callback(const std::string &error_string) { gLLErrorActivated = true; + gDebugInfo["FatalMessage"] = error_string; + LLAppViewer::instance()->writeDebugInfo(); + #ifdef LL_WINDOWS RaiseException(0,0,0,0); #else @@ -3962,7 +3974,10 @@ static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_q void LLAppViewer::userQuit() { - if (gDisconnected || gViewerWindow->getProgressView()->getVisible()) + if (gDisconnected + || !gViewerWindow + || !gViewerWindow->getProgressView() + || gViewerWindow->getProgressView()->getVisible()) { requestQuit(); } @@ -4492,6 +4507,7 @@ void LLAppViewer::saveFinalSnapshot() gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, + gSavedSettings.getBOOL("RenderHUDInSnapshot"), TRUE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG); diff --git a/indra/newview/llaudiosourcevo.cpp b/indra/newview/llaudiosourcevo.cpp index b37aba6c1520b10d6493967d7cf6a93ddd0be5d6..4b6c855bde3427eb74aabd2e4432fb23629bd385 100644 --- a/indra/newview/llaudiosourcevo.cpp +++ b/indra/newview/llaudiosourcevo.cpp @@ -29,8 +29,10 @@ #include "llaudiosourcevo.h" +#include "llagent.h" #include "llagentcamera.h" #include "llmutelist.h" +#include "llviewercontrol.h" #include "llviewerparcelmgr.h" LLAudioSourceVO::LLAudioSourceVO(const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, LLViewerObject *objectp) @@ -54,6 +56,79 @@ void LLAudioSourceVO::setGain(const F32 gain) mGain = llclamp(gain, 0.f, 1.f); } +void LLAudioSourceVO::checkCutOffRadius() +{ + if (mSourceMuted // already muted by something, will be recalculated on update() + || !mObjectp) + { + return; + } + + F32 cutoff = mObjectp->getSoundCutOffRadius(); + if (cutoff < 0.1f) + { + // consider cutoff below 0.1m as off (to avoid near zero comparison) + return; + } + + LLVector3d pos_global = getPosGlobal(); + if (!isInCutOffRadius(pos_global, cutoff)) + { + mSourceMuted = true; + } +} + +LLVector3d LLAudioSourceVO::getPosGlobal() const +{ + if (mObjectp->isAttachment()) + { + LLViewerObject* parent = mObjectp; + while (parent && !parent->isAvatar()) + { + parent = (LLViewerObject*)parent->getParent(); + } + if (parent) + { + return parent->getPositionGlobal(); + } + } + else + { + return mObjectp->getPositionGlobal(); + } + return LLVector3d(); +} + +bool LLAudioSourceVO::isInCutOffRadius(const LLVector3d pos_global, const F32 cutoff) const +{ + static LLCachedControl<S32> ear_mode(gSavedSettings, "VoiceEarLocation", 0); + + LLVector3d pos_ear; + + switch (ear_mode()) + { + case 0: // camera + pos_ear = gAgentCamera.getCameraPositionGlobal(); + break; + + case 1: // avatar + case 2: + // voice support 'mixed' in '2' case with agent's position and camera's rotations + // but it is not defined in settings and uses camera as default + pos_ear = gAgent.getPositionGlobal(); + break; + + default: + pos_ear = gAgentCamera.getCameraPositionGlobal(); + break; + } + LLVector3d to_vec = pos_global - pos_ear; + + F32 dist = (F32)to_vec.magVec(); + + return dist < cutoff; +} + void LLAudioSourceVO::updateMute() { if (!mObjectp || mObjectp->isDead()) @@ -63,26 +138,11 @@ void LLAudioSourceVO::updateMute() } bool mute = false; - LLVector3d pos_global; - - if (mObjectp->isAttachment()) - { - LLViewerObject* parent = mObjectp; - while (parent && !parent->isAvatar()) - { - parent = (LLViewerObject*)parent->getParent(); - } - if (parent) - { - pos_global = parent->getPositionGlobal(); - } - } - else - { - pos_global = mObjectp->getPositionGlobal(); - } + LLVector3d pos_global = getPosGlobal(); - if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) + F32 cutoff = mObjectp->getSoundCutOffRadius(); + if ((cutoff > 0.1f && !isInCutOffRadius(pos_global, cutoff)) // consider cutoff below 0.1m as off + || !LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) { mute = true; } diff --git a/indra/newview/llaudiosourcevo.h b/indra/newview/llaudiosourcevo.h index f1d8ef4528507b6be516b70cc54ac5edbc551b96..672a07f7d350f0b852236d08554b59119dd250e6 100644 --- a/indra/newview/llaudiosourcevo.h +++ b/indra/newview/llaudiosourcevo.h @@ -41,7 +41,11 @@ class LLAudioSourceVO : public LLAudioSource /*virtual*/ void update(); /*virtual*/ void setGain(const F32 gain); + void checkCutOffRadius(); + private: + LLVector3d getPosGlobal() const; + bool isInCutOffRadius(LLVector3d pos_global, const F32 cutoff) const; void updateMute(); private: diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 1099d4bc09e1481233d1c41b3a64656ff5a5979f..722523830baa8f1d096e16d6804315fe73c24b89 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -1085,7 +1085,8 @@ LLView* LLChatHistory::getSeparator() LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args) { LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename); - header->setup(chat, style_params, args); + if (header) + header->setup(chat, style_params, args); return header; } @@ -1298,6 +1299,12 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL view = getSeparator(); p.top_pad = mTopSeparatorPad; p.bottom_pad = mBottomSeparatorPad; + if (!view) + { + // Might be wiser to make this LL_ERRS, getSeparator() should work in case of correct instalation. + LL_WARNS() << "Failed to create separator from " << mMessageSeparatorFilename << ": can't append to history" << LL_ENDL; + return; + } } else { @@ -1306,7 +1313,12 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL p.top_pad = 0; else p.top_pad = mTopHeaderPad; - p.bottom_pad = mBottomHeaderPad; + p.bottom_pad = mBottomHeaderPad; + if (!view) + { + LL_WARNS() << "Failed to create header from " << mMessageHeaderFilename << ": can't append to history" << LL_ENDL; + return; + } } p.view = view; diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index 92eeebd705446ad4a8f4bebbbf59fb5197d05aad..f0682dc1ba77a72fd346e60f68bb01d8bf559de3 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -171,7 +171,10 @@ void LLControlAvatar::matchVolumeTransform() if (attached_av) { LLViewerJointAttachment *attach = attached_av->getTargetAttachmentPoint(mRootVolp); - setPositionAgent(mRootVolp->getRenderPosition()); + if (getRegion() && !isDead()) + { + setPositionAgent(mRootVolp->getRenderPosition()); + } attach->updateWorldPRSParent(); LLVector3 joint_pos = attach->getWorldPosition(); LLQuaternion joint_rot = attach->getWorldRotation(); @@ -227,7 +230,10 @@ void LLControlAvatar::matchVolumeTransform() #endif setRotation(bind_rot*obj_rot); mRoot->setWorldRotation(bind_rot*obj_rot); - setPositionAgent(vol_pos); + if (getRegion() && !isDead()) + { + setPositionAgent(vol_pos); + } mRoot->setPosition(vol_pos + mPositionConstraintFixup); F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale"); diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index f7c61efce07dc93bf1c1fe76ccb62d5190467a10..5539fa75dd4afb23b125514d78b2a310279b1db2 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -490,7 +490,7 @@ bool LLConversationLog::saveToFile(const std::string& filename) (S32)conv_it->getConversationType(), (S32)0, (S32)conv_it->hasOfflineMessages(), - conv_it->getConversationName().c_str(), + LLURI::escape(conv_it->getConversationName()).c_str(), participant_id.c_str(), conversation_id.c_str(), LLURI::escape(conv_it->getHistoryFileName()).c_str()); @@ -545,7 +545,7 @@ bool LLConversationLog::loadFromFile(const std::string& filename) params.time(LLUnits::Seconds::fromValue(time)) .conversation_type((SessionType)stype) .has_offline_ims(has_offline_ims) - .conversation_name(conv_name_buffer) + .conversation_name(LLURI::unescape(conv_name_buffer)) .participant_id(LLUUID(part_id_buffer)) .session_id(LLUUID(conv_id_buffer)) .history_filename(LLURI::unescape(history_file_name)); diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 0075b621008ac03909d77dd3b30315b8090ecafd..60a5204547d158b630a7723042de398a92b1a773 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -175,7 +175,7 @@ BOOL LLConversationViewSession::postBuild() LLAvatarIconCtrl* icon = mItemPanel->getChild<LLAvatarIconCtrl>("avatar_icon"); icon->setVisible(true); icon->setValue(session->mOtherParticipantID); - mSpeakingIndicator->setSpeakerId(gAgentID, session->mSessionID, true); + mSpeakingIndicator->setSpeakerId(session->mOtherParticipantID, session->mSessionID, true); mHasArrow = false; } break; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 1587903a1517e6b9fd9fb60f167bda344fb0574e..85ee33edb19234b99736aba2c106c52b4cd3a71e 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -456,7 +456,7 @@ void LLFace::setTextureIndex(U8 index) } else { - if (mDrawInfo && !mDrawInfo->mTextureList.empty()) + if (mDrawInfo && mDrawInfo->mTextureList.size() <= 1) { LL_ERRS() << "Face with no texture index references indexed texture draw info." << LL_ENDL; } diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 5b4b7789b482f4c803266917d053e27bdc4b2ef1..347997a69a6ad9cef52cf76e2de55a567fe6b81f 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1493,18 +1493,24 @@ void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id) } // static -std::string LLFavoritesOrderStorage::getStoredFavoritesFilename() +std::string LLFavoritesOrderStorage::getStoredFavoritesFilename(const std::string &grid) { - std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); + std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); return (user_dir.empty() ? "" : gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites_" - + LLGridManager::getInstance()->getGrid() + + grid + ".xml") ); } +// static +std::string LLFavoritesOrderStorage::getStoredFavoritesFilename() +{ + return getStoredFavoritesFilename(LLGridManager::getInstance()->getGrid()); +} + // static void LLFavoritesOrderStorage::destroyClass() { @@ -1584,14 +1590,29 @@ void LLFavoritesOrderStorage::load() << (fav_llsd.isMap() ? "" : "un") << "successfully" << LL_ENDL; in_file.close(); - user_llsd = fav_llsd[gAgentUsername]; + if (fav_llsd.isMap() && fav_llsd.has(gAgentUsername)) + { + user_llsd = fav_llsd[gAgentUsername]; - S32 index = 0; - for (LLSD::array_iterator iter = user_llsd.beginArray(); + S32 index = 0; + bool needs_validation = gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); + for (LLSD::array_iterator iter = user_llsd.beginArray(); iter != user_llsd.endArray(); ++iter) - { - mSortIndexes.insert(std::make_pair(iter->get("id").asUUID(), index)); - index++; + { + // Validation + LLUUID fv_id = iter->get("id").asUUID(); + if (needs_validation + && (fv_id.isNull() + || iter->get("asset_id").asUUID().isNull() + || iter->get("name").asString().empty() + || iter->get("slurl").asString().empty())) + { + mRecreateFavoriteStorage = true; + } + + mSortIndexes.insert(std::make_pair(fv_id, index)); + index++; + } } } else @@ -1602,6 +1623,64 @@ void LLFavoritesOrderStorage::load() } } +// static +void LLFavoritesOrderStorage::removeFavoritesRecordOfUser(const std::string &user, const std::string &grid) +{ + std::string filename = getStoredFavoritesFilename(grid); + if (!filename.empty()) + { + LLSD fav_llsd; + llifstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, file); + file.close(); + + // Note : use the "John Doe" and not the "john.doe" version of the name. + // See saveFavoritesSLURLs() here above for the reason why. + if (fav_llsd.has(user)) + { + LLSD user_llsd = fav_llsd[user]; + + if ((user_llsd.beginArray() != user_llsd.endArray()) && user_llsd.beginArray()->has("id")) + { + for (LLSD::array_iterator iter = user_llsd.beginArray(); iter != user_llsd.endArray(); ++iter) + { + LLSD value; + value["id"] = iter->get("id").asUUID(); + iter->assign(value); + } + fav_llsd[user] = user_llsd; + llofstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(fav_llsd, file); + file.close(); + } + } + else + { + LL_INFOS("FavoritesBar") << "Removed favorites for " << user << LL_ENDL; + fav_llsd.erase(user); + } + } + + llofstream out_file; + out_file.open(filename.c_str()); + if (out_file.is_open()) + { + LLSDSerialize::toPrettyXML(fav_llsd, out_file); + LL_INFOS("FavoritesBar") << "saved favorites to '" << filename << "' " + << LL_ENDL; + out_file.close(); + } + } + } +} + +// static void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() { std::string filename = getStoredFavoritesFilename(); @@ -1777,6 +1856,8 @@ void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_it BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) { + pref_changed |= mRecreateFavoriteStorage; + mRecreateFavoriteStorage = false; LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); if (favorite_folder.isNull()) diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index cac32c7f2a6dfce51212e59a0e7e6cf08b28d753..571208aa31b201f1c42e73c8cbf63668daa7eec7 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -208,9 +208,15 @@ class LLFavoritesOrderStorage : public LLSingleton<LLFavoritesOrderStorage> * @see cleanup() */ static void destroyClass(); + static std::string getStoredFavoritesFilename(const std::string &grid); static std::string getStoredFavoritesFilename(); static std::string getSavedOrderFileName(); + // Remove record of specified user's favorites from file on disk. + static void removeFavoritesRecordOfUser(const std::string &user, const std::string &grid); + // Remove record of current user's favorites from file on disk. + static void removeFavoritesRecordOfUser(); + BOOL saveFavoritesRecord(bool pref_changed = false); void showFavoritesOnLoginChanged(BOOL show); @@ -232,9 +238,6 @@ class LLFavoritesOrderStorage : public LLSingleton<LLFavoritesOrderStorage> void load(); - // Remove record of current user's favorites from file on disk. - void removeFavoritesRecordOfUser(); - void onLandmarkLoaded(const LLUUID& asset_id, class LLLandmark* landmark); void storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl); @@ -245,6 +248,7 @@ class LLFavoritesOrderStorage : public LLSingleton<LLFavoritesOrderStorage> slurls_map_t mSLURLs; std::set<LLUUID> mMissingSLURLs; bool mIsDirty; + bool mRecreateFavoriteStorage; struct IsNotInFavorites { @@ -275,7 +279,9 @@ class LLFavoritesOrderStorage : public LLSingleton<LLFavoritesOrderStorage> inline LLFavoritesOrderStorage::LLFavoritesOrderStorage() : - mIsDirty(false), mUpdateRequired(false) + mIsDirty(false), + mUpdateRequired(false), + mRecreateFavoriteStorage(false) { load(); } #endif // LL_LLFAVORITESBARCTRL_H diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index 56619e818af2526f399da48e11796809130da5c5..957b2e1e8ef008d21980b77b1b09bebc653b5865 100644 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -182,8 +182,11 @@ void LLFloaterAuction::onClickSnapshot(void* data) BOOL success = gViewerWindow->rawSnapshot(raw, gViewerWindow->getWindowWidthScaled(), gViewerWindow->getWindowHeightScaled(), - TRUE, FALSE, - FALSE, FALSE); + TRUE, + FALSE, + FALSE, //UI + FALSE, //HUD + FALSE); gForceRenderLandFence = FALSE; if (success) diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 33099db1b946c0b10f8ace73c6b1cd4e26eb95a3..ab95bc06b889f1fcbdf7da58130dc6690561e77f 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -361,59 +361,8 @@ void LLFloaterAvatarPicker::populateFriend() void LLFloaterAvatarPicker::drawFrustum() { - if(mFrustumOrigin.get()) - { - LLView * frustumOrigin = mFrustumOrigin.get(); - LLRect origin_rect; - frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this); - // draw context cone connecting color picker with color swatch in parent floater - LLRect local_rect = getLocalRect(); - if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); - { - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); - gGL.vertex2i(origin_rect.mRight, origin_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mRight, origin_rect.mTop); - gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom); - - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom); - } - gGL.end(); - } - - if (gFocusMgr.childHasMouseCapture(getDragHandle())) - { - mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(mContextConeFadeTime)); - } - else - { - mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(mContextConeFadeTime)); - } - } + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha); } void LLFloaterAvatarPicker::draw() diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index ec2c9740afe9846836ce5632a7b0e5f2b8f01689..1a784223c2eb0084645ccef108fb203e3f09fcff 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -485,56 +485,8 @@ BOOL LLFloaterColorPicker::isColorChanged() // void LLFloaterColorPicker::draw() { - LLRect swatch_rect; - mSwatch->localRectToOtherView(mSwatch->getLocalRect(), &swatch_rect, this); - // draw context cone connecting color picker with color swatch in parent floater - LLRect local_rect = getLocalRect(); - if (hasFocus() && mSwatch->isInVisibleChain() && mContextConeOpacity > 0.001f) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); - { - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop); - gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom); - gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop); - gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom); - - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom); - gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom); - } - gGL.end(); - } - - if (gFocusMgr.childHasMouseCapture(getDragHandle())) - { - mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), - LLSmoothInterpolation::getInterpolant(mContextConeFadeTime)); - } - else - { - mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(mContextConeFadeTime)); - } + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, mSwatch, mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha); mPipetteBtn->setToggleState(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance()); mApplyImmediateCheck->setEnabled(mActive && mCanApplyImmediately); diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp index 55561fa1281c35bb39b9c2d93bfb874a979c1eb9..44725cab7023cfbe4eb027fb598b70d4b226cc55 100644 --- a/indra/newview/llfloaterconversationpreview.cpp +++ b/indra/newview/llfloaterconversationpreview.cpp @@ -50,6 +50,7 @@ LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_i mShowHistory(false), mMessages(NULL), mHistoryThreadsBusy(false), + mIsGroup(false), mOpened(false) { } @@ -75,6 +76,7 @@ BOOL LLFloaterConversationPreview::postBuild() { name = conv->getConversationName(); file = conv->getHistoryFileName(); + mIsGroup = (LLIMModel::LLIMSession::GROUP_SESSION == conv->getConversationType()); } else { @@ -82,6 +84,10 @@ BOOL LLFloaterConversationPreview::postBuild() file = "chat"; } mChatHistoryFileName = file; + if (mIsGroup) + { + mChatHistoryFileName += GROUP_CHAT_SUFFIX; + } LLStringUtil::format_map_t args; args["[NAME]"] = name; std::string title = getString("Title", args); @@ -145,6 +151,7 @@ void LLFloaterConversationPreview::onOpen(const LLSD& key) LLSD load_params; load_params["load_all_history"] = true; load_params["cut_off_todays_date"] = false; + load_params["is_group"] = mIsGroup; // The temporary message list with "Loading..." text // Will be deleted upon loading completion in setPages() method diff --git a/indra/newview/llfloaterconversationpreview.h b/indra/newview/llfloaterconversationpreview.h index a8dbbc9ffe0c112721f984dfcd1dd821afbe82e4..7ca4ee6945cceb3e6230cb7a0231f9f171146574 100644 --- a/indra/newview/llfloaterconversationpreview.h +++ b/indra/newview/llfloaterconversationpreview.h @@ -66,6 +66,7 @@ class LLFloaterConversationPreview : public LLFloater bool mShowHistory; bool mHistoryThreadsBusy; bool mOpened; + bool mIsGroup; }; #endif /* LLFLOATERCONVERSATIONPREVIEW_H_ */ diff --git a/indra/newview/llfloaterexperiencepicker.cpp b/indra/newview/llfloaterexperiencepicker.cpp index bb54c57baf1a23ed33ee0fc4591ea2d9f9bbf50d..c642da7b83b104554023dd2aa4e0eff54f393f12 100644 --- a/indra/newview/llfloaterexperiencepicker.cpp +++ b/indra/newview/llfloaterexperiencepicker.cpp @@ -74,59 +74,8 @@ LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t ca void LLFloaterExperiencePicker::drawFrustum() { - if(mFrustumOrigin.get()) - { - LLView * frustumOrigin = mFrustumOrigin.get(); - LLRect origin_rect; - frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this); - // draw context cone connecting color picker with color swatch in parent floater - LLRect local_rect = getLocalRect(); - if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); - { - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); - gGL.vertex2i(origin_rect.mRight, origin_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mRight, origin_rect.mTop); - gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom); - - gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); - gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); - gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom); - gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom); - } - gGL.end(); - } - - if (gFocusMgr.childHasMouseCapture(getDragHandle())) - { - mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime)); - } - else - { - mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime)); - } - } + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha); } void LLFloaterExperiencePicker::draw() diff --git a/indra/newview/llfloaterexperiences.cpp b/indra/newview/llfloaterexperiences.cpp index fdc1b473341f0be8e4bfb96996d7e768e9a18211..184e39402a47d229b4db97d300cddd3f8599fd4f 100644 --- a/indra/newview/llfloaterexperiences.cpp +++ b/indra/newview/llfloaterexperiences.cpp @@ -74,10 +74,6 @@ BOOL LLFloaterExperiences::postBuild() getChild<LLTabContainer>("xp_tabs")->addTabPanel(new LLPanelExperienceLog()); resizeToTabs(); - - LLEventPumps::instance().obtain("experience_permission").listen("LLFloaterExperiences", - boost::bind(&LLFloaterExperiences::updatePermissions, this, _1)); - return TRUE; } @@ -163,6 +159,10 @@ void LLFloaterExperiences::refreshContents() void LLFloaterExperiences::onOpen( const LLSD& key ) { + LLEventPumps::instance().obtain("experience_permission").stopListening("LLFloaterExperiences"); + LLEventPumps::instance().obtain("experience_permission").listen("LLFloaterExperiences", + boost::bind(&LLFloaterExperiences::updatePermissions, this, _1)); + LLViewerRegion* region = gAgent.getRegion(); if(region) { diff --git a/indra/newview/llfloaterforgetuser.cpp b/indra/newview/llfloaterforgetuser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5659cb2f793fb780cdb0290dc3a3c6676b302585 --- /dev/null +++ b/indra/newview/llfloaterforgetuser.cpp @@ -0,0 +1,154 @@ +/** + * @file llfloaterforgetuser.cpp + * @brief LLFloaterForgetUser class definition. + * + * $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$ + */ + + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterforgetuser.h" + +#include "llcheckboxctrl.h" +#include "llfavoritesbar.h" +#include "llpanellogin.h" // for helper function getUserName() and to repopulate list if nessesary +#include "llscrolllistctrl.h" +#include "llsecapi.h" +#include "llviewernetwork.h" + + +LLFloaterForgetUser::LLFloaterForgetUser(const LLSD &key) + : LLFloater("floater_forget_user"), + mLoginPanelDirty(false) +{ + +} + +LLFloaterForgetUser::~LLFloaterForgetUser() +{ + if (mLoginPanelDirty) + { + LLPanelLogin::resetFields(); + } +} + +BOOL LLFloaterForgetUser::postBuild() +{ + // Note, storage works per grid, watever is selected currently in login screen or logged in. + // Since login screen can change grid, store the value. + mGrid = LLGridManager::getInstance()->getGrid(); + + LLScrollListCtrl *scroll_list = getChild<LLScrollListCtrl>("user_list"); + if (gSecAPIHandler->hasCredentialMap("login_list", mGrid)) + { + LLSecAPIHandler::credential_map_t credencials; + gSecAPIHandler->loadCredentialMap("login_list", mGrid, credencials); + + LLSecAPIHandler::credential_map_t::iterator cr_iter = credencials.begin(); + LLSecAPIHandler::credential_map_t::iterator cr_end = credencials.end(); + while (cr_iter != cr_end) + { + if (cr_iter->second.notNull()) // basic safety + { + LLScrollListItem::Params item_params; + item_params.value(cr_iter->first); + item_params.columns.add() + .value(LLPanelLogin::getUserName(cr_iter->second)) + .column("user") + .font(LLFontGL::getFontSansSerifSmall()); + scroll_list->addRow(item_params, ADD_BOTTOM); + } + cr_iter++; + } + scroll_list->selectFirstItem(); + } + else + { + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(mGrid); + if (cred.notNull()) + { + LLScrollListItem::Params item_params; + item_params.value(cred->userID()); + item_params.columns.add() + .value(LLPanelLogin::getUserName(cred)) + .column("user") + .font(LLFontGL::getFontSansSerifSmall()); + scroll_list->addRow(item_params, ADD_BOTTOM); + scroll_list->selectFirstItem(); + } + } + + bool enable_button = scroll_list->getFirstSelectedIndex() != -1; + getChild<LLView>("delete_data")->setEnabled(enable_button); + LLButton *button = getChild<LLButton>("forget"); + button->setEnabled(enable_button); + button->setCommitCallback(boost::bind(&LLFloaterForgetUser::onForgetClicked, this)); + + return TRUE; +} + +void LLFloaterForgetUser::onForgetClicked() +{ + mLoginPanelDirty = true; + LLScrollListCtrl *scroll_list = getChild<LLScrollListCtrl>("user_list"); + std::string user_key = scroll_list->getSelectedValue(); + + // remove creds + gSecAPIHandler->removeFromCredentialMap("login_list", mGrid, user_key); + + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(mGrid); + if (cred.notNull() && cred->userID() == user_key) + { + gSecAPIHandler->deleteCredential(cred); + } + + // Clean data + LLCheckBoxCtrl *chk_box = getChild<LLCheckBoxCtrl>("delete_data"); + BOOL delete_data = chk_box->getValue(); + if (delete_data) + { + // key is edentical to one we use for name of user's folder + std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + user_key; + gDirUtilp->deleteDirAndContents(user_path); + + // Clean favorites, label is edentical to username + LLFavoritesOrderStorage::removeFavoritesRecordOfUser(scroll_list->getSelectedItemLabel(), mGrid); + + // Note: we do not clean user-related files from cache because there are id dependent (inventory) + // files and cache has separate cleaning mechanism either way. + // Also this only cleans user from current grid, not all of them. + } + + + // Update UI + scroll_list->deleteSelectedItems(); + scroll_list->selectFirstItem(); + if (scroll_list->getFirstSelectedIndex() == -1) + { + LLButton *button = getChild<LLButton>("forget"); + button->setEnabled(false); + chk_box->setEnabled(false); + } +} + + diff --git a/indra/newview/llfloaterforgetuser.h b/indra/newview/llfloaterforgetuser.h new file mode 100644 index 0000000000000000000000000000000000000000..119aece2d10f522ab68fa7a3ffe80736f40ff6b0 --- /dev/null +++ b/indra/newview/llfloaterforgetuser.h @@ -0,0 +1,46 @@ +/** + * @file llfloaterforgetuser.h + * @brief LLFloaterForgetUser class declaration. + * + * $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$ + */ + +#ifndef LL_LLFLOATERFORGETUSER_H +#define LL_LLFLOATERFORGETUSER_H + +#include "llfloater.h" + +class LLFloaterForgetUser : public LLFloater +{ +public: + LLFloaterForgetUser(const LLSD &key); + ~LLFloaterForgetUser(); + + BOOL postBuild(); + void onForgetClicked(); + +private: + bool mLoginPanelDirty; + std::string mGrid; +}; + +#endif diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index b840d37c4d99fe0af8612c5452365468e760d6bf..e778e8eb9e14b7e831149165c3b2a526ae25d9ac 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -41,6 +41,7 @@ #include "llkeyboard.h" #include "llmenugl.h" #include "llmultigesture.h" +#include "llnotificationsutil.h" #include "llpreviewgesture.h" #include "llscrolllistctrl.h" #include "lltrans.h" @@ -125,6 +126,7 @@ LLFloaterGesture::LLFloaterGesture(const LLSD& key) mCommitCallbackRegistrar.add("Gesture.Action.ShowPreview", boost::bind(&LLFloaterGesture::onClickEdit, this)); mCommitCallbackRegistrar.add("Gesture.Action.CopyPaste", boost::bind(&LLFloaterGesture::onCopyPasteAction, this, _2)); mCommitCallbackRegistrar.add("Gesture.Action.SaveToCOF", boost::bind(&LLFloaterGesture::addToCurrentOutFit, this)); + mCommitCallbackRegistrar.add("Gesture.Action.Rename", boost::bind(&LLFloaterGesture::onRenameSelected, this)); mEnableCallbackRegistrar.add("Gesture.EnableAction", boost::bind(&LLFloaterGesture::isActionEnabled, this, _2)); } @@ -430,6 +432,19 @@ bool LLFloaterGesture::isActionEnabled(const LLSD& command) { return mGestureList->getAllSelected().size() == 1; } + else if ("rename_gesture" == command_name) + { + if (mGestureList->getAllSelected().size() == 1) + { + LLViewerInventoryItem* item = gInventory.getItem(mGestureList->getCurrentID()); + + if (item && item->getPermissions().allowModifyBy(gAgentID)) + { + return true; + } + } + return false; + } return true; } @@ -514,6 +529,44 @@ void LLFloaterGesture::onActivateBtnClick() } } +void LLFloaterGesture::onRenameSelected() +{ + LLViewerInventoryItem* gesture = gInventory.getItem(mGestureList->getCurrentID()); + if (!gesture) + { + return; + } + + LLSD args; + args["NAME"] = gesture->getName(); + + LLSD payload; + payload["gesture_id"] = mGestureList->getCurrentID(); + + LLNotificationsUtil::add("RenameGesture", args, payload, boost::bind(onGestureRename, _1, _2)); + +} + +void LLFloaterGesture::onGestureRename(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return; // canceled + + std::string new_name = response["new_name"].asString(); + LLInventoryObject::correctInventoryName(new_name); + if (!new_name.empty()) + { + LLUUID item_id = notification["payload"]["gesture_id"].asUUID(); + LLViewerInventoryItem* gesture = gInventory.getItem(item_id); + if (gesture && (gesture->getName() != new_name)) + { + LLSD updates; + updates["name"] = new_name; + update_inventory_item(item_id, updates, NULL); + } + } +} + void LLFloaterGesture::onCopyPasteAction(const LLSD& command) { std::string command_name = command.asString(); diff --git a/indra/newview/llfloatergesture.h b/indra/newview/llfloatergesture.h index 8efb3e6461a901d1f865543d7a72b8681837d4c5..1d702c6704e17dfed42e634b7e3008c7d0da6e35 100644 --- a/indra/newview/llfloatergesture.h +++ b/indra/newview/llfloatergesture.h @@ -95,6 +95,9 @@ class LLFloaterGesture void onCommitList(); void onCopyPasteAction(const LLSD& command); void onDeleteSelected(); + void onRenameSelected(); + + static void onGestureRename(const LLSD& notification, const LLSD& response); LLUUID mSelectedID; LLUUID mGestureFolderID; diff --git a/indra/newview/llfloatergridstatus.cpp b/indra/newview/llfloatergridstatus.cpp index c47ff1c1d926197b4b16b4f9f9b08715da5630e8..faa7e9f3db25886e3eb703c040c60c8db301ada7 100644 --- a/indra/newview/llfloatergridstatus.cpp +++ b/indra/newview/llfloatergridstatus.cpp @@ -39,7 +39,7 @@ #include "llxmltree.h" std::map<std::string, std::string> LLFloaterGridStatus::sItemsMap; -const std::string DEFAULT_GRID_STATUS_URL = "http://secondlife-status.statuspage.io/"; +const std::string DEFAULT_GRID_STATUS_URL = "http://status.secondlifegrid.net/"; LLFloaterGridStatus::LLFloaterGridStatus(const Params& key) : LLFloaterWebContent(key), diff --git a/indra/newview/llfloatergroupinvite.cpp b/indra/newview/llfloatergroupinvite.cpp index 7fdba8734a6cac29dcd180aa99a21b73003bccdc..30c90ac184f3ef36f8149115ac1cdfa8d40ea06c 100644 --- a/indra/newview/llfloatergroupinvite.cpp +++ b/indra/newview/llfloatergroupinvite.cpp @@ -108,7 +108,7 @@ LLFloaterGroupInvite::~LLFloaterGroupInvite() } // static -void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, uuid_vec_t *agent_ids) +void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, uuid_vec_t *agent_ids, bool request_update) { const LLFloater::Params& floater_params = LLFloater::getDefaultParams(); S32 floater_header_size = floater_params.header_height; @@ -126,9 +126,12 @@ void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, uuid_vec_t *agen group_id, (LLFloaterGroupInvite*)NULL); - // refresh group information - gAgent.sendAgentDataUpdateRequest(); - LLGroupMgr::getInstance()->clearGroupData(group_id); + if (request_update) + { + // refresh group information + gAgent.sendAgentDataUpdateRequest(); + LLGroupMgr::getInstance()->clearGroupData(group_id); + } if (!fgi) diff --git a/indra/newview/llfloatergroupinvite.h b/indra/newview/llfloatergroupinvite.h index f6a3ca55509b6c2a7e6c2b3b50a9e7fb50c4f58d..657e5711f0fdebf9ac043fdf27fd9b110d0a9447 100644 --- a/indra/newview/llfloatergroupinvite.h +++ b/indra/newview/llfloatergroupinvite.h @@ -37,7 +37,7 @@ class LLFloaterGroupInvite public: virtual ~LLFloaterGroupInvite(); - static void showForGroup(const LLUUID &group_id, uuid_vec_t *agent_ids = NULL); + static void showForGroup(const LLUUID &group_id, uuid_vec_t *agent_ids = NULL, bool request_update = true); protected: LLFloaterGroupInvite(const LLUUID& group_id = LLUUID::null); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 3098c6d11831c941fd2d769dadd3cb55df5b462a..d8f4360142e5ac4ba8c8f96cf01376f90f76a9ac 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -2209,7 +2209,7 @@ void LLPanelLandOptions::refreshSearch() // effort to reduce search spam from small parcels. See also // the search crawler "grid-crawl.py" in secondlife.com/doc/app/search/ JC const S32 MIN_PARCEL_AREA_FOR_SEARCH = 128; - bool large_enough = parcel->getArea() > MIN_PARCEL_AREA_FOR_SEARCH; + bool large_enough = parcel->getArea() >= MIN_PARCEL_AREA_FOR_SEARCH; if (large_enough) { if (can_change) diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp index 10cce3bd22dcd5ff255bfe46405e7597916fc008..595d584799d2171765778d1505c99da818a7b174 100644 --- a/indra/newview/llfloaterlinkreplace.cpp +++ b/indra/newview/llfloaterlinkreplace.cpp @@ -32,6 +32,8 @@ #include "llagent.h" #include "llappearancemgr.h" #include "lllineeditor.h" +#include "llnotificationsutil.h" +#include "llnotifications.h" #include "lltextbox.h" #include "llviewercontrol.h" @@ -142,37 +144,72 @@ void LLFloaterLinkReplace::onStartClicked() LL_WARNS() << "Cannot replace. Source and target are identical." << LL_ENDL; return; } + + const LLUUID& source_item_id = gInventory.getLinkedItemID(mSourceUUID); + LLViewerInventoryItem *source_item = gInventory.getItem(source_item_id); + const LLUUID& target_item_id = gInventory.getLinkedItemID(mTargetUUID); + LLViewerInventoryItem *target_item = gInventory.getItem(target_item_id); - LLInventoryModel::cat_array_t cat_array; - LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - mRemainingInventoryItems, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); - LL_INFOS() << "Found " << mRemainingInventoryItems.size() << " inventory links that need to be replaced." << LL_ENDL; - if (mRemainingInventoryItems.size() > 0) + LLNotification::Params params("ConfirmReplaceLink"); + params.functor.function(boost::bind(&LLFloaterLinkReplace::onStartClickedResponse, this, _1, _2)); + if (source_item && source_item->isWearableType() && source_item->getWearableType() <= LLWearableType::WT_EYES) { - LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); - if (target_item) + if(target_item && target_item->isWearableType() && source_item->getWearableType() == target_item->getWearableType()) { - mRemainingItems = (U32)mRemainingInventoryItems.size(); - - LLStringUtil::format_map_t args; - args["NUM"] = llformat("%d", mRemainingItems); - mStatusText->setText(getString("ItemsRemaining", args)); - - mStartBtn->setEnabled(FALSE); - mRefreshBtn->setEnabled(FALSE); - - mEventTimer.start(); - tick(); + LLNotifications::instance().forceResponse(params, 0); } else { - mStatusText->setText(getString("TargetNotFound")); - LL_WARNS() << "Link replace target not found." << LL_ENDL; + LLSD args; + args["TYPE"] = LLWearableType::getTypeName(source_item->getWearableType()); + params.substitutions(args); + LLNotifications::instance().add(params); + } + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } +} + +void LLFloaterLinkReplace::onStartClickedResponse(const LLSD& notification, const LLSD& response) +{ + + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + + LLInventoryModel::cat_array_t cat_array; + LLLinkedItemIDMatches is_linked_item_match(mSourceUUID); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + mRemainingInventoryItems, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + LL_INFOS() << "Found " << mRemainingInventoryItems.size() << " inventory links that need to be replaced." << LL_ENDL; + + if (mRemainingInventoryItems.size() > 0) + { + LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); + if (target_item) + { + mRemainingItems = (U32)mRemainingInventoryItems.size(); + + LLStringUtil::format_map_t args; + args["NUM"] = llformat("%d", mRemainingItems); + mStatusText->setText(getString("ItemsRemaining", args)); + + mStartBtn->setEnabled(FALSE); + mRefreshBtn->setEnabled(FALSE); + + mEventTimer.start(); + tick(); + } + else + { + mStatusText->setText(getString("TargetNotFound")); + LL_WARNS() << "Link replace target not found." << LL_ENDL; + } } } } diff --git a/indra/newview/llfloaterlinkreplace.h b/indra/newview/llfloaterlinkreplace.h index dd5c3012061fd89313b8b42afdf23182ff1b692e..060773f93e769d3e001bd3ba5a7923299a0fcd90 100644 --- a/indra/newview/llfloaterlinkreplace.h +++ b/indra/newview/llfloaterlinkreplace.h @@ -94,6 +94,7 @@ class LLFloaterLinkReplace : public LLFloater, LLEventTimer private: void checkEnableStart(); void onStartClicked(); + void onStartClickedResponse(const LLSD& notification, const LLSD& response); void decreaseOpenItemCount(); void updateFoundLinks(); void processBatch(LLInventoryModel::item_array_t items); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index b6efc1590ea3ec51d40fa3908510850b65df024c..e12ad262f820e7e9e985e46bb8f76e637425d63d 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -433,7 +433,7 @@ void LLFloaterModelPreview::initModelPreview() mModelPreview = new LLModelPreview(512, 512, this ); mModelPreview->setPreviewTarget(16.f); mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5)); - mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, _1)); + mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::modelUpdated, this, _1)); } void LLFloaterModelPreview::onViewOptionChecked(LLUICtrl* ctrl) @@ -510,7 +510,8 @@ void LLFloaterModelPreview::onClickCalculateBtn() mModelPreview->getPreviewAvatar()->showAttachmentOverrides(); } - mUploadModelUrl.clear(); + mUploadModelUrl.clear(); + mModelPhysicsFee.clear(); gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, childGetValue("upload_textures").asBoolean(), @@ -3014,6 +3015,15 @@ void LLModelPreview::updateStatusMessages() { mFMP->childDisable("ok_btn"); } + + if (mModelNoErrors && mLodsWithParsingError.empty()) + { + mFMP->childEnable("calculate_btn"); + } + else + { + mFMP->childDisable("calculate_btn"); + } //add up physics triangles etc S32 phys_tris = 0; @@ -4430,6 +4440,12 @@ void LLFloaterModelPreview::toggleCalculateButton() toggleCalculateButton(true); } +void LLFloaterModelPreview::modelUpdated(bool calculate_visible) +{ + mModelPhysicsFee.clear(); + toggleCalculateButton(calculate_visible); +} + void LLFloaterModelPreview::toggleCalculateButton(bool visible) { mCalculateBtn->setVisible(visible); @@ -4455,7 +4471,10 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible) childSetTextArg("download_weight", "[ST]", tbd); childSetTextArg("server_weight", "[SIM]", tbd); childSetTextArg("physics_weight", "[PH]", tbd); - childSetTextArg("upload_fee", "[FEE]", tbd); + if (!mModelPhysicsFee.isMap() || mModelPhysicsFee.emptyMap()) + { + childSetTextArg("upload_fee", "[FEE]", tbd); + } childSetTextArg("price_breakdown", "[STREAMING]", tbd); childSetTextArg("price_breakdown", "[PHYSICS]", tbd); childSetTextArg("price_breakdown", "[INSTANCES]", tbd); @@ -4515,10 +4534,21 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived() mUploadBtn->setEnabled(isModelUploadAllowed()); } -void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) +void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result) { LL_WARNS() << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << LL_ENDL; doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, true)); + + if (result.has("upload_price")) + { + mModelPhysicsFee = result; + childSetTextArg("upload_fee", "[FEE]", llformat("%d", result["upload_price"].asInteger())); + childSetVisible("upload_fee", true); + } + else + { + mModelPhysicsFee.clear(); + } } /*virtual*/ diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index edc90d1695176aa3859ff656e84daef8b9d97c5b..1c66570650b64a977be0533f60dcf0f8f9d09d8f 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -125,7 +125,7 @@ class LLFloaterModelPreview : public LLFloaterModelUploadBase /*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url); void handleModelPhysicsFeeReceived(); - /*virtual*/ void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason); + /*virtual*/ void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result); /*virtual*/ void onModelUploadSuccess(); @@ -208,6 +208,8 @@ class LLFloaterModelPreview : public LLFloaterModelUploadBase void onLoDSourceCommit(S32 lod); + void modelUpdated(bool calculate_visible); + // Toggles between "Calculate weights & fee" and "Upload" buttons. void toggleCalculateButton(bool visible); diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h index 0d4c834122325d56ab1bc62457ca1fbfc0465ac5..721fce059e008288a06fa8c40c6c0af6298326f7 100644 --- a/indra/newview/llfloatermodeluploadbase.h +++ b/indra/newview/llfloatermodeluploadbase.h @@ -45,7 +45,7 @@ class LLFloaterModelUploadBase : public LLFloater, public LLUploadPermissionsObs virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; - virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0; + virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result) = 0; virtual void onModelUploadSuccess() {}; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index fe347a91a301e2f328c4f7cd22ef977840de035b..c9c563a054a5f024d392c6efd2fe5321aee2908b 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -71,8 +71,9 @@ #include "lltrans.h" #include "llviewercontrol.h" #include "llviewercamera.h" -#include "llviewerwindow.h" +#include "llviewereventrecorder.h" #include "llviewermessage.h" +#include "llviewerwindow.h" #include "llviewershadermgr.h" #include "llviewerthrottle.h" #include "llvoavatarself.h" @@ -124,7 +125,9 @@ char const* const VISIBILITY_DEFAULT = "default"; char const* const VISIBILITY_HIDDEN = "hidden"; //control value for middle mouse as talk2push button -const static std::string MIDDLE_MOUSE_CV = "MiddleMouse"; +const static std::string MIDDLE_MOUSE_CV = "MiddleMouse"; // for voice client and redability +const static std::string MOUSE_BUTTON_4_CV = "MouseButton4"; +const static std::string MOUSE_BUTTON_5_CV = "MouseButton5"; /// This must equal the maximum value set for the IndirectMaxComplexity slider in panel_preferences_graphics1.xml static const U32 INDIRECT_MAX_ARC_OFF = 101; // all the way to the right == disabled @@ -157,67 +160,6 @@ struct LabelTable : public LLInitParam::Block<LabelTable> {} }; -class LLVoiceSetKeyDialog : public LLModalDialog -{ -public: - LLVoiceSetKeyDialog(const LLSD& key); - ~LLVoiceSetKeyDialog(); - - /*virtual*/ BOOL postBuild(); - - void setParent(LLFloaterPreference* parent) { mParent = parent; } - - BOOL handleKeyHere(KEY key, MASK mask); - static void onCancel(void* user_data); - -private: - LLFloaterPreference* mParent; -}; - -LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(const LLSD& key) - : LLModalDialog(key), - mParent(NULL) -{ -} - -//virtual -BOOL LLVoiceSetKeyDialog::postBuild() -{ - childSetAction("Cancel", onCancel, this); - getChild<LLUICtrl>("Cancel")->setFocus(TRUE); - - gFocusMgr.setKeystrokesOnly(TRUE); - - return TRUE; -} - -LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog() -{ -} - -BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) -{ - BOOL result = TRUE; - - if (key == 'Q' && mask == MASK_CONTROL) - { - result = FALSE; - } - else if (mParent) - { - mParent->setKey(key); - } - closeFloater(); - return result; -} - -//static -void LLVoiceSetKeyDialog::onCancel(void* user_data) -{ - LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data; - self->closeFloater(); -} - // global functions @@ -297,37 +239,6 @@ void handleAppearanceCameraMovementChanged(const LLSD& newvalue) } } -/*bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option && floater ) - { - if ( floater ) - { - floater->setAllIgnored(); - // LLFirstUse::disableFirstUse(); - floater->buildPopupLists(); - } - } - return false; -} - -bool callback_reset_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if ( 0 == option && floater ) - { - if ( floater ) - { - floater->resetAllIgnored(); - //LLFirstUse::resetFirstUse(); - floater->buildPopupLists(); - } - } - return false; -} -*/ - void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator) { numerator = 0; @@ -352,8 +263,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mGotPersonalInfo(false), mOriginalIMViaEmail(false), mLanguageChanged(false), - mAvatarDataInitialized(false), - mClickActionDirty(false) + mAvatarDataInitialized(false) { LLConversationLog::instance().addObserver(this); @@ -362,7 +272,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) static bool registered_dialog = false; if (!registered_dialog) { - LLFloaterReg::add("voice_set_key", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLVoiceSetKeyDialog>); + LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLSetKeyBindDialog>); registered_dialog = true; } @@ -375,8 +285,6 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.ResetCache", boost::bind(&LLFloaterPreference::onClickResetCache, this)); mCommitCallbackRegistrar.add("Pref.ClickSkin", boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2)); mCommitCallbackRegistrar.add("Pref.SelectSkin", boost::bind(&LLFloaterPreference::onSelectSkin, this)); - mCommitCallbackRegistrar.add("Pref.VoiceSetKey", boost::bind(&LLFloaterPreference::onClickSetKey, this)); - mCommitCallbackRegistrar.add("Pref.VoiceSetMiddleMouse", boost::bind(&LLFloaterPreference::onClickSetMiddleMouse, this)); mCommitCallbackRegistrar.add("Pref.SetSounds", boost::bind(&LLFloaterPreference::onClickSetSounds, this)); mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this)); mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this)); @@ -397,13 +305,12 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this)); mCommitCallbackRegistrar.add("Pref.AutoReplace", boost::bind(&LLFloaterPreference::onClickAutoReplace, this)); mCommitCallbackRegistrar.add("Pref.PermsDefault", boost::bind(&LLFloaterPreference::onClickPermsDefault, this)); + mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this)); mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this)); sSkin = gSavedSettings.getString("SkinCurrent"); - mCommitCallbackRegistrar.add("Pref.ClickActionChange", boost::bind(&LLFloaterPreference::onClickActionChange, this)); - gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged, _2)); @@ -670,12 +577,6 @@ void LLFloaterPreference::apply() } saveAvatarProperties(); - - if (mClickActionDirty) - { - updateClickActionSettings(); - mClickActionDirty = false; - } } void LLFloaterPreference::cancel() @@ -708,12 +609,6 @@ void LLFloaterPreference::cancel() // reverts any changes to current skin gSavedSettings.setString("SkinCurrent", sSkin); - if (mClickActionDirty) - { - updateClickActionControls(); - mClickActionDirty = false; - } - LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance<LLFloaterPreferenceProxy>("prefs_proxy"); if (advanced_proxy_settings) { @@ -795,9 +690,6 @@ void LLFloaterPreference::onOpen(const LLSD& key) onChangeTextureFolder(); onChangeSoundFolder(); onChangeAnimationFolder(); - - // Load (double-)click to walk/teleport settings. - updateClickActionControls(); // Enabled/disabled popups, might have been changed by user actions // while preferences floater was closed. @@ -1219,7 +1111,7 @@ void LLFloaterPreference::buildPopupLists() LLNotificationFormPtr formp = templatep->mForm; LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType(); - if (ignore == LLNotificationForm::IGNORE_NO) + if (ignore <= LLNotificationForm::IGNORE_NO) continue; LLSD row; @@ -1244,12 +1136,12 @@ void LLFloaterPreference::buildPopupLists() if (it->second.asBoolean()) { row["columns"][1]["value"] = formp->getElement(it->first)["ignore"].asString(); + row["columns"][1]["font"] = "SANSSERIF_SMALL"; + row["columns"][1]["width"] = 360; break; } } } - row["columns"][1]["font"] = "SANSSERIF_SMALL"; - row["columns"][1]["width"] = 360; } item = disabled_popups.addElement(row); } @@ -1678,37 +1570,6 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data) refresh(); } -void LLFloaterPreference::onClickSetKey() -{ - LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance<LLVoiceSetKeyDialog>("voice_set_key", LLSD(), TRUE); - if (dialog) - { - dialog->setParent(this); - } -} - -void LLFloaterPreference::setKey(KEY key) -{ - getChild<LLUICtrl>("modifier_combo")->setValue(LLKeyboard::stringFromKey(key)); - // update the control right away since we no longer wait for apply - getChild<LLUICtrl>("modifier_combo")->onCommit(); -} - -void LLFloaterPreference::onClickSetMiddleMouse() -{ - LLUICtrl* p2t_line_editor = getChild<LLUICtrl>("modifier_combo"); - - // update the control right away since we no longer wait for apply - p2t_line_editor->setControlValue(MIDDLE_MOUSE_CV); - - //push2talk button "middle mouse" control value is in English, need to localize it for presentation - LLPanel* advanced_preferences = dynamic_cast<LLPanel*>(p2t_line_editor->getParent()); - if (advanced_preferences) - { - p2t_line_editor->setValue(advanced_preferences->getString("middle_mouse")); - } -} - void LLFloaterPreference::onClickSetSounds() { // Disable Enable gesture sounds checkbox if the master sound is disabled @@ -1716,18 +1577,6 @@ void LLFloaterPreference::onClickSetSounds() getChild<LLCheckBoxCtrl>("gesture_audio_play_btn")->setEnabled(!gSavedSettings.getBOOL("MuteSounds")); } -/* -void LLFloaterPreference::onClickSkipDialogs() -{ - LLNotificationsUtil::add("SkipShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_skip_dialogs, _1, _2, this)); -} - -void LLFloaterPreference::onClickResetDialogs() -{ - LLNotificationsUtil::add("ResetShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_reset_dialogs, _1, _2, this)); -} - */ - void LLFloaterPreference::onClickEnablePopup() { LLScrollListCtrl& disabled_popups = getChildRef<LLScrollListCtrl>("disabled_popups"); @@ -1766,7 +1615,7 @@ void LLFloaterPreference::resetAllIgnored() iter != LLNotifications::instance().templatesEnd(); ++iter) { - if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) { iter->second->mForm->setIgnored(false); } @@ -1779,7 +1628,7 @@ void LLFloaterPreference::setAllIgnored() iter != LLNotifications::instance().templatesEnd(); ++iter) { - if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) { iter->second->mForm->setIgnored(true); } @@ -2189,14 +2038,14 @@ void LLFloaterPreference::onClickAdvanced() } } -void LLFloaterPreference::onClickActionChange() +void LLFloaterPreference::onClickPermsDefault() { - mClickActionDirty = true; + LLFloaterReg::showInstance("perms_default"); } -void LLFloaterPreference::onClickPermsDefault() +void LLFloaterPreference::onClickRememberedUsernames() { - LLFloaterReg::showInstance("perms_default"); + LLFloaterReg::showInstance("forget_username"); } void LLFloaterPreference::onDeleteTranscripts() @@ -2226,26 +2075,6 @@ void LLFloaterPreference::onLogChatHistorySaved() } } -void LLFloaterPreference::updateClickActionSettings() -{ - const int single_clk_action = getChild<LLComboBox>("single_click_action_combo")->getValue().asInteger(); - const int double_clk_action = getChild<LLComboBox>("double_click_action_combo")->getValue().asInteger(); - - gSavedSettings.setBOOL("ClickToWalk", single_clk_action == 1); - gSavedSettings.setBOOL("DoubleClickAutoPilot", double_clk_action == 1); - gSavedSettings.setBOOL("DoubleClickTeleport", double_clk_action == 2); -} - -void LLFloaterPreference::updateClickActionControls() -{ - const bool click_to_walk = gSavedSettings.getBOOL("ClickToWalk"); - const bool dbl_click_to_walk = gSavedSettings.getBOOL("DoubleClickAutoPilot"); - const bool dbl_click_to_teleport = gSavedSettings.getBOOL("DoubleClickTeleport"); - - getChild<LLComboBox>("single_click_action_combo")->setValue((int)click_to_walk); - getChild<LLComboBox>("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk); -} - void LLFloaterPreference::applyUIColor(LLUICtrl* ctrl, const LLSD& param) { LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue())); @@ -2427,16 +2256,6 @@ BOOL LLPanelPreference::postBuild() getChild<LLTextBox>("mute_chb_label")->setClickedCallback(boost::bind(&toggleMuteWhenMinimized)); } - //////////////////////PanelAdvanced /////////////////// - if (hasChild("modifier_combo", TRUE)) - { - //localizing if push2talk button is set to middle mouse - if (MIDDLE_MOUSE_CV == getChild<LLUICtrl>("modifier_combo")->getValue().asString()) - { - getChild<LLUICtrl>("modifier_combo")->setValue(getString("middle_mouse")); - } - } - //////////////////////PanelSetup /////////////////// if (hasChild("max_bandwidth"), TRUE) { @@ -2602,7 +2421,7 @@ void LLPanelPreference::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl) bool music_enabled = getChild<LLCheckBoxCtrl>("enable_music")->get(); bool media_enabled = getChild<LLCheckBoxCtrl>("enable_media")->get(); - getChild<LLCheckBoxCtrl>("media_auto_play_btn")->setEnabled(music_enabled || media_enabled); + getChild<LLCheckBoxCtrl>("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); } } @@ -2722,7 +2541,7 @@ void LLPanelPreferenceGraphics::setPresetText() } } - if (hasDirtyChilds() && !preset_graphic_active.empty()) + if (hasDirtyChilds() && !preset_graphic_active.empty()) { gSavedSettings.setString("PresetGraphicActive", ""); preset_graphic_active.clear(); @@ -2842,6 +2661,373 @@ void LLPanelPreferenceGraphics::setHardwareDefaults() resetDirtyChilds(); } +//------------------------LLPanelPreferenceControls-------------------------------- +static LLPanelInjector<LLPanelPreferenceControls> t_pref_contrls("panel_preference_controls"); + +LLPanelPreferenceControls::LLPanelPreferenceControls() + :LLPanelPreference(), + mEditingColumn(-1), + mEditingMode(0) +{ + // MODE_COUNT - 1 because there are currently no settings assigned to 'saved settings'. + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + mConflictHandler[i].setLoadMode((LLKeyConflictHandler::ESourceMode)i); + } +} + +LLPanelPreferenceControls::~LLPanelPreferenceControls() +{ +} + +BOOL LLPanelPreferenceControls::postBuild() +{ + // populate list of controls + pControlsTable = getChild<LLScrollListCtrl>("controls_list"); + pKeyModeBox = getChild<LLComboBox>("key_mode"); + + pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this)); + pKeyModeBox->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onModeCommit, this)); + getChild<LLButton>("restore_defaults")->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onRestoreDefaultsBtn, this)); + + return TRUE; +} + +void LLPanelPreferenceControls::regenerateControls() +{ + mEditingMode = pKeyModeBox->getValue().asInteger(); + mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::ESourceMode)mEditingMode); + populateControlTable(); +} + +void LLPanelPreferenceControls::populateControlTable() +{ + pControlsTable->clearRows(); + pControlsTable->clearColumns(); + + std::string filename; + switch ((LLKeyConflictHandler::ESourceMode)mEditingMode) + { + case LLKeyConflictHandler::MODE_THIRD_PERSON: + case LLKeyConflictHandler::MODE_FIRST_PERSON: + case LLKeyConflictHandler::MODE_EDIT_AVATAR: + case LLKeyConflictHandler::MODE_SITTING: + filename = "control_table_contents.xml"; + break; + default: + // 'saved settings' mode doesn't have UI or actual settings yet + LL_INFOS() << "Unimplemented mode" << LL_ENDL; + return; + } + + LLXMLNodePtr xmlNode; + LLScrollListCtrl::Contents contents; + if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode)) + { + LL_WARNS() << "Failed to load " << filename << LL_ENDL; + return; + } + LLXUIParser parser; + parser.readXUI(xmlNode, contents, filename); + + if (!contents.validateBlock()) + { + return; + } + + for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator col_it = contents.columns.begin(); + col_it != contents.columns.end(); + ++col_it) + { + pControlsTable->addColumn(*col_it); + } + + LLScrollListCell::Params cell_params; + // init basic cell params + cell_params.font = LLFontGL::getFontSansSerif(); + cell_params.font_halign = LLFontGL::LEFT; + cell_params.column = ""; + cell_params.value = ""; + + + for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = contents.rows.begin(); + row_it != contents.rows.end(); + ++row_it) + { + std::string control = row_it->value.getValue().asString(); + if (!control.empty() && control != "menu_separator") + { + // At the moment 4 collumns are hardcoded + LLScrollListItem::Params item_params(*row_it); + bool enabled = mConflictHandler[mEditingMode].canAssignControl(control); + item_params.enabled.setValue(enabled); + cell_params.column = "lst_ctrl1"; + cell_params.value = mConflictHandler[mEditingMode].getControlString(control, 0); + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl2"; + cell_params.value = mConflictHandler[mEditingMode].getControlString(control, 1); + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl3"; + cell_params.value = mConflictHandler[mEditingMode].getControlString(control, 2); + item_params.columns.add(cell_params); + pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM); + } + else + { + pControlsTable->addRow(*row_it, EAddPosition::ADD_BOTTOM); + } + } +} + +// Just a workaround to not care about first separator before headers (we can start from random header) +void LLPanelPreferenceControls::addSeparator() +{ + if (pControlsTable->getItemCount() > 0) + { + pControlsTable->addSeparator(EAddPosition::ADD_BOTTOM); + } +} + +void LLPanelPreferenceControls::updateTable() +{ + mEditingControl.clear(); + std::vector<LLScrollListItem*> list = pControlsTable->getAllData(); + for (S32 i = 0; i < list.size(); ++i) + { + std::string control = list[i]->getValue(); + if (!control.empty()) + { + LLScrollListCell* cell = list[i]->getColumn(1); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0)); + cell = list[i]->getColumn(2); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 1)); + cell = list[i]->getColumn(3); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 2)); + } + } + pControlsTable->deselectAllItems(); +} + +void LLPanelPreferenceControls::apply() +{ + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].saveToSettings(); + } + } +} + +void LLPanelPreferenceControls::cancel() +{ + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].clear(); + } + } + pControlsTable->clear(); +} + +void LLPanelPreferenceControls::saveSettings() +{ + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].saveToSettings(); + mConflictHandler[i].clear(); + } + } + + S32 mode = pKeyModeBox->getValue().asInteger(); + if (mConflictHandler[mode].empty()) + { + regenerateControls(); + } +} + +void LLPanelPreferenceControls::resetDirtyChilds() +{ + regenerateControls(); +} + +void LLPanelPreferenceControls::onListCommit() +{ + LLScrollListItem* item = pControlsTable->getFirstSelected(); + if (item == NULL) + { + return; + } + + std::string control = item->getValue(); + + if (control.empty()) + { + pControlsTable->deselectAllItems(); + return; + } + + if (!mConflictHandler[mEditingMode].canAssignControl(control)) + { + pControlsTable->deselectAllItems(); + return; + } + + S32 cell_ind = item->getSelectedCell(); + if (cell_ind <= 0) + { + pControlsTable->deselectAllItems(); + return; + } + + // List does not tell us what cell was clicked, so we have to figure it out manually, but + // fresh mouse coordinates are not yet accessible during onCommit() and there are other issues, + // so we cheat: remember item user clicked at, trigger 'key dialog' on hover that comes next, + // use coordinates from hover to calculate cell + + LLScrollListCell* cell = item->getColumn(cell_ind); + if (cell) + { + LLSetKeyBindDialog* dialog = LLFloaterReg::getTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD()); + if (dialog) + { + mEditingControl = control; + mEditingColumn = cell_ind; + dialog->setParent(this, pControlsTable, DEFAULT_KEY_FILTER); + + LLFloater* root_floater = gFloaterView->getParentFloater(this); + if (root_floater) + root_floater->addDependentFloater(dialog); + dialog->openFloater(); + dialog->setFocus(TRUE); + } + } + else + { + pControlsTable->deselectAllItems(); + } +} + +void LLPanelPreferenceControls::onModeCommit() +{ + mEditingMode = pKeyModeBox->getValue().asInteger(); + if (mConflictHandler[mEditingMode].empty()) + { + // opening for first time + mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::ESourceMode)mEditingMode); + } + populateControlTable(); +} + +void LLPanelPreferenceControls::onRestoreDefaultsBtn() +{ + LLNotificationsUtil::add("PreferenceControlsDefaults", LLSD(), LLSD(), boost::bind(&LLPanelPreferenceControls::onRestoreDefaultsResponse, this, _1, _2)); +} + +void LLPanelPreferenceControls::onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch(option) + { + case 0: // All + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + mConflictHandler[i].resetToDefaults(); + // Apply changes to viewer as 'temporary' + mConflictHandler[i].saveToSettings(true); + } + + updateTable(); + break; + case 1: // Current + mConflictHandler[mEditingMode].resetToDefaults(); + // Apply changes to viewer as 'temporary' + mConflictHandler[mEditingMode].saveToSettings(true); + + updateTable(); + break; + case 2: // Cancel + default: + //exit; + break; + } +} + +// todo: copy onSetKeyBind to interface and inherit from interface +bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes) +{ + if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl)) + { + return true; + } + + if ( mEditingColumn > 0) + { + if (all_modes) + { + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + if (mConflictHandler[i].empty()) + { + mConflictHandler[i].loadFromSettings((LLKeyConflictHandler::ESourceMode)i); + } + mConflictHandler[i].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true); + // Apply changes to viewer as 'temporary' + mConflictHandler[i].saveToSettings(true); + } + } + else + { + mConflictHandler[mEditingMode].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true); + // Apply changes to viewer as 'temporary' + mConflictHandler[mEditingMode].saveToSettings(true); + } + } + + updateTable(); + return true; +} + +void LLPanelPreferenceControls::onDefaultKeyBind(bool all_modes) +{ + if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl)) + { + return; + } + + if (mEditingColumn > 0) + { + if (all_modes) + { + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + if (mConflictHandler[i].empty()) + { + mConflictHandler[i].loadFromSettings((LLKeyConflictHandler::ESourceMode)i); + } + mConflictHandler[i].resetToDefault(mEditingControl, mEditingColumn - 1); + // Apply changes to viewer as 'temporary' + mConflictHandler[i].saveToSettings(true); + } + } + else + { + mConflictHandler[mEditingMode].resetToDefault(mEditingControl, mEditingColumn - 1); + // Apply changes to viewer as 'temporary' + mConflictHandler[mEditingMode].saveToSettings(true); + } + } + updateTable(); +} + +void LLPanelPreferenceControls::onCancelKeyBind() +{ + pControlsTable->deselectAllItems(); +} + LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key) : LLFloater(key) { diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 1b8229ada6cc3e2b4148fab02ab2a40aa147788b..9ede7d5bcf2cec64332d112092b9cd659cf56a79 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -37,13 +37,17 @@ #include "llavatarpropertiesprocessor.h" #include "llconversationlog.h" #include "llsearcheditor.h" +#include "llsetkeybinddialog.h" +#include "llkeyconflict.h" class LLConversationLogObserver; class LLPanelPreference; class LLPanelLCD; class LLPanelDebug; class LLMessageSystem; +class LLComboBox; class LLScrollListCtrl; +class LLScrollListCell; class LLSliderCtrl; class LLSD; class LLTextBox; @@ -127,13 +131,6 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver, // callback for when client turns on impostors void onAvatarImpostorsEnable(); - // callback for commit in the "Single click on land" and "Double click on land" comboboxes. - void onClickActionChange(); - // updates click/double-click action settings depending on controls values - void updateClickActionSettings(); - // updates click/double-click action controls depending on values from settings.xml - void updateClickActionControls(); - public: // This function squirrels away the current values of the controls so that // cancel() can restore them. @@ -146,9 +143,6 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver, void onClickResetCache(); void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata); void onSelectSkin(); - void onClickSetKey(); - void setKey(KEY key); - void onClickSetMiddleMouse(); void onClickSetSounds(); void onClickEnablePopup(); void onClickDisablePopup(); @@ -167,7 +161,6 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver, void refreshUI(); - void onCommitParcelMediaAutoPlayEnable(); void onCommitMediaEnabled(); void onCommitMusicEnabled(); void applyResolution(); @@ -180,6 +173,7 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver, void onClickProxySettings(); void onClickTranslationSettings(); void onClickPermsDefault(); + void onClickRememberedUsernames(); void onClickAutoReplace(); void onClickSpellChecker(); void onClickRenderExceptions(); @@ -202,7 +196,6 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver, static std::string sSkin; notifications_map mNotificationOptions; - bool mClickActionDirty; ///< Set to true when the click/double-click options get changed by user. bool mGotPersonalInfo; bool mOriginalIMViaEmail; bool mLanguageChanged; @@ -292,6 +285,44 @@ class LLPanelPreferenceGraphics : public LLPanelPreference LOG_CLASS(LLPanelPreferenceGraphics); }; +class LLPanelPreferenceControls : public LLPanelPreference, public LLKeyBindResponderInterface +{ + LOG_CLASS(LLPanelPreferenceControls); +public: + LLPanelPreferenceControls(); + virtual ~LLPanelPreferenceControls(); + + BOOL postBuild(); + + void apply(); + void cancel(); + void saveSettings(); + void resetDirtyChilds(); + + void onListCommit(); + void onModeCommit(); + void onRestoreDefaultsBtn(); + void onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response); + /*virtual*/ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes); + /*virtual*/ void onDefaultKeyBind(bool all_modes); + /*virtual*/ void onCancelKeyBind(); + +private: + // reloads settings, discards current changes, updates table + void regenerateControls(); + + void populateControlTable(); + void addSeparator(); + void updateTable(); + + LLScrollListCtrl* pControlsTable; + LLComboBox *pKeyModeBox; + LLKeyConflictHandler mConflictHandler[LLKeyConflictHandler::MODE_COUNT]; + std::string mEditingControl; + S32 mEditingColumn; + S32 mEditingMode; +}; + class LLFloaterPreferenceGraphicsAdvanced : public LLFloater { public: diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index fbb7432f71caf4539bfcb4aa85c4e74b052bf516..64ad40f4195a7b73b353ded636c400b049fcf910 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -85,7 +85,7 @@ class LLPropertiesObserver : public LLInventoryObserver } virtual void changed(U32 mask); private: - LLFloaterProperties* mFloater; + LLFloaterProperties* mFloater; // Not a handle because LLFloaterProperties is managing LLPropertiesObserver }; void LLPropertiesObserver::changed(U32 mask) diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 960fd9620d8a6bf66b9e3e1f8fa559b0d6c12be5..60cb22c4de4a5678cb0ddd40a79b635a3f59c1bc 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -936,7 +936,7 @@ void LLFloaterReporter::takeNewSnapshot() // Take a screenshot, but don't draw this floater. setVisible(FALSE); - if( !gViewerWindow->rawSnapshot(mImageRaw, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, FALSE, TRUE, FALSE)) + if (!gViewerWindow->rawSnapshot(mImageRaw, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, FALSE, gSavedSettings.getBOOL("RenderHUDInSnapshot"), TRUE, FALSE)) { LL_WARNS() << "Unable to take screenshot" << LL_ENDL; setVisible(TRUE); diff --git a/indra/newview/llhudeffectbeam.cpp b/indra/newview/llhudeffectbeam.cpp index 54e683e048371e9c834346c09cbf8b42b4d35445..d1d83e6e03847b5bb9379d37c7f677fb79546674 100644 --- a/indra/newview/llhudeffectbeam.cpp +++ b/indra/newview/llhudeffectbeam.cpp @@ -90,7 +90,7 @@ void LLHUDEffectBeam::packData(LLMessageSystem *mesgsys) memset(packed_data, 0, 41); if (mSourceObject) { - htonmemcpy(packed_data, mSourceObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(packed_data, mSourceObject->mID.mData, MVT_LLUUID, 16); } if (mTargetObject) @@ -104,11 +104,11 @@ void LLHUDEffectBeam::packData(LLMessageSystem *mesgsys) if (mTargetObject) { - htonmemcpy(&(packed_data[17]), mTargetObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[17]), mTargetObject->mID.mData, MVT_LLUUID, 16); } else { - htonmemcpy(&(packed_data[17]), mTargetPos.mdV, MVT_LLVector3d, 24); + htolememcpy(&(packed_data[17]), mTargetPos.mdV, MVT_LLVector3d, 24); } mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, 41); } @@ -131,7 +131,7 @@ void LLHUDEffectBeam::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, 41, blocknum); - htonmemcpy(source_id.mData, packed_data, MVT_LLUUID, 16); + htolememcpy(source_id.mData, packed_data, MVT_LLUUID, 16); LLViewerObject *objp = gObjectList.findObject(source_id); if (objp) @@ -143,7 +143,7 @@ void LLHUDEffectBeam::unpackData(LLMessageSystem *mesgsys, S32 blocknum) if (use_target_object) { - htonmemcpy(target_id.mData, &packed_data[17], MVT_LLUUID, 16); + htolememcpy(target_id.mData, &packed_data[17], MVT_LLUUID, 16); LLViewerObject *objp = gObjectList.findObject(target_id); if (objp) @@ -153,7 +153,7 @@ void LLHUDEffectBeam::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } else { - htonmemcpy(new_target.mdV, &(packed_data[17]), MVT_LLVector3d, 24); + htolememcpy(new_target.mdV, &(packed_data[17]), MVT_LLVector3d, 24); setTargetPos(new_target); } diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp index f46152dcec96844d9bc88f66f15f07db2e1261dd..6898dce7b10f75f285c39613cf5653d4b481e653 100644 --- a/indra/newview/llhudeffectlookat.cpp +++ b/indra/newview/llhudeffectlookat.cpp @@ -269,29 +269,29 @@ void LLHUDEffectLookAt::packData(LLMessageSystem *mesgsys) if (mSourceObject) { - htonmemcpy(&(packed_data[SOURCE_AVATAR]), mSourceObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[SOURCE_AVATAR]), mSourceObject->mID.mData, MVT_LLUUID, 16); } else { - htonmemcpy(&(packed_data[SOURCE_AVATAR]), LLUUID::null.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[SOURCE_AVATAR]), LLUUID::null.mData, MVT_LLUUID, 16); } // pack both target object and position // position interpreted as offset if target object is non-null if (mTargetObject) { - htonmemcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16); } else { - htonmemcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16); } - htonmemcpy(&(packed_data[TARGET_POS]), mTargetOffsetGlobal.mdV, MVT_LLVector3d, 24); + htolememcpy(&(packed_data[TARGET_POS]), mTargetOffsetGlobal.mdV, MVT_LLVector3d, 24); U8 lookAtTypePacked = (U8)mTargetType; - htonmemcpy(&(packed_data[LOOKAT_TYPE]), &lookAtTypePacked, MVT_U8, 1); + htolememcpy(&(packed_data[LOOKAT_TYPE]), &lookAtTypePacked, MVT_U8, 1); mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, PKT_SIZE); @@ -325,7 +325,7 @@ void LLHUDEffectLookAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum); - htonmemcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16); + htolememcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16); LLViewerObject *objp = gObjectList.findObject(source_id); if (objp && objp->isAvatar()) @@ -338,11 +338,11 @@ void LLHUDEffectLookAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) return; } - htonmemcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16); + htolememcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16); objp = gObjectList.findObject(target_id); - htonmemcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24); + htolememcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24); if (objp) { @@ -358,7 +358,7 @@ void LLHUDEffectLookAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } U8 lookAtTypeUnpacked = 0; - htonmemcpy(&lookAtTypeUnpacked, &(packed_data[LOOKAT_TYPE]), MVT_U8, 1); + htolememcpy(&lookAtTypeUnpacked, &(packed_data[LOOKAT_TYPE]), MVT_U8, 1); mTargetType = (ELookAtType)lookAtTypeUnpacked; if (mTargetType == LOOKAT_TARGET_NONE) diff --git a/indra/newview/llhudeffectpointat.cpp b/indra/newview/llhudeffectpointat.cpp index cc772c8f5c0aa2f1e11afc0a576bf2215e02ddbb..ecf6d42d692af8f0e14028c9db10bf76a36adc3b 100644 --- a/indra/newview/llhudeffectpointat.cpp +++ b/indra/newview/llhudeffectpointat.cpp @@ -107,28 +107,28 @@ void LLHUDEffectPointAt::packData(LLMessageSystem *mesgsys) if (mSourceObject) { - htonmemcpy(&(packed_data[SOURCE_AVATAR]), mSourceObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[SOURCE_AVATAR]), mSourceObject->mID.mData, MVT_LLUUID, 16); } else { - htonmemcpy(&(packed_data[SOURCE_AVATAR]), LLUUID::null.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[SOURCE_AVATAR]), LLUUID::null.mData, MVT_LLUUID, 16); } // pack both target object and position // position interpreted as offset if target object is non-null if (mTargetObject) { - htonmemcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16); } else { - htonmemcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16); + htolememcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16); } - htonmemcpy(&(packed_data[TARGET_POS]), mTargetOffsetGlobal.mdV, MVT_LLVector3d, 24); + htolememcpy(&(packed_data[TARGET_POS]), mTargetOffsetGlobal.mdV, MVT_LLVector3d, 24); U8 pointAtTypePacked = (U8)mTargetType; - htonmemcpy(&(packed_data[POINTAT_TYPE]), &pointAtTypePacked, MVT_U8, 1); + htolememcpy(&(packed_data[POINTAT_TYPE]), &pointAtTypePacked, MVT_U8, 1); mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, PKT_SIZE); @@ -164,10 +164,10 @@ void LLHUDEffectPointAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum); - htonmemcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16); - htonmemcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16); - htonmemcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24); - htonmemcpy(&pointAtTypeUnpacked, &(packed_data[POINTAT_TYPE]), MVT_U8, 1); + htolememcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16); + htolememcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16); + htolememcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24); + htolememcpy(&pointAtTypeUnpacked, &(packed_data[POINTAT_TYPE]), MVT_U8, 1); LLViewerObject *objp = gObjectList.findObject(source_id); if (objp && objp->isAvatar()) diff --git a/indra/newview/llhudeffecttrail.cpp b/indra/newview/llhudeffecttrail.cpp index fc6efdb840f03cf03a621bd188f60054fa610f79..2ba8aa422bd1b70335222ca1c12e69d299fe3029 100644 --- a/indra/newview/llhudeffecttrail.cpp +++ b/indra/newview/llhudeffecttrail.cpp @@ -87,15 +87,15 @@ void LLHUDEffectSpiral::packData(LLMessageSystem *mesgsys) if (mSourceObject) { - htonmemcpy(packed_data, mSourceObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(packed_data, mSourceObject->mID.mData, MVT_LLUUID, 16); } if (mTargetObject) { - htonmemcpy(packed_data + 16, mTargetObject->mID.mData, MVT_LLUUID, 16); + htolememcpy(packed_data + 16, mTargetObject->mID.mData, MVT_LLUUID, 16); } if (!mPositionGlobal.isExactlyZero()) { - htonmemcpy(packed_data + 32, mPositionGlobal.mdV, MVT_LLVector3d, 24); + htolememcpy(packed_data + 32, mPositionGlobal.mdV, MVT_LLVector3d, 24); } mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, 56); } @@ -116,9 +116,9 @@ void LLHUDEffectSpiral::unpackData(LLMessageSystem *mesgsys, S32 blocknum) mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, EFFECT_SIZE, blocknum, EFFECT_SIZE); - htonmemcpy(object_id.mData, packed_data, MVT_LLUUID, 16); - htonmemcpy(target_object_id.mData, packed_data + 16, MVT_LLUUID, 16); - htonmemcpy(mPositionGlobal.mdV, packed_data + 32, MVT_LLVector3d, 24); + htolememcpy(object_id.mData, packed_data, MVT_LLUUID, 16); + htolememcpy(target_object_id.mData, packed_data + 16, MVT_LLUUID, 16); + htolememcpy(mPositionGlobal.mdV, packed_data + 32, MVT_LLVector3d, 24); LLViewerObject *objp = NULL; diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 3606a439a69fc2abdccda3a83e1dc5ce5fdf62b5..48101bf0d9c8c9cd6029a0f24a73bf4cec45a074 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -29,6 +29,7 @@ #include "llimprocessing.h" #include "llagent.h" +#include "llappviewer.h" #include "llavatarnamecache.h" #include "llfirstuse.h" #include "llfloaterreg.h" @@ -61,6 +62,8 @@ #pragma warning (disable:4702) #endif +extern void on_new_message(const LLSD& msg); + // Strip out "Resident" for display, but only if the message came from a user // (rather than a script) static std::string clean_name_from_im(const std::string& name, EInstantMessage type) @@ -715,7 +718,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, { info = new LLOfferInfo(); - info->mIM = IM_GROUP_NOTICE; + info->mIM = dialog; info->mFromID = from_id; info->mFromGroup = from_group; info->mTransactionID = session_id; @@ -854,39 +857,18 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } else // IM_TASK_INVENTORY_OFFERED { - if (offline == IM_OFFLINE && session_id.isNull() && aux_id.notNull() && binary_bucket_size > sizeof(S8)* 5) - { - // cap received offline message - std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("|", "", boost::keep_empty_tokens); - tokenizer tokens(str_bucket, sep); - tokenizer::iterator iter = tokens.begin(); - - info->mType = (LLAssetType::EType)(atoi((*(iter++)).c_str())); - // Note There is more elements in 'tokens' ... - - info->mObjectID = LLUUID::null; - info->mFromObject = TRUE; - } - else - { - if (sizeof(S8) != binary_bucket_size) - { - LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; - delete info; - break; - } - info->mType = (LLAssetType::EType) binary_bucket[0]; - info->mObjectID = LLUUID::null; - info->mFromObject = TRUE; - } + info->mType = (LLAssetType::EType) binary_bucket[0]; + info->mObjectID = LLUUID::null; + info->mFromObject = TRUE; } + // In the case of an offline message, the transaction id will be in aux_id and th session_id will be null + // (conversely when online the transaction id is passed as session_id) + info->mTransactionID = session_id.isNull() ? aux_id : session_id; + info->mIM = dialog; info->mFromID = from_id; info->mFromGroup = from_group; - info->mTransactionID = session_id; info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); info->mFromName = name; @@ -896,12 +878,18 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, if (is_muted) { // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331) - LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID); - fetch_item->startFetch(); - delete fetch_item; - - // Same as closing window - info->forceResponse(IOR_DECLINE); + if (IM_INVENTORY_OFFERED == dialog) + { + LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID); + fetch_item->startFetch(); + delete fetch_item; + // Same as closing window + info->forceResponse(IOR_DECLINE); + } + else + { + info->forceResponse(IOR_MUTE); + } } // old logic: busy mode must not affect interaction with objects (STORM-565) // new logic: inventory offers from in-world objects should be auto-declined (CHUI-519) @@ -1021,6 +1009,14 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); + if (message != "") + { + LLSD msg_notify; + msg_notify["session_id"] = LLUUID(); + msg_notify["from_id"] = chat.mFromID; + msg_notify["source_type"] = chat.mSourceType; + on_new_message(msg_notify); + } } @@ -1468,6 +1464,7 @@ void LLIMProcessing::requestOfflineMessages() static BOOL requested = FALSE; if (!requested && gMessageSystem + && !gDisconnected && LLMuteList::getInstance()->isLoaded() && isAgentAvatarValid() && gAgent.getRegion() @@ -1555,7 +1552,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) std::vector<U8> data; S32 binary_bucket_size = 0; - LLHost sender = gAgent.getRegion()->getHost(); + LLHost sender = gAgent.getRegionHost(); LLSD::array_iterator i = messages.beginArray(); LLSD::array_iterator iEnd = messages.endArray(); diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index e331a51bda76220197e21dc08c9078fce942c966..d5142a4496a9b2bc3e9a6c2894d80a6ba3a73f7d 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -843,7 +843,7 @@ void LLIMModel::LLIMSession::loadHistory() std::list<LLSD> chat_history; //involves parsing of a chat history - LLLogChat::loadChatHistory(mHistoryFileName, chat_history); + LLLogChat::loadChatHistory(mHistoryFileName, chat_history, LLSD(), isGroupChat()); addMessagesFromHistory(chat_history); } } @@ -907,6 +907,11 @@ bool LLIMModel::LLIMSession::isP2P() return IM_NOTHING_SPECIAL == mType; } +bool LLIMModel::LLIMSession::isGroupChat() +{ + return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID)); +} + bool LLIMModel::LLIMSession::isOtherParticipantAvaline() { return !mOtherParticipantIsAvatar; @@ -964,6 +969,10 @@ void LLIMModel::LLIMSession::buildHistoryFileName() mHistoryFileName = LLCacheName::buildUsername(mName); } } + else if (isGroupChat()) + { + mHistoryFileName = mName + GROUP_CHAT_SUFFIX; + } } //static diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 2a9e4679a8bd1dd8447ee8dbe42aab39f82edec3..79c831ebb6a6981d2f3695ee43c6bdc003bb615f 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -91,6 +91,7 @@ class LLIMModel : public LLSingleton<LLIMModel> bool isOutgoingAdHoc() const; bool isAdHoc(); bool isP2P(); + bool isGroupChat(); bool isOtherParticipantAvaline(); bool isP2PSessionType() const { return mSessionType == P2P_SESSION;} diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 349ba6183ba61ca5be91b73b1e5379d92c049aa0..d460aa145246c901e92f4e368362d5441a1358b5 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1797,7 +1797,7 @@ void LLItemBridge::restoreToWorld() msg->nextBlockFast(_PREHASH_InventoryData); itemp->packMessage(msg); - msg->sendReliable(gAgent.getRegion()->getHost()); + msg->sendReliable(gAgent.getRegionHost()); //remove local inventory copy, sim will deal with permissions and removing the item //from the actual inventory if its a no-copy etc @@ -2270,7 +2270,7 @@ class LLIsItemRemovable : public LLFolderViewFunctor // Can be destroyed (or moved to trash) BOOL LLFolderBridge::isItemRemovable() const { - if (!get_is_category_removable(getInventoryModel(), mUUID) || isMarketplaceListingsFolder()) + if (!get_is_category_removable(getInventoryModel(), mUUID)) { return FALSE; } @@ -2287,6 +2287,11 @@ BOOL LLFolderBridge::isItemRemovable() const } } + if (isMarketplaceListingsFolder() && (!LLMarketplaceData::instance().isSLMDataFetched() || LLMarketplaceData::instance().getActivationState(mUUID))) + { + return FALSE; + } + return TRUE; } @@ -4662,7 +4667,7 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response { LLInventoryObject::object_list_t inventory_objects; object->getInventoryContents(inventory_objects); - int contents_count = inventory_objects.size()-1; //subtract one for containing folder + int contents_count = inventory_objects.size(); LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count, cat_and_wear->mFolderResponded, cat_and_wear->mReplace); diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 16385928b4d8e9e88d71289e5b48ef63d419956a..e8bc915f22975233b0c49195cd179913ac141695 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -42,7 +42,7 @@ #include "llviewerfoldertype.h" #include "llradiogroup.h" #include "llstartup.h" - +#include <boost/regex.hpp> // linden library includes #include "llclipboard.h" #include "lltrans.h" @@ -116,7 +116,39 @@ bool LLInventoryFilter::check(const LLFolderViewModelItem* item) break; } - bool passed = (mFilterSubString.size() ? desc.find(mFilterSubString) != std::string::npos : true); + + bool passed = true; + if (!mExactToken.empty() && (mSearchType == SEARCHTYPE_NAME)) + { + passed = false; + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep(" "); + tokenizer tokens(desc, sep); + + for (auto token_iter : tokens) + { + if (token_iter == mExactToken) + { + passed = true; + break; + } + } + } + else if ((mFilterTokens.size() > 0) && (mSearchType == SEARCHTYPE_NAME)) + { + for (auto token_iter : mFilterTokens) + { + if (desc.find(token_iter) == std::string::npos) + { + return false; + } + } + } + else + { + passed = (mFilterSubString.size() ? desc.find(mFilterSubString) != std::string::npos : true); + } + passed = passed && checkAgainstFilterType(listener); passed = passed && checkAgainstPermissions(listener); passed = passed && checkAgainstFilterLinks(listener); @@ -693,6 +725,38 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) if (mFilterSubString != filter_sub_string_new) { + + mFilterTokens.clear(); + if (filter_sub_string_new.find_first_of("+") != std::string::npos) + { + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("+"); + tokenizer tokens(filter_sub_string_new, sep); + + for (auto token_iter : tokens) + { + mFilterTokens.push_back(token_iter); + } + } + + std::string old_token = mExactToken; + mExactToken.clear(); + bool exact_token_changed = false; + if (mFilterTokens.empty() && filter_sub_string_new.size() > 2) + { + boost::regex mPattern = boost::regex("\"\\s*([^<]*)?\\s*\"", + boost::regex::perl | boost::regex::icase); + boost::match_results<std::string::const_iterator> matches; + mExactToken = (boost::regex_match(filter_sub_string_new, matches, mPattern) && matches[1].matched) + ? matches[1] + : LLStringUtil::null; + if ((old_token.empty() && !mExactToken.empty()) + || (!old_token.empty() && mExactToken.empty())) + { + exact_token_changed = true; + } + } + // hitting BACKSPACE, for example const BOOL less_restrictive = mFilterSubString.size() >= filter_sub_string_new.size() && !mFilterSubString.substr(0, filter_sub_string_new.size()).compare(filter_sub_string_new); @@ -702,7 +766,11 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) && !filter_sub_string_new.substr(0, mFilterSubString.size()).compare(mFilterSubString); mFilterSubString = filter_sub_string_new; - if (less_restrictive) + if (exact_token_changed) + { + setModified(FILTER_RESTART); + } + else if (less_restrictive) { setModified(FILTER_LESS_RESTRICTIVE); } diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h index 4a1fec8454893963b0d2c338bbf95894742607bf..3f24211f4127f20e334df9be192be060e853822b 100644 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -327,6 +327,9 @@ class LLInventoryFilter : public LLFolderViewFilter std::string mEmptyLookupMessage; ESearchType mSearchType; + + std::vector<std::string> mFilterTokens; + std::string mExactToken; }; #endif diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index d4993a1091a2cfa225a031e016d1a69faccc55e5..6f461673ee0580752b9b88a9b35aae8e057e97f0 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -291,7 +291,6 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible")) { getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX)); - getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_OUTBOX)); } // hide marketplace listing box, unless we are a marketplace panel if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && !mParams.use_marketplace_folders) diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a94836c59d0580accb3d548c05c121e969ae7c3f --- /dev/null +++ b/indra/newview/llkeyconflict.cpp @@ -0,0 +1,852 @@ +/** + * @file llkeyconflict.cpp + * @brief + * + * $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$ + */ + +/* + * App-wide preferences. Note that these are not per-user, + * because we need to load many preferences before we have + * a login name. + */ + +#include "llviewerprecompiledheaders.h" + +#include "llkeyconflict.h" + +#include "llinitparam.h" +#include "llkeyboard.h" +#include "lltrans.h" +#include "llviewercontrol.h" +#include "llviewerinput.h" +#include "llviewermenu.h" +#include "llxuiparser.h" + +static const std::string saved_settings_key_controls[] = { "placeholder" }; // add settings from gSavedSettings here + +static const std::string filename_default = "key_bindings.xml"; +static const std::string filename_temporary = "key_bindings_tmp.xml"; // used to apply uncommited changes on the go. + +// LLKeyboard::stringFromMask is meant for UI and is OS dependent, +// so this class uses it's own version +std::string string_from_mask(MASK mask) +{ + std::string res; + if ((mask & MASK_CONTROL) != 0) + { + res = "CTL"; + } + if ((mask & MASK_ALT) != 0) + { + if (!res.empty()) res += "_"; + res += "ALT"; + } + if ((mask & MASK_SHIFT) != 0) + { + if (!res.empty()) res += "_"; + res += "SHIFT"; + } + + if (mask == MASK_NONE) + { + res = "NONE"; + } + return res; +} + +std::string string_from_mouse(EMouseClickType click, bool translate) +{ + std::string res; + switch (click) + { + case CLICK_LEFT: + res = "LMB"; + break; + case CLICK_MIDDLE: + res = "MMB"; + break; + case CLICK_RIGHT: + res = "RMB"; + break; + case CLICK_BUTTON4: + res = "MB4"; + break; + case CLICK_BUTTON5: + res = "MB5"; + break; + case CLICK_DOUBLELEFT: + res = "Double LMB"; + break; + default: + break; + } + + if (translate && !res.empty()) + { + res = LLTrans::getString(res); + } + return res; +} + +// LLKeyConflictHandler + +S32 LLKeyConflictHandler::sTemporaryFileUseCount = 0; + +LLKeyConflictHandler::LLKeyConflictHandler() +: mHasUnsavedChanges(false), + mUsesTemporaryFile(false), + mLoadMode(MODE_COUNT) +{ +} + +LLKeyConflictHandler::LLKeyConflictHandler(ESourceMode mode) +: mHasUnsavedChanges(false), + mUsesTemporaryFile(false), + mLoadMode(mode) +{ + loadFromSettings(mode); +} + +LLKeyConflictHandler::~LLKeyConflictHandler() +{ + clearUnsavedChanges(); + // Note: does not reset bindings if temporary file was used +} + +bool LLKeyConflictHandler::canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask) +{ + return mControlsMap[control_name].canHandle(mouse_ind, key, mask); +} + +bool LLKeyConflictHandler::canHandleKey(const std::string &control_name, KEY key, MASK mask) +{ + return canHandleControl(control_name, CLICK_NONE, key, mask); +} + +bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask) +{ + return canHandleControl(control_name, mouse_ind, KEY_NONE, mask); +} + +bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask) +{ + return canHandleControl(control_name, (EMouseClickType)mouse_ind, KEY_NONE, mask); +} + +bool LLKeyConflictHandler::canAssignControl(const std::string &control_name) +{ + control_map_t::iterator iter = mControlsMap.find(control_name); + if (iter != mControlsMap.end()) + { + return iter->second.mAssignable; + } + // If we don't know this control means it wasn't assigned by user yet and thus is editable + return true; +} + +// static +bool LLKeyConflictHandler::isReservedByMenu(const KEY &key, const MASK &mask) +{ + if (key == KEY_NONE) + { + return false; + } + return (gMenuBarView && gMenuBarView->hasAccelerator(key, mask)) + || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(key, mask)); +} + +// static +bool LLKeyConflictHandler::isReservedByMenu(const LLKeyData &data) +{ + if (data.mMouse != CLICK_NONE || data.mKey == KEY_NONE) + { + return false; + } + return (gMenuBarView && gMenuBarView->hasAccelerator(data.mKey, data.mMask)) + || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(data.mKey, data.mMask)); +} + +bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask) +{ + if (control_name.empty()) + { + return false; + } + LLKeyConflict &type_data = mControlsMap[control_name]; + if (!type_data.mAssignable) + { + LL_ERRS() << "Error in code, user or system should not be able to change certain controls" << LL_ENDL; + } + LLKeyData data(mouse, key, mask, ignore_mask); + if (type_data.mKeyBind.getKeyData(index) == data) + { + return true; + } + if (isReservedByMenu(data)) + { + return false; + } + if (removeConflicts(data, type_data.mConflictMask)) + { + type_data.mKeyBind.replaceKeyData(data, index); + mHasUnsavedChanges = true; + return true; + } + // control already in use/blocked + return false; +} + +LLKeyData LLKeyConflictHandler::getControl(const std::string &control_name, U32 index) +{ + if (control_name.empty()) + { + return LLKeyData(); + } + return mControlsMap[control_name].getKeyData(index); +} + +// static +std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata) +{ + std::string result; + + if (keydata.mMask != MASK_NONE && keydata.mKey != KEY_NONE) + { + result = LLKeyboard::stringFromAccelerator(keydata.mMask, keydata.mKey); + } + else if (keydata.mKey != KEY_NONE) + { + result = LLKeyboard::stringFromKey(keydata.mKey); + } + else if (keydata.mMask != MASK_NONE) + { + result = LLKeyboard::stringFromAccelerator(keydata.mMask); + } + + result += string_from_mouse(keydata.mMouse, true); + + return result; +} + +std::string LLKeyConflictHandler::getControlString(const std::string &control_name, U32 index) +{ + if (control_name.empty()) + { + return ""; + } + return getStringFromKeyData(mControlsMap[control_name].getKeyData(index)); +} + +void LLKeyConflictHandler::loadFromControlSettings(const std::string &name) +{ + LLControlVariablePtr var = gSavedSettings.getControl(name); + if (var) + { + LLKeyBind bind(var->getValue()); + LLKeyConflict key(bind, true, 0); + mControlsMap[name] = key; + } +} + +void LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination) +{ + for (LLInitParam::ParamIterator<LLViewerInput::KeyBinding>::const_iterator it = keymode.bindings.begin(), + end_it = keymode.bindings.end(); + it != end_it; + ++it) + { + KEY key; + MASK mask; + EMouseClickType mouse = CLICK_NONE; + if (it->mouse.isProvided()) + { + LLViewerInput::mouseFromString(it->mouse.getValue(), &mouse); + } + if (it->key.getValue().empty()) + { + key = KEY_NONE; + } + else + { + LLKeyboard::keyFromString(it->key, &key); + } + LLKeyboard::maskFromString(it->mask, &mask); + // Note: it->command is also the name of UI element, howhever xml we are loading from + // might not know all the commands, so UI will have to know what to fill by its own + LLKeyConflict &type_data = (*destination)[it->command]; + type_data.mAssignable = true; + type_data.mKeyBind.addKeyData(mouse, key, mask, true); + } +} + +bool LLKeyConflictHandler::loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination) +{ + if (filename.empty()) + { + return false; + } + + bool res = false; + + LLViewerInput::Keys keys; + LLSimpleXUIParser parser; + + if (parser.readXUI(filename, keys) + && keys.validateBlock()) + { + switch (load_mode) + { + case MODE_FIRST_PERSON: + if (keys.first_person.isProvided()) + { + loadFromSettings(keys.first_person, destination); + res = true; + } + break; + case MODE_THIRD_PERSON: + if (keys.third_person.isProvided()) + { + loadFromSettings(keys.third_person, destination); + res = true; + } + break; + case MODE_EDIT_AVATAR: + if (keys.edit_avatar.isProvided()) + { + loadFromSettings(keys.edit_avatar, destination); + res = true; + } + break; + case MODE_SITTING: + if (keys.sitting.isProvided()) + { + loadFromSettings(keys.sitting, destination); + res = true; + } + break; + default: + LL_ERRS() << "Not implememted mode " << load_mode << LL_ENDL; + break; + } + } + return res; +} + +void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode) +{ + mControlsMap.clear(); + mDefaultsMap.clear(); + + // E.X. In case we need placeholder keys for conflict resolution. + generatePlaceholders(load_mode); + + if (load_mode == MODE_SAVED_SETTINGS) + { + // load settings clss knows about, but it also possible to load settings by name separately + const S32 size = std::extent<decltype(saved_settings_key_controls)>::value; + for (U32 i = 0; i < size; i++) + { + loadFromControlSettings(saved_settings_key_controls[i]); + } + } + else + { + // load defaults + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename_default); + if (!loadFromSettings(load_mode, filename, &mDefaultsMap)) + { + LL_WARNS() << "Failed to load default settings, aborting" << LL_ENDL; + return; + } + + // load user's + filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default); + if (!gDirUtilp->fileExists(filename) || !loadFromSettings(load_mode, filename, &mControlsMap)) + { + // mind placeholders + mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end()); + } + } + mLoadMode = load_mode; +} + +void LLKeyConflictHandler::saveToSettings(bool temporary) +{ + if (mControlsMap.empty()) + { + return; + } + + if (mLoadMode == MODE_SAVED_SETTINGS) + { + // Does not support 'temporary', preferences handle that themself + // so in case of saved settings we just do not clear mHasUnsavedChanges + control_map_t::iterator iter = mControlsMap.begin(); + control_map_t::iterator end = mControlsMap.end(); + + for (; iter != end; ++iter) + { + if (iter->first.empty()) + { + continue; + } + + LLKeyConflict &key = iter->second; + key.mKeyBind.trimEmpty(); + if (!key.mAssignable) + { + continue; + } + + if (gSavedSettings.controlExists(iter->first)) + { + gSavedSettings.setLLSD(iter->first, key.mKeyBind.asLLSD()); + } + else if (!key.mKeyBind.empty()) + { + // Note: this is currently not in use, might be better for load mechanics to ask for and retain control group + // otherwise settings loaded from other control groups will end in this one + LL_INFOS() << "Creating new keybinding " << iter->first << LL_ENDL; + gSavedSettings.declareLLSD(iter->first, key.mKeyBind.asLLSD(), "comment", LLControlVariable::PERSIST_ALWAYS); + } + } + } + else + { + // Determine what file to load and load full copy of that file + std::string filename; + + if (temporary) + { + filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary); + if (!gDirUtilp->fileExists(filename)) + { + filename.clear(); + } + } + + if (filename.empty()) + { + filename = gDirUtilp->findFile(filename_default, + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + } + + LLViewerInput::Keys keys; + LLSimpleXUIParser parser; + + if (parser.readXUI(filename, keys) + && keys.validateBlock()) + { + // replace category we edited + + // mode is a HACK to correctly reset bindings without reparsing whole file and avoid doing + // own param container (which will face issues with inasseesible members of LLInitParam) + LLViewerInput::KeyMode mode; + LLViewerInput::KeyBinding binding; + + control_map_t::iterator iter = mControlsMap.begin(); + control_map_t::iterator end = mControlsMap.end(); + for (; iter != end; ++iter) + { + // By default xml have (had) up to 6 elements per function + // eventually it will be cleaned up and UI will only shows 3 per function, + // so make sure to cleanup. + // Also this helps in keeping file small. + iter->second.mKeyBind.trimEmpty(); + U32 size = iter->second.mKeyBind.getDataCount(); + for (U32 i = 0; i < size; ++i) + { + if (iter->first.empty()) + { + continue; + } + + LLKeyConflict &key = iter->second; + key.mKeyBind.trimEmpty(); + if (key.mKeyBind.empty() || !key.mAssignable) + { + continue; + } + + LLKeyData data = key.mKeyBind.getKeyData(i); + // Still write empty LLKeyData to make sure we will maintain UI position + if (data.mKey == KEY_NONE) + { + // Might be better idea to be consistent and use NONE. LLViewerInput can work with both cases + binding.key = ""; + } + else + { + binding.key = LLKeyboard::stringFromKey(data.mKey, false /*Do not localize*/); + } + binding.mask = string_from_mask(data.mMask); + if (data.mMouse == CLICK_NONE) + { + binding.mouse.setProvided(false); + } + else + { + // set() because 'optional', for compatibility purposes + // just copy old keys.xml and rename to key_bindings.xml, it should work + binding.mouse.set(string_from_mouse(data.mMouse, false), true); + } + binding.command = iter->first; + mode.bindings.add(binding); + } + } + + switch (mLoadMode) + { + case MODE_FIRST_PERSON: + if (keys.first_person.isProvided()) + { + keys.first_person.bindings.set(mode.bindings, true); + } + break; + case MODE_THIRD_PERSON: + if (keys.third_person.isProvided()) + { + keys.third_person.bindings.set(mode.bindings, true); + } + break; + case MODE_EDIT_AVATAR: + if (keys.edit_avatar.isProvided()) + { + keys.edit_avatar.bindings.set(mode.bindings, true); + } + break; + case MODE_SITTING: + if (keys.sitting.isProvided()) + { + keys.sitting.bindings.set(mode.bindings, true); + } + break; + default: + LL_ERRS() << "Not implememted mode " << mLoadMode << LL_ENDL; + break; + } + + if (temporary) + { + // write to temporary xml and use it for gViewerInput + filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary); + if (!mUsesTemporaryFile) + { + mUsesTemporaryFile = true; + sTemporaryFileUseCount++; + } + } + else + { + // write back to user's xml and use it for gViewerInput + filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default); + // Don't reset mUsesTemporaryFile, it will be reset at cleanup stage + } + + LLXMLNodePtr output_node = new LLXMLNode("keys", false); + LLXUIParser parser; + parser.writeXUI(output_node, keys); + + // Write the resulting XML to file + if (!output_node->isNull()) + { + LLFILE *fp = LLFile::fopen(filename, "w"); + if (fp != NULL) + { + LLXMLNode::writeHeaderToFile(fp); + output_node->writeToFile(fp); + fclose(fp); + } + } + // Now force a rebind for keyboard + if (gDirUtilp->fileExists(filename)) + { + // Ideally instead of rebinding immediately we should shedule + // the rebind since single file can have multiple handlers, + // one per mode, saving simultaneously. + // Or whatever uses LLKeyConflictHandler should control the process. + gViewerInput.loadBindingsXML(filename); + } + } + } + + if (!temporary) + { + // will remove any temporary file if there were any + clearUnsavedChanges(); + } +} + +LLKeyData LLKeyConflictHandler::getDefaultControl(const std::string &control_name, U32 index) +{ + if (control_name.empty()) + { + return LLKeyData(); + } + if (mLoadMode == MODE_SAVED_SETTINGS) + { + LLControlVariablePtr var = gSavedSettings.getControl(control_name); + if (var) + { + return LLKeyBind(var->getDefault()).getKeyData(index); + } + return LLKeyData(); + } + else + { + control_map_t::iterator iter = mDefaultsMap.find(control_name); + if (iter != mDefaultsMap.end()) + { + return iter->second.mKeyBind.getKeyData(index); + } + return LLKeyData(); + } +} + +void LLKeyConflictHandler::resetToDefault(const std::string &control_name, U32 index) +{ + if (control_name.empty()) + { + return; + } + LLKeyData data = getDefaultControl(control_name, index); + + if (data != mControlsMap[control_name].getKeyData(index)) + { + // reset controls that might have been switched to our current control + removeConflicts(data, mControlsMap[control_name].mConflictMask); + mControlsMap[control_name].setKeyData(data, index); + } +} + +void LLKeyConflictHandler::resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts) +{ + if (control_name.empty()) + { + return; + } + if (mLoadMode == MODE_SAVED_SETTINGS) + { + LLControlVariablePtr var = gSavedSettings.getControl(control_name); + if (var) + { + LLKeyBind bind(var->getDefault()); + if (!ignore_conflicts) + { + for (S32 i = 0; i < bind.getDataCount(); ++i) + { + removeConflicts(bind.getKeyData(i), mControlsMap[control_name].mConflictMask); + } + } + mControlsMap[control_name].mKeyBind = bind; + } + else + { + mControlsMap[control_name].mKeyBind.clear(); + } + } + else + { + control_map_t::iterator iter = mDefaultsMap.find(control_name); + if (iter != mDefaultsMap.end()) + { + if (!ignore_conflicts) + { + for (S32 i = 0; i < iter->second.mKeyBind.getDataCount(); ++i) + { + removeConflicts(iter->second.mKeyBind.getKeyData(i), mControlsMap[control_name].mConflictMask); + } + } + mControlsMap[control_name].mKeyBind = iter->second.mKeyBind; + } + else + { + mControlsMap[control_name].mKeyBind.clear(); + } + } +} + +void LLKeyConflictHandler::resetToDefault(const std::string &control_name) +{ + // reset specific binding without ignoring conflicts + resetToDefaultAndResolve(control_name, false); +} + +void LLKeyConflictHandler::resetToDefaults(ESourceMode mode) +{ + if (mode == MODE_SAVED_SETTINGS) + { + control_map_t::iterator iter = mControlsMap.begin(); + control_map_t::iterator end = mControlsMap.end(); + + for (; iter != end; ++iter) + { + resetToDefaultAndResolve(iter->first, true); + } + } + else + { + mControlsMap.clear(); + generatePlaceholders(mode); + mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end()); + } + + mHasUnsavedChanges = true; +} + +void LLKeyConflictHandler::resetToDefaults() +{ + if (!empty()) + { + resetToDefaults(mLoadMode); + } + else + { + // not optimal since: + // 1. We are not sure that mLoadMode was set + // 2. We are not sure if there are any changes in comparison to default + // 3. We are loading 'current' only to replace it + // but it is reliable and works Todo: consider optimizing. + loadFromSettings(mLoadMode); + resetToDefaults(mLoadMode); + } +} + +void LLKeyConflictHandler::clear() +{ + if (clearUnsavedChanges()) + { + // temporary file was removed, this means we were using it and need to reload keyboard's bindings + resetKeyboardBindings(); + } + mControlsMap.clear(); + mDefaultsMap.clear(); +} + +// static +void LLKeyConflictHandler::resetKeyboardBindings() +{ + // Try to load User's bindings first + std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default); + if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) + { + // Failed to load custom bindings, try default ones + key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename_default); + if (!gViewerInput.loadBindingsXML(key_bindings_file)) + { + LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; + } + } +} + +void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode) +{ + // These controls are meant to cause conflicts when user tries to assign same control somewhere else + // also this can be used to pre-record controls that should not conflict or to assign conflict groups/masks + /*registerTemporaryControl(CONTROL_RESERVED_MENU, CLICK_RIGHT, KEY_NONE, MASK_NONE, 0); + registerTemporaryControl(CONTROL_DELETE, CLICK_NONE, KEY_DELETE, MASK_NONE, 0);*/ +} + +bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask) +{ + if (conlict_mask == CONFLICT_NOTHING) + { + // Can't conflict + return true; + } + std::map<std::string, S32> conflict_list; + control_map_t::iterator cntrl_iter = mControlsMap.begin(); + control_map_t::iterator cntrl_end = mControlsMap.end(); + for (; cntrl_iter != cntrl_end; ++cntrl_iter) + { + S32 index = cntrl_iter->second.mKeyBind.findKeyData(data); + if (index >= 0 + && cntrl_iter->second.mConflictMask != CONFLICT_NOTHING + && (cntrl_iter->second.mConflictMask & conlict_mask) != 0) + { + if (cntrl_iter->second.mAssignable) + { + // Potentially we can have multiple conflict flags conflicting + // including unassignable keys. + // So record the conflict and find all others before doing any changes. + // Assume that there is only one conflict per bind + conflict_list[cntrl_iter->first] = index; + } + else + { + return false; + } + } + } + + std::map<std::string, S32>::iterator cnflct_iter = conflict_list.begin(); + std::map<std::string, S32>::iterator cnflct_end = conflict_list.end(); + for (; cnflct_iter != cnflct_end; ++cnflct_iter) + { + mControlsMap[cnflct_iter->first].mKeyBind.resetKeyData(cnflct_iter->second); + } + return true; +} + +void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_name, EMouseClickType mouse, KEY key, MASK mask, U32 conflict_mask) +{ + LLKeyConflict *type_data = &mControlsMap[control_name]; + type_data->mAssignable = false; + type_data->mConflictMask = conflict_mask; + type_data->mKeyBind.addKeyData(mouse, key, mask, false); +} + +bool LLKeyConflictHandler::clearUnsavedChanges() +{ + bool result = false; + mHasUnsavedChanges = false; + + if (mUsesTemporaryFile) + { + mUsesTemporaryFile = false; + sTemporaryFileUseCount--; + if (!sTemporaryFileUseCount) + { + result = clearTemporaryFile(); + } + // else: might be usefull to overwrite content of temp file with defaults + // but at the moment there is no such need + } + return result; +} + +//static +bool LLKeyConflictHandler::clearTemporaryFile() +{ + // At the moment single file needs five handlers (one per mode), so doing this + // will remove file for all hadlers + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary); + if (gDirUtilp->fileExists(filename)) + { + LLFile::remove(filename); + return true; + } + return false; +} + diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h new file mode 100644 index 0000000000000000000000000000000000000000..84730e4d4f27b3b75ca8014ef73423caf58f7582 --- /dev/null +++ b/indra/newview/llkeyconflict.h @@ -0,0 +1,156 @@ +/** + * @file llkeyconflict.h + * @brief + * + * $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$ + */ + +#ifndef LL_LLKEYCONFLICT_H +#define LL_LLKEYCONFLICT_H + +#include "llkeybind.h" +#include "llviewerinput.h" + + +class LLKeyConflict +{ +public: + LLKeyConflict() : mAssignable(true), mConflictMask(U32_MAX) {} //temporary assignable, don't forget to change once all keys are recorded + LLKeyConflict(bool assignable, U32 conflict_mask) + : mAssignable(assignable), mConflictMask(conflict_mask) {} + LLKeyConflict(const LLKeyBind &bind, bool assignable, U32 conflict_mask) + : mAssignable(assignable), mConflictMask(conflict_mask), mKeyBind(bind) {} + + LLKeyData getPrimaryKeyData() { return mKeyBind.getKeyData(0); } + LLKeyData getKeyData(U32 index) { return mKeyBind.getKeyData(index); } + void setPrimaryKeyData(const LLKeyData& data) { mKeyBind.replaceKeyData(data, 0); } + void setKeyData(const LLKeyData& data, U32 index) { mKeyBind.replaceKeyData(data, index); } + bool canHandle(EMouseClickType mouse, KEY key, MASK mask) { return mKeyBind.canHandle(mouse, key, mask); } + + LLKeyBind mKeyBind; + bool mAssignable; // whether user can change key or key simply acts as placeholder + U32 mConflictMask; +}; + +class LLKeyConflictHandler +{ +public: + + enum ESourceMode // partially repeats e_keyboard_mode + { + MODE_FIRST_PERSON, + MODE_THIRD_PERSON, + MODE_EDIT_AVATAR, + MODE_SITTING, + MODE_SAVED_SETTINGS, // for settings from saved settings + MODE_COUNT + }; + + const U32 CONFLICT_NOTHING = 0; + // at the moment this just means that key will conflict with everything that is identical + const U32 CONFLICT_ANY = U32_MAX; + + // Note: missed selection and edition commands (would be really nice to go through selection via MB4/5 or wheel) + + LLKeyConflictHandler(); + LLKeyConflictHandler(ESourceMode mode); + ~LLKeyConflictHandler(); + + bool canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask); + bool canHandleKey(const std::string &control_name, KEY key, MASK mask); + bool canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask); + bool canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask); //Just for convinience + bool canAssignControl(const std::string &control_name); + static bool isReservedByMenu(const KEY &key, const MASK &mask); + static bool isReservedByMenu(const LLKeyData &data); + bool registerControl(const std::string &control_name, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts? + + LLKeyData getControl(const std::string &control_name, U32 data_index); + + // localized string + static std::string getStringFromKeyData(const LLKeyData& keydata); + std::string getControlString(const std::string &control_name, U32 data_index); + + // Load single control, overrides existing one if names match + void loadFromControlSettings(const std::string &name); + // Drops any changes loads controls with ones from 'saved settings' or from xml + void loadFromSettings(ESourceMode load_mode); + + // Saves settings to 'saved settings' or to xml + // If 'temporary' is set, function will save settings to temporary + // file and reload input bindings from temporary file. + // 'temporary' does not support gSavedSettings, those are handled + // by preferences, so 'temporary' is such case will simply not + // reset mHasUnsavedChanges + void saveToSettings(bool apply_temporary = false); + + LLKeyData getDefaultControl(const std::string &control_name, U32 data_index); + // Resets keybinding to default variant from 'saved settings' or xml + void resetToDefault(const std::string &control_name, U32 index); + void resetToDefault(const std::string &control_name); + // resets current mode to defaults + void resetToDefaults(); + + bool empty() { return mControlsMap.empty(); } + void clear(); + + // reloads bindings from last valid user's xml or from default xml + // to keyboard's handler + static void resetKeyboardBindings(); + + bool hasUnsavedChanges() { return mHasUnsavedChanges; } + void setLoadMode(ESourceMode mode) { mLoadMode = mode; } + ESourceMode getLoadMode() { return mLoadMode; } + +private: + void resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts); + void resetToDefaults(ESourceMode mode); + + // at the moment these kind of control is not savable, but takes part will take part in conflict resolution + void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask); + + typedef std::map<std::string, LLKeyConflict> control_map_t; + void loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination); + bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination); + void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values + // returns false in case user is trying to reuse control that can't be reassigned + bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask); + + // removes flags and removes temporary file, returns 'true' if file was removed + bool clearUnsavedChanges(); + // return true if there was a file to remove + static bool clearTemporaryFile(); + + control_map_t mControlsMap; + control_map_t mDefaultsMap; + bool mHasUnsavedChanges; + ESourceMode mLoadMode; + + // To implement 'apply immediately'+revert on cancel, class applies changes to temporary file + // but this only works for settings from keybndings files (key_bindings.xml) + // saved setting rely onto external mechanism of preferences floater + bool mUsesTemporaryFile; + static S32 sTemporaryFileUseCount; +}; + + +#endif // LL_LLKEYCONFLICT_H diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 42b5ff38907cced1436c0c22f186c946d8aa1629..802e4941e634c6137f7faee131054389ac7b7ce1 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -1100,9 +1100,7 @@ void LLLocationInputCtrl::changeLocationPresentation() //change location presentation only if user does not select/paste anything and //human-readable region name is being displayed - std::string text = mTextEntry->getText(); - LLStringUtil::trim(text); - if(!mTextEntry->hasSelection() && text == mHumanReadableLocation) + if(!mTextEntry->hasSelection() && mTextEntry->getText() == mHumanReadableLocation) { //needs unescaped one LLSLURL slurl; diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 453bf17b119bf9fef9c8eff362a8272d498dd61e..0c64531783b6cfa32c73626fd068dc313bfb4373 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -67,6 +67,8 @@ const std::string LL_IM_FROM("from"); const std::string LL_IM_FROM_ID("from_id"); const std::string LL_TRANSCRIPT_FILE_EXTENSION("txt"); +const std::string GROUP_CHAT_SUFFIX(" (group)"); + const static char IM_SYMBOL_SEPARATOR(':'); const static std::string IM_SEPARATOR(std::string() + IM_SYMBOL_SEPARATOR + " "); const static std::string NEW_LINE("\n"); @@ -355,7 +357,7 @@ void LLLogChat::saveHistory(const std::string& filename, } // static -void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params) +void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params, bool is_group) { if (file_name.empty()) { @@ -368,10 +370,25 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ if (!fptr) { - fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (is_group) + { + std::string old_name(file_name); + old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size()); + fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "r"); + if (fptr) + { + fclose(fptr); + LLFile::copy(LLLogChat::makeLogFileName(old_name), LLLogChat::makeLogFileName(file_name)); + } + fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r"); + } if (!fptr) { - return; //No previous conversation with this name. + fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (!fptr) + { + return; //No previous conversation with this name. + } } } @@ -1053,12 +1070,28 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LL if (!fptr) { - fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + bool is_group = load_params.has("is_group") ? load_params["is_group"].asBoolean() : false; + if (is_group) + { + std::string old_name(file_name); + old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size()); + fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "r"); + if (fptr) + { + fclose(fptr); + LLFile::copy(LLLogChat::makeLogFileName(old_name), LLLogChat::makeLogFileName(file_name)); + } + fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r"); + } if (!fptr) { - mNewLoad = false; - (*mLoadEndSignal)(messages, file_name); - return; //No previous conversation with this name. + fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ + if (!fptr) + { + mNewLoad = false; + (*mLoadEndSignal)(messages, file_name); + return; //No previous conversation with this name. + } } } diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index b71a34ae0aaac1a7b6d3cc3c0b05637b8417e35f..8b7fe14e1684ad4c6c4b7596a09aaa948978f154 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -106,7 +106,7 @@ class LLLogChat : public LLSingleton<LLLogChat> static void getListOfTranscriptFiles(std::vector<std::string>& list); static void getListOfTranscriptBackupFiles(std::vector<std::string>& list_of_transcriptions); - static void loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params = LLSD()); + static void loadChatHistory(const std::string& file_name, std::list<LLSD>& messages, const LLSD& load_params = LLSD(), bool is_group = false); typedef boost::signals2::signal<void ()> save_history_signal_t; boost::signals2::connection setSaveHistorySignal(const save_history_signal_t::slot_type& cb); @@ -196,6 +196,7 @@ class LLChatLogParser virtual ~LLChatLogParser() {}; }; +extern const std::string GROUP_CHAT_SUFFIX; // LLSD map lookup constants extern const std::string LL_IM_TIME; //("time"); diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp index eca34c0d4d47ae1bf7521ee1175b370bd1ddfba9..22cedf450eb9a009c2fe422573ba51ad9d634d80 100644 --- a/indra/newview/llloginhandler.cpp +++ b/indra/newview/llloginhandler.cpp @@ -139,8 +139,11 @@ LLPointer<LLCredential> LLLoginHandler::initializeLoginInfo() // so try to load it from the UserLoginInfo result = loadSavedUserLoginInfo(); if (result.isNull()) - { - result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + { + // Since legacy viewer store login info one per grid, newer viewers have to + // reuse same information to remember last user and for compatibility, + // but otherwise login info is stored in separate map in gSecAPIHandler + result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); } return result; diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 805c25508fe4f5d5e9da0d6550846154b7cdc73d..aa0c7fb73bcbe46d739a249d0fe020fedbf1c28a 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -1294,6 +1294,11 @@ void LLMarketplaceData::setSLMDataFetched(U32 status) } } +bool LLMarketplaceData::isSLMDataFetched() +{ + return mMarketPlaceDataFetched == MarketplaceFetchCodes::MARKET_FETCH_DONE; +} + // Creation / Deletion / Update // Methods publicly called bool LLMarketplaceData::createListing(const LLUUID& folder_id) diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h index ec312baca395b65116c27286cfe73c53ec7f3229..fee9225f77c5905d04f5530e2694c14ece2e1c74 100644 --- a/indra/newview/llmarketplacefunctions.h +++ b/indra/newview/llmarketplacefunctions.h @@ -204,7 +204,9 @@ class LLMarketplaceData void setDataFetchedSignal(const status_updated_signal_t::slot_type& cb); void setSLMDataFetched(U32 status); U32 getSLMDataFetched() { return mMarketPlaceDataFetched; } - + + bool isSLMDataFetched(); + // High level create/delete/set Marketplace data: each method returns true if the function succeeds, false if error bool createListing(const LLUUID& folder_id); bool activateListing(const LLUUID& folder_id, bool activate, S32 depth = -1); diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index b399ab9bc4f5d0dd11e7c36b834b6fae06ab3c78..0affe8efb4b51f15efb57b8560ade06b949b4e08 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -202,11 +202,28 @@ BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks ) { if (LLPanel::handleScrollWheel(x, y, clicks)) return TRUE; if (mMediaSource && mMediaSource->hasMedia()) - mMediaSource->getMediaPlugin()->scrollEvent(0, clicks, gKeyboard->currentMask(TRUE)); + { + convertInputCoords(x, y); + mMediaSource->scrollWheel(x, y, 0, clicks, gKeyboard->currentMask(TRUE)); + } return TRUE; } +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + if (LLPanel::handleScrollHWheel(x, y, clicks)) return TRUE; + if (mMediaSource && mMediaSource->hasMedia()) + { + convertInputCoords(x, y); + mMediaSource->scrollWheel(x, y, clicks, 0, gKeyboard->currentMask(TRUE)); + } + + return TRUE; +} + //////////////////////////////////////////////////////////////////////////////// // virtual BOOL LLMediaCtrl::handleToolTip(S32 x, S32 y, MASK mask) diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 11400c82742cb624df901cf222ffe36f846ba2a8..958c76f2613fb855a94ab3a4a0b03ce24ccb3f92 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -92,6 +92,7 @@ class LLMediaCtrl : virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + virtual BOOL handleScrollHWheel( S32 x, S32 y, S32 clicks ); virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); // navigation diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 31e3d408d7d95c5cd440ad38c3d9429e1fc6deaf..ce41e2bd3519c380f8c8f1b394dee64f4e90b3e8 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1889,7 +1889,7 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p std::string mesh_string((char*)data, data_size); stream.str(mesh_string); } - catch (std::bad_alloc) + catch (std::bad_alloc&) { // out of memory, we won't be able to process this mesh return MESH_OUT_OF_MEMORY; @@ -2772,7 +2772,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp if (observer) { - observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason); + observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason, body["error"]); } } else @@ -2805,7 +2805,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp if (observer) { - observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason); + observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason, body["error"]); } } } diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 8fc356c9282045bbe75dded7e944ac2c95aa083d..54409a69943fb201bec596cfad43d18d656fefa5 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -574,6 +574,8 @@ BOOL LLPanelStandStopFlying::postBuild() //mStopFlyingButton->setCommitCallback(boost::bind(&LLFloaterMove::setFlyingMode, FALSE)); mStopFlyingButton->setCommitCallback(boost::bind(&LLPanelStandStopFlying::onStopFlyingButtonClick, this)); mStopFlyingButton->setVisible(FALSE); + + gViewerWindow->setOnWorldViewRectUpdated(boost::bind(&LLPanelStandStopFlying::updatePosition, this)); return TRUE; } diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index fc1039b37257467074a5dfb53eaf9f5dd6cfe843..112da556825647b5d5d1ed65cd2119c8f576b1e2 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -354,7 +354,7 @@ void LLNetMap::draw() LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color; - unknown_relative_z = positions[i].mdV[VZ] == COARSEUPDATE_MAX_Z && + unknown_relative_z = positions[i].mdV[VZ] >= COARSEUPDATE_MAX_Z && camera_position.mV[VZ] >= COARSEUPDATE_MAX_Z; LLWorldMapView::drawAvatar( diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp index b405d3dca24ef96598dd8c2c0173a2f05dc2824a..6a79a0c68cf9224f873f5332187fda8a24e33443 100644 --- a/indra/newview/llnotificationlistitem.cpp +++ b/indra/newview/llnotificationlistitem.cpp @@ -262,6 +262,7 @@ std::set<std::string> LLTransactionNotificationListItem::getTypes() std::set<std::string> types; types.insert("PaymentReceived"); types.insert("PaymentSent"); + types.insert("UploadPayment"); return types; } diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index b2b6de94b3bedf231fbedfebb19c5d11371875df..12b46e9bb23cdd96221b60f294214c6421abf13e 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1364,6 +1364,7 @@ void LLOutfitGallery::onSelectPhoto(LLUUID selected_outfit_id) texture_floaterp->setOnFloaterCommitCallback(boost::bind(&LLOutfitGallery::onTexturePickerCommit, this, _1, _2)); texture_floaterp->setOnUpdateImageStatsCallback(boost::bind(&LLOutfitGallery::onTexturePickerUpdateImageStats, this, _1)); texture_floaterp->setLocalTextureEnabled(FALSE); + texture_floaterp->setCanApply(false, true); } floaterp->openFloater(); diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp index 7f6c065bb9f8b3ba62d16d8e9a21b2d9e4e7fd0c..e9fe493d7ec294b11df910feb00d62b0310fa8aa 100644 --- a/indra/newview/lloutputmonitorctrl.cpp +++ b/indra/newview/lloutputmonitorctrl.cpp @@ -245,11 +245,11 @@ void LLOutputMonitorCtrl::draw() // virtual BOOL LLOutputMonitorCtrl::handleMouseUp(S32 x, S32 y, MASK mask) { - if (mSpeakerId != gAgentID && !mShowParticipantsSpeaking) + if (mSpeakerId != gAgentID) { LLFloaterReg::showInstance("floater_voice_volume", LLSD().with("avatar_id", mSpeakerId)); } - else if(mShowParticipantsSpeaking) + else if (mShowParticipantsSpeaking) { LLFloaterReg::showInstance("chat_voice", LLSD()); } diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 6d0c30fbf336917ddb1630503979178e3ff26464..c0342eef4e4de70ffe4e5b4101364c5a93946024 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -764,6 +764,7 @@ void LLPanelClassifiedEdit::processProperties(void* data, EAvatarProcessorType t setClassifiedName(c_info->name); setDescription(c_info->description); setSnapshotId(c_info->snapshot_id); + setParcelId(c_info->parcel_id); setPosGlobal(c_info->pos_global); setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 0efb234015b52252f745b9798eefdd92ac554b3b..e3d75d5604d7368ed74d093e5444d325d9d67a58 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1153,7 +1153,7 @@ void LLPanelGroupMembersSubTab::onInviteMember(void *userdata) void LLPanelGroupMembersSubTab::handleInviteMember() { - LLFloaterGroupInvite::showForGroup(mGroupID); + LLFloaterGroupInvite::showForGroup(mGroupID, NULL, false); } void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata) diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index e253557797de8c149132fbffcde1d8a1fce24e05..fd76a360444116063c8d9b5bc3d84d15d7e6010b 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -41,7 +41,6 @@ #include "llcommandhandler.h" // for secondlife:///app/login/ #include "llcombobox.h" #include "llviewercontrol.h" -#include "llfloaterpreference.h" #include "llfocusmgr.h" #include "lllineeditor.h" #include "llnotificationsutil.h" @@ -77,6 +76,60 @@ LLPanelLogin *LLPanelLogin::sInstance = NULL; BOOL LLPanelLogin::sCapslockDidNotification = FALSE; BOOL LLPanelLogin::sCredentialSet = FALSE; +// Helper functions + +LLPointer<LLCredential> load_user_credentials(std::string &user_key) +{ + if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid())) + { + // user_key should be of "name Resident" format + return gSecAPIHandler->loadFromCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), user_key); + } + else + { + // legacy (or legacy^2, since it also tries to load from settings) + return gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + } +} + +// keys are lower case to be case insensitive so they are not always +// identical to names which retain user input, like: +// "AwEsOmE Resident" -> "awesome_resident" +std::string get_user_key_from_name(const std::string &username) +{ + std::string key = username; + LLStringUtil::trim(key); + LLStringUtil::toLower(key); + if (!LLGridManager::getInstance()->isSystemGrid()) + { + size_t separator_index = username.find_first_of(" "); + if (separator_index == username.npos) + { + // CRED_IDENTIFIER_TYPE_ACCOUNT + return key; + } + } + // CRED_IDENTIFIER_TYPE_AGENT + size_t separator_index = username.find_first_of(" ._"); + std::string first = username.substr(0, separator_index); + std::string last; + if (separator_index != username.npos) + { + last = username.substr(separator_index + 1, username.npos); + LLStringUtil::trim(last); + } + else + { + // ...on Linden grids, single username users as considered to have + // last name "Resident" + // *TODO: Make login.cgi support "account_name" like above + last = "resident"; + } + + key = first + "_" + last; + return key; +} + class LLLoginLocationAutoHandler : public LLCommandHandler { public: @@ -168,6 +221,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, mCallback(callback), mCallbackData(cb_data), mListener(new LLPanelLoginListener(this)), + mFirstLoginThisInstall(gSavedSettings.getBOOL("FirstLoginThisInstall")), mUsernameLength(0), mPasswordLength(0), mLocationLength(0), @@ -186,7 +240,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, login_holder->addChild(this); } - if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + if (mFirstLoginThisInstall) { buildFromFile( "panel_login_first.xml"); } @@ -206,35 +260,39 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, sendChildToBack(getChildView("forgot_password_text")); sendChildToBack(getChildView("sign_up_text")); - LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo"); - updateLocationSelectorsVisibility(); // separate so that it can be called from preferences - favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); - favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); - - LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo"); - server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); - - // Load all of the grids, sorted, and then add a bar and the current grid at the top - server_choice_combo->removeall(); - - std::string current_grid = LLGridManager::getInstance()->getGrid(); - std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); - for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); - grid_choice != known_grids.end(); - grid_choice++) - { - if (!grid_choice->first.empty() && current_grid != grid_choice->first) - { - LL_DEBUGS("AppInit")<<"adding "<<grid_choice->first<<LL_ENDL; - server_choice_combo->add(grid_choice->second, grid_choice->first); - } - } - server_choice_combo->sortByName(); - LL_DEBUGS("AppInit")<<"adding current "<<current_grid<<LL_ENDL; - server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), - current_grid, - ADD_TOP); - server_choice_combo->selectFirstItem(); + std::string current_grid = LLGridManager::getInstance()->getGrid(); + if (!mFirstLoginThisInstall) + { + LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo"); + updateLocationSelectorsVisibility(); // separate so that it can be called from preferences + favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); + favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); + + LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo"); + server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); + + // Load all of the grids, sorted, and then add a bar and the current grid at the top + server_choice_combo->removeall(); + + std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); + for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); + grid_choice != known_grids.end(); + grid_choice++) + { + if (!grid_choice->first.empty() && current_grid != grid_choice->first) + { + LL_DEBUGS("AppInit") << "adding " << grid_choice->first << LL_ENDL; + server_choice_combo->add(grid_choice->second, grid_choice->first); + } + } + server_choice_combo->sortByName(); + + LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL; + server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), + current_grid, + ADD_TOP); + server_choice_combo->selectFirstItem(); + } LLSLURL start_slurl(LLStartUp::getStartSLURL()); // The StartSLURL might have been set either by an explicit command-line @@ -297,14 +355,30 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, loadLoginPage(); LLComboBox* username_combo(getChild<LLComboBox>("username_combo")); - username_combo->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this)); + username_combo->setTextChangedCallback(boost::bind(&LLPanelLogin::onUserNameTextEnty, this)); // STEAM-14: When user presses Enter with this field in focus, initiate login - username_combo->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); + username_combo->setCommitCallback(boost::bind(&LLPanelLogin::onUserListCommit, this)); + username_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); username_combo->setKeystrokeOnEsc(TRUE); + + if (!mFirstLoginThisInstall) + { + LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name"); + remember_name->setCommitCallback(boost::bind(&LLPanelLogin::onRememberUserCheck, this)); + } } void LLPanelLogin::addFavoritesToStartLocation() { + if (mFirstLoginThisInstall) + { + // first login panel has no favorites, just update name length and buttons + std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple(); + mUsernameLength = user_defined_name.length(); + updateLoginButtons(); + return; + } + // Clear the combo. LLComboBox* combo = getChild<LLComboBox>("start_location_combo"); if (!combo) return; @@ -316,14 +390,14 @@ void LLPanelLogin::addFavoritesToStartLocation() // Load favorites into the combo. std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple(); + LLStringUtil::trim(user_defined_name); LLStringUtil::toLower(user_defined_name); - std::replace(user_defined_name.begin(), user_defined_name.end(), '.', ' '); std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites_" + LLGridManager::getInstance()->getGrid() + ".xml"); std::string old_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); mUsernameLength = user_defined_name.length(); updateLoginButtons(); - std::string::size_type index = user_defined_name.find(' '); + std::string::size_type index = user_defined_name.find_first_of(" ._"); if (index != std::string::npos) { std::string username = user_defined_name.substr(0, index); @@ -332,6 +406,10 @@ void LLPanelLogin::addFavoritesToStartLocation() { user_defined_name = username; } + else + { + user_defined_name = username + " " + lastname; + } } LLSD fav_llsd; @@ -377,6 +455,10 @@ void LLPanelLogin::addFavoritesToStartLocation() } break; } + if (combo->getValue().asString().empty()) + { + combo->selectFirstItem(); + } } LLPanelLogin::~LLPanelLogin() @@ -442,24 +524,6 @@ void LLPanelLogin::giveFocus() } } -// static -void LLPanelLogin::showLoginWidgets() -{ - if (sInstance) - { - // *NOTE: Mani - This may or may not be obselete code. - // It seems to be part of the defunct? reg-in-client project. - sInstance->getChildView("login_widgets")->setVisible( true); - LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); - - // *TODO: Append all the usual login parameters, like first_login=Y etc. - std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage(); - web_browser->navigateTo( splash_screen_url, "text/html" ); - LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo"); - username_combo->setFocus(TRUE); - } -} - // static void LLPanelLogin::show(const LLRect &rect, void (*callback)(S32 option, void* user_data), @@ -480,9 +544,55 @@ void LLPanelLogin::show(const LLRect &rect, gFocusMgr.setDefaultKeyboardFocus(sInstance); } +//static +void LLPanelLogin::populateFields(LLPointer<LLCredential> credential, bool remember_user, bool remember_psswrd) +{ + if (!sInstance) + { + LL_WARNS() << "Attempted fillFields with no login view shown" << LL_ENDL; + return; + } + LLUICtrl* remember_check = sInstance->getChild<LLUICtrl>("remember_check"); + remember_check->setValue(remember_psswrd); + if (sInstance->mFirstLoginThisInstall) + { + // no list to populate + setFields(credential, remember_psswrd); + } + else + { + sInstance->getChild<LLUICtrl>("remember_name")->setValue(remember_user); + sInstance->populateUserList(credential, remember_psswrd); + remember_check->setEnabled(remember_user); + } +} + +//static +void LLPanelLogin::resetFields() +{ + if (!sInstance) + { + // class not existing at this point might happen since this + // function is used to reset list in case of changes by external sources + return; + } + if (sInstance->mFirstLoginThisInstall) + { + // no list to populate + LL_WARNS() << "Shouldn't happen, user should have no ability to modify list on first install" << LL_ENDL; + } + else + { + LLUICtrl* remember_check = sInstance->getChild<LLUICtrl>("remember_check"); + bool remember_psswrd = remember_check->getValue(); + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(cred, remember_psswrd); + } +} + // static void LLPanelLogin::setFields(LLPointer<LLCredential> credential, - BOOL remember) + bool remember_psswrd) { if (!sInstance) { @@ -492,13 +602,15 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential, sCredentialSet = TRUE; LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL; - LLSD identifier = credential->getIdentifier(); - if((std::string)identifier["type"] == "agent") + LLSD identifier = credential.notNull() ? credential->getIdentifier() : LLSD(); + + if(identifier.has("type") && (std::string)identifier["type"] == "agent") { + // not nessesary for panel_login.xml, needed for panel_login_first.xml std::string firstname = identifier["first_name"].asString(); std::string lastname = identifier["last_name"].asString(); std::string login_id = firstname; - if (!lastname.empty() && lastname != "Resident") + if (!lastname.empty() && lastname != "Resident" && lastname != "resident") { // support traditional First Last name SLURLs login_id += " "; @@ -506,22 +618,23 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential, } sInstance->getChild<LLComboBox>("username_combo")->setLabel(login_id); } - else if((std::string)identifier["type"] == "account") + else if(identifier.has("type") && (std::string)identifier["type"] == "account") { sInstance->getChild<LLComboBox>("username_combo")->setLabel((std::string)identifier["account_name"]); } else { - sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string()); + sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string()); } + sInstance->addFavoritesToStartLocation(); // if the password exists in the credential, set the password field with // a filler to get some stars - LLSD authenticator = credential->getAuthenticator(); + LLSD authenticator = credential.notNull() ? credential->getAuthenticator() : LLSD(); LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL; if(authenticator.isMap() && authenticator.has("secret") && - (authenticator["secret"].asString().size() > 0) && remember) + (authenticator["secret"].asString().size() > 0) && remember_psswrd) { // This is a MD5 hex digest of a password. @@ -537,36 +650,25 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential, { sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string()); } - sInstance->getChild<LLUICtrl>("remember_check")->setValue(remember); } - // static void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, - BOOL& remember) + bool& remember_user, + bool& remember_psswrd) { if (!sInstance) { LL_WARNS() << "Attempted getFields with no login view shown" << LL_ENDL; return; } - - // load the credential so we can pass back the stored password or hash if the user did - // not modify the password field. - - credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); LLSD identifier = LLSD::emptyMap(); LLSD authenticator = LLSD::emptyMap(); - - if(credential.notNull()) - { - authenticator = credential->getAuthenticator(); - } - std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString(); - LLStringUtil::trim(username); + std::string username = sInstance->getChild<LLComboBox>("username_combo")->getValue().asString(); std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString(); + LLStringUtil::trim(username); LL_INFOS("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL; // determine if the username is a first/last form or not. @@ -586,6 +688,14 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR; authenticator["secret"] = password; } + else + { + credential = load_user_credentials(username); + if (credential.notNull()) + { + authenticator = credential->getAuthenticator(); + } + } } else { @@ -597,7 +707,7 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, if (separator_index != username.npos) { last = username.substr(separator_index+1, username.npos); - LLStringUtil::trim(last); + LLStringUtil::trim(last); } else { @@ -625,10 +735,28 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, pass.hex_digest(md5pass); authenticator["secret"] = md5pass; } + else + { + std::string key = first + "_" + last; + LLStringUtil::toLower(key); + credential = load_user_credentials(key); + if (credential.notNull()) + { + authenticator = credential->getAuthenticator(); + } + } } } credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator); - remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); + remember_psswrd = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); + if (!sInstance->mFirstLoginThisInstall) + { + remember_user = sInstance->getChild<LLUICtrl>("remember_name")->getValue(); + } + else + { + remember_user = true; + } } @@ -898,8 +1026,8 @@ void LLPanelLogin::onClickConnect(void *) { sCredentialSet = FALSE; LLPointer<LLCredential> cred; - BOOL remember; - getFields(cred, remember); + bool remember_1, remember_2; + getFields(cred, remember_1, remember_2); std::string identifier_type; cred->identifierType(identifier_type); LLSD allowed_credential_types; @@ -952,6 +1080,57 @@ void LLPanelLogin::onClickSignUp(void*) } } +// static +void LLPanelLogin::onUserNameTextEnty(void*) +{ + sInstance->mPasswordModified = true; + sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string()); + sInstance->addFavoritesToStartLocation(); //will call updateLoginButtons() +} + +// static +void LLPanelLogin::onUserListCommit(void*) +{ + if (sInstance) + { + LLComboBox* username_combo(sInstance->getChild<LLComboBox>("username_combo")); + static S32 ind = -1; + if (ind != username_combo->getCurrentIndex()) + { + std::string user_key = username_combo->getSelectedValue(); + LLPointer<LLCredential> cred = gSecAPIHandler->loadFromCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), user_key); + bool remember_psswrd = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); + setFields(cred, remember_psswrd); + sInstance->mPasswordModified = false; + } + else + { + std::string pass = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString(); + if (pass.empty()) + { + sInstance->giveFocus(); + } + else + { + onClickConnect(NULL); + } + } + } +} + +// static +void LLPanelLogin::onRememberUserCheck(void*) +{ + if (sInstance) + { + LLCheckBoxCtrl* remember_name(sInstance->getChild<LLCheckBoxCtrl>("remember_name")); + LLCheckBoxCtrl* remember_psswrd(sInstance->getChild<LLCheckBoxCtrl>("remember_check")); + + bool remember = remember_name->getValue().asBoolean(); + remember_psswrd->setEnabled(remember); + } +} + // static void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) { @@ -979,9 +1158,11 @@ void LLPanelLogin::updateServer() // for that grid and set them to the UI. if(!sInstance->areCredentialFieldsDirty()) { - LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); - bool remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); - sInstance->setFields(credential, remember); + // populate dropbox and setFields + bool remember_psswrd = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); + // Note: following call is related to initializeLoginInfo() + LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(credential, remember_psswrd); } // update the login panel links @@ -1011,14 +1192,63 @@ void LLPanelLogin::updateLoginButtons() LLButton* login_btn = getChild<LLButton>("connect_btn"); login_btn->setEnabled(mUsernameLength != 0 && mPasswordLength != 0); + + if (!mFirstLoginThisInstall) + { + LLComboBox* user_combo = getChild<LLComboBox>("username_combo"); + LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name"); + remember_name->setEnabled(user_combo->getCurrentIndex() == -1); + } +} + +void LLPanelLogin::populateUserList(LLPointer<LLCredential> credential, bool remember_psswrd) +{ + LLComboBox* user_combo = getChild<LLComboBox>("username_combo"); + user_combo->removeall(); + user_combo->clear(); + + if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid())) + { + LLSecAPIHandler::credential_map_t credencials; + gSecAPIHandler->loadCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), credencials); + + LLSecAPIHandler::credential_map_t::iterator cr_iter = credencials.begin(); + LLSecAPIHandler::credential_map_t::iterator cr_end = credencials.end(); + while (cr_iter != cr_end) + { + if (cr_iter->second.notNull()) // basic safety in case of future changes + { + // cr_iter->first == user_id , to be able to be find it in case we select it + user_combo->add(LLPanelLogin::getUserName(cr_iter->second), cr_iter->first, ADD_BOTTOM, TRUE); + } + cr_iter++; + } + + if (credential.isNull() || !user_combo->setSelectedByValue(LLSD(credential->userID()), true)) + { + // selection failed, just deselect whatever might be selected + user_combo->setValue(std::string()); + } + else + { + setFields(credential, remember_psswrd); + } + } + else + { + if (credential.notNull()) + { + user_combo->add(LLPanelLogin::getUserName(credential), credential->userID(), ADD_BOTTOM, TRUE); + setFields(credential, remember_psswrd); + } + } } + void LLPanelLogin::onSelectServer() { // The user twiddled with the grid choice ui. // apply the selection to the grid setting. - LLPointer<LLCredential> credential; - LLComboBox* server_combo = getChild<LLComboBox>("server_combo"); LLSD server_combo_val = server_combo->getSelectedValue(); LL_INFOS("AppInit") << "grid "<<server_combo_val.asString()<< LL_ENDL; @@ -1048,13 +1278,13 @@ void LLPanelLogin::onSelectServer() { std::string location = location_combo->getValue().asString(); LLSLURL slurl(location); // generata a slurl from the location combo contents - if ( slurl.getType() == LLSLURL::LOCATION - && slurl.getGrid() != LLGridManager::getInstance()->getGrid() - ) + if (location.empty() + || (slurl.getType() == LLSLURL::LOCATION + && slurl.getGrid() != LLGridManager::getInstance()->getGrid()) + ) { // the grid specified by the location is not this one, so clear the combo location_combo->setCurrentByIndex(0); // last location on the new grid - location_combo->setTextEntry(LLStringUtil::null); } } break; @@ -1077,3 +1307,34 @@ bool LLPanelLogin::getShowFavorites() { return gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); } + +// static +std::string LLPanelLogin::getUserName(LLPointer<LLCredential> &cred) +{ + if (cred.isNull()) + { + return "unknown"; + } + const LLSD &ident = cred->getIdentifier(); + + if (!ident.isMap()) + { + return "unknown"; + } + else if ((std::string)ident["type"] == "agent") + { + std::string second_name = ident["last_name"]; + if (second_name == "resident" || second_name == "Resident") + { + return (std::string)ident["first_name"]; + } + return (std::string)ident["first_name"] + " " + (std::string)ident["last_name"]; + } + else if ((std::string)ident["type"] == "account") + { + return LLCacheName::cleanFullName((std::string)ident["account_name"]); + } + + return "unknown"; +} + diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index c633582d89886ea55e669e942d65222079a85fbd..3eb7b68949f1ed9b3d6a37c9d3454971231185b3 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -55,9 +55,9 @@ class LLPanelLogin: void (*callback)(S32 option, void* user_data), void* callback_data); - static void setFields(LLPointer<LLCredential> credential, BOOL remember); - - static void getFields(LLPointer<LLCredential>& credential, BOOL& remember); + static void populateFields(LLPointer<LLCredential> credential, bool remember_user, bool remember_psswrd); + static void resetFields(); + static void getFields(LLPointer<LLCredential>& credential, bool& remember_user, bool& remember_psswrd); static BOOL isCredentialSet() { return sCredentialSet; } @@ -72,8 +72,6 @@ class LLPanelLogin: void setSiteIsAlive( bool alive ); - void showLoginWidgets(); - static void loadLoginPage(); static void giveFocus(); static void setAlwaysRefresh(bool refresh); @@ -88,6 +86,9 @@ class LLPanelLogin: // called from prefs when initializing panel static bool getShowFavorites(); + // extract name from cred in a format apropriate for username field + static std::string getUserName(LLPointer<LLCredential> &cred); + private: friend class LLPanelLoginListener; void addFavoritesToStartLocation(); @@ -95,11 +96,16 @@ class LLPanelLogin: void onSelectServer(); void onLocationSLURL(); + static void setFields(LLPointer<LLCredential> credential, bool remember_psswrd); + static void onClickConnect(void*); static void onClickNewAccount(void*); static void onClickVersion(void*); static void onClickForgotPassword(void*); static void onClickSignUp(void*); + static void onUserNameTextEnty(void*); + static void onUserListCommit(void*); + static void onRememberUserCheck(void*); static void onPassKey(LLLineEditor* caller, void* user_data); static void updateServerCombo(); @@ -107,6 +113,7 @@ class LLPanelLogin: boost::scoped_ptr<LLPanelLoginListener> mListener; void updateLoginButtons(); + void populateUserList(LLPointer<LLCredential> credential, bool remember_psswrd); void (*mCallback)(S32 option, void *userdata); void* mCallbackData; diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index 2dca55514d2b39f3ed28dc6464a3ce478e7c4e25..b654e928e2effb2ae4cd04f0c10a71d648bab450 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -43,6 +43,7 @@ #include "llbutton.h" #include "lltextbox.h" #include "llviewermedia.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewerregion.h" #include "llviewermediafocus.h" @@ -83,10 +84,11 @@ LLPanelNearByMedia::LLPanelNearByMedia() { mHoverTimer.stop(); - mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay"); + // This is just an initial value, mParcelAudioAutoStart does not affect ParcelMediaAutoPlayEnable + mParcelAudioAutoStart = gSavedSettings.getS32("ParcelMediaAutoPlayEnable") != 0 + && gSavedSettings.getBOOL("MediaTentativeAutoPlay"); - gSavedSettings.getControl(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING)->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2)); + gSavedSettings.getControl("ParcelMediaAutoPlayEnable")->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2)); mCommitCallbackRegistrar.add("MediaListCtrl.EnableAll", boost::bind(&LLPanelNearByMedia::onClickEnableAll, this)); mCommitCallbackRegistrar.add("MediaListCtrl.DisableAll", boost::bind(&LLPanelNearByMedia::onClickDisableAll, this)); @@ -177,9 +179,18 @@ BOOL LLPanelNearByMedia::postBuild() void LLPanelNearByMedia::handleMediaAutoPlayChanged(const LLSD& newvalue) { - // update mParcelAudioAutoStart if AUTO_PLAY_MEDIA_SETTING changes - mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay"); + // update mParcelAudioAutoStartMode if "ParcelMediaAutoPlayEnable" changes + S32 value = gSavedSettings.getS32("ParcelMediaAutoPlayEnable"); + mParcelAudioAutoStart = value != 0 + && gSavedSettings.getBOOL("MediaTentativeAutoPlay"); + + LLViewerParcelAskPlay *inst = LLViewerParcelAskPlay::getInstance(); + if (value == 2 && !inst->hasData()) + { + // Init if nessesary + inst->loadSettings(); + } + inst->cancelNotification(); } /*virtual*/ diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 961e2599472ff47caf1c00aef286dbc41f916319..2ef82d0cf907c0702a9370e51eb03498e07a1f99 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -675,6 +675,12 @@ void LLPanelPlaces::onShowOnMapButtonClicked() } else if (mPlaceInfoType == LANDMARK_INFO_TYPE) { + if (mItem.isNull()) + { + LL_WARNS() << "NULL landmark item" << LL_ENDL; + llassert(mItem.notNull()); + return; + } LLLandmark* landmark = gLandmarkList.getAsset(mItem->getAssetUUID()); if (!landmark) return; diff --git a/indra/newview/llpanelpresetspulldown.cpp b/indra/newview/llpanelpresetspulldown.cpp index 9b4dc5474a08e644ed0121935862e91ebb848958..0ca4a83779d41eb974853f9ae98475828cad52df 100644 --- a/indra/newview/llpanelpresetspulldown.cpp +++ b/indra/newview/llpanelpresetspulldown.cpp @@ -33,8 +33,8 @@ #include "llbutton.h" #include "lltabcontainer.h" +#include "llfloater.h" #include "llfloaterreg.h" -#include "llfloaterpreference.h" #include "llpresetsmanager.h" #include "llsliderctrl.h" #include "llscrolllistctrl.h" diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index 8105beae1b971cf4c81c19dae7142c1d1b3e5571..3c74aed734ccdd7864fa7dc55387b99e48a2d382 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -547,17 +547,17 @@ void LLPanelPrimMediaControls::updateShape() switch (mScrollState) { case SCROLL_UP: - media_impl->scrollWheel(0, -1, MASK_NONE); + media_impl->scrollWheel(0, 0, 0, -1, MASK_NONE); break; case SCROLL_DOWN: - media_impl->scrollWheel(0, 1, MASK_NONE); + media_impl->scrollWheel(0, 0, 0, 1, MASK_NONE); break; case SCROLL_LEFT: - media_impl->scrollWheel(1, 0, MASK_NONE); + media_impl->scrollWheel(0, 0, 1, 0, MASK_NONE); // media_impl->handleKeyHere(KEY_LEFT, MASK_NONE); break; case SCROLL_RIGHT: - media_impl->scrollWheel(-1, 0, MASK_NONE); + media_impl->scrollWheel(0, 0, -1, 0, MASK_NONE); // media_impl->handleKeyHere(KEY_RIGHT, MASK_NONE); break; case SCROLL_NONE: @@ -1134,7 +1134,7 @@ void LLPanelPrimMediaControls::onScrollUp(void* user_data) if(impl) { - impl->scrollWheel(0, -1, MASK_NONE); + impl->scrollWheel(0, 0, 0, -1, MASK_NONE); } } void LLPanelPrimMediaControls::onScrollUpHeld(void* user_data) @@ -1151,7 +1151,7 @@ void LLPanelPrimMediaControls::onScrollRight(void* user_data) if(impl) { - impl->scrollWheel(-1, 0, MASK_NONE); + impl->scrollWheel(0, 0, -1, 0, MASK_NONE); // impl->handleKeyHere(KEY_RIGHT, MASK_NONE); } } @@ -1170,7 +1170,7 @@ void LLPanelPrimMediaControls::onScrollLeft(void* user_data) if(impl) { - impl->scrollWheel(1, 0, MASK_NONE); + impl->scrollWheel(0, 0, 1, 0, MASK_NONE); // impl->handleKeyHere(KEY_LEFT, MASK_NONE); } } @@ -1189,7 +1189,7 @@ void LLPanelPrimMediaControls::onScrollDown(void* user_data) if(impl) { - impl->scrollWheel(0, 1, MASK_NONE); + impl->scrollWheel(0, 0, 0, 1, MASK_NONE); } } void LLPanelPrimMediaControls::onScrollDownHeld(void* user_data) diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 735eaa423dc6a5f5ef2bf5fed0eec1d76b37ce8f..58bc0493388ed69123c308e0c34240c5109191d3 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -82,8 +82,11 @@ #include <boost/bind.hpp> -// "Features" Tab +const F32 DEFAULT_GRAVITY_MULTIPLIER = 1.f; +const F32 DEFAULT_DENSITY = 1000.f; + +// "Features" Tab BOOL LLPanelVolume::postBuild() { // Flexible Objects Parameters @@ -830,7 +833,7 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data) // static void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) { - //LLPanelObject* self = (LLPanelObject*) userdata; + LLPanelVolume* self = (LLPanelVolume*)userdata; LLComboBox* box = (LLComboBox*) ctrl; if (box) @@ -841,6 +844,19 @@ void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) if (material_name != LEGACY_FULLBRIGHT_DESC) { U8 material_code = LLMaterialTable::basic.getMCode(material_name); + if (self) + { + LLViewerObject* objectp = self->mObject; + if (objectp) + { + objectp->setPhysicsGravity(DEFAULT_GRAVITY_MULTIPLIER); + objectp->setPhysicsFriction(LLMaterialTable::basic.getFriction(material_code)); + //currently density is always set to 1000 serverside regardless of chosen material, + //actual material density should be used here, if this behavior change + objectp->setPhysicsDensity(DEFAULT_DENSITY); + objectp->setPhysicsRestitution(LLMaterialTable::basic.getRestitution(material_code)); + } + } LLSelectMgr::getInstance()->selectionSetMaterial(material_code); } } diff --git a/indra/newview/llpanelvolumepulldown.cpp b/indra/newview/llpanelvolumepulldown.cpp index 6792137350bd01292537f6c33238a3a74830ad2d..f063d8427283b670a1f732f8691b9947e3040de3 100644 --- a/indra/newview/llpanelvolumepulldown.cpp +++ b/indra/newview/llpanelvolumepulldown.cpp @@ -140,7 +140,7 @@ void LLPanelVolumePulldown::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl) bool music_enabled = getChild<LLCheckBoxCtrl>("enable_music")->get(); bool media_enabled = getChild<LLCheckBoxCtrl>("enable_media")->get(); - getChild<LLCheckBoxCtrl>("media_auto_play_btn")->setEnabled(music_enabled || media_enabled); + getChild<LLCheckBoxCtrl>("media_auto_play_combo")->setEnabled(music_enabled || media_enabled); } } diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 1533a2746952765787b5130195ce7b5467f7f691..2f534ac2456eb9690c6892d9dde30ab652e9d895 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -367,6 +367,7 @@ void LLPreviewNotecard::onLoadComplete(LLVFS *vfs, previewEditor->makePristine(); BOOL modifiable = preview->canModify(preview->mObjectID, preview->getItem()); preview->setEnabled(modifiable); + preview->syncExternal(); preview->mAssetStatus = PREVIEW_ASSET_LOADED; } else @@ -503,10 +504,6 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem, bool sync) } editor->makePristine(); - if (sync) - { - syncExternal(); - } const LLInventoryItem* item = getItem(); // save it out to database if (item) @@ -755,6 +752,7 @@ void LLPreviewNotecard::openInExternalEditor() // Start watching file changes. mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLPreviewNotecard::onExternalChange, this, _1)); + mLiveFile->ignoreNextUpdate(); mLiveFile->addToEventTimer(); // Open it in external editor. diff --git a/indra/newview/llrecentpeople.h b/indra/newview/llrecentpeople.h index 1b4295ddad9509bec5e03f0e332981db889bd8ad..18b669ff4fc81be07d5f47d1a1c78dee5aeae1e5 100644 --- a/indra/newview/llrecentpeople.h +++ b/indra/newview/llrecentpeople.h @@ -53,7 +53,7 @@ class LLRecentPeople: public LLSingleton<LLRecentPeople>, public LLOldEvents::LL LLSINGLETON_EMPTY_CTOR(LLRecentPeople); LOG_CLASS(LLRecentPeople); public: - typedef std::map <LLUUID, F32> id_to_time_map_t; + typedef std::map <LLUUID, F64> id_to_time_map_t; typedef boost::signals2::signal<void ()> signal_t; /** diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp index 72d7cf1e4522eebcf56bfb455976d79dd7abc000..10e510b8428a777587476c42062ef26004bb58e8 100644 --- a/indra/newview/llsecapi.cpp +++ b/indra/newview/llsecapi.cpp @@ -64,7 +64,7 @@ void initializeSecHandler() { handler->init(); } - catch (LLProtectedDataException e) + catch (LLProtectedDataException& e) { exception_msg = e.what(); } diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index d207f3b5b78a5d072696eb58197eb8d7928c3cea..c0f0a367c75a5efd7be869bf177768703391ceb4 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -464,7 +464,19 @@ class LLSecAPIHandler : public LLThreadSafeRefCount // delete a protected data item from the store virtual void deleteProtectedData(const std::string& data_type, const std::string& data_id)=0; - + + // persist data in a protected store's map + virtual void addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data)=0; + + // remove data from protected store's map + virtual void removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem)=0; + +public: virtual LLPointer<LLCredential> createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator)=0; @@ -474,6 +486,38 @@ class LLSecAPIHandler : public LLThreadSafeRefCount virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator)=0; virtual void deleteCredential(LLPointer<LLCredential> cred)=0; + + // has map of credentials declared as specific storage + virtual bool hasCredentialMap(const std::string& storage, + const std::string& grid)=0; + + // load map of credentials from specific storage + typedef std::map<std::string, LLPointer<LLCredential> > credential_map_t; + virtual void loadCredentialMap(const std::string& storage, + const std::string& grid, + credential_map_t& credential_map)=0; + + // load single username from map of credentials from specific storage + virtual LLPointer<LLCredential> loadFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid)=0; + + // add item to map of credentials from specific storage + virtual void addToCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred, + bool save_authenticator)=0; + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred)=0; + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid)=0; + + virtual void removeCredentialMap(const std::string& storage, + const std::string& grid)=0; }; diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 9ab9e4a1a24b15775d63915375b61533bc904291..a8bb54a90ed0949640506ff5a6709e4178e48fdd 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -52,6 +52,7 @@ #include "llmachineid.h" +static const std::string DEFAULT_CREDENTIAL_STORAGE = "credential"; // 128 bits of salt data... #define STORE_SALT_SIZE 16 @@ -1533,6 +1534,38 @@ void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type, mProtectedDataMap[data_type][data_id] = data; } +// persist data in a protected store's map +void LLSecAPIBasicHandler::addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data) +{ + if (!mProtectedDataMap.has(data_type) || !mProtectedDataMap[data_type].isMap()) { + mProtectedDataMap[data_type] = LLSD::emptyMap(); + } + + if (!mProtectedDataMap[data_type].has(data_id) || !mProtectedDataMap[data_type][data_id].isMap()) { + mProtectedDataMap[data_type][data_id] = LLSD::emptyMap(); + } + + mProtectedDataMap[data_type][data_id][map_elem] = data; +} + +// remove data from protected store's map +void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem) +{ + if (mProtectedDataMap.has(data_type) && + mProtectedDataMap[data_type].isMap() && + mProtectedDataMap[data_type].has(data_id) && + mProtectedDataMap[data_type][data_id].isMap() && + mProtectedDataMap[data_type][data_id].has(map_elem)) + { + mProtectedDataMap[data_type][data_id].erase(map_elem); + } +} + // // Create a credential object from an identifier and authenticator. credentials are // per grid. @@ -1545,10 +1578,10 @@ LLPointer<LLCredential> LLSecAPIBasicHandler::createCredential(const std::string return result; } -// Load a credential from the credential store, given the grid +// Load a credential from default credential store, given the grid LLPointer<LLCredential> LLSecAPIBasicHandler::loadCredential(const std::string& grid) { - LLSD credential = getProtectedData("credential", grid); + LLSD credential = getProtectedData(DEFAULT_CREDENTIAL_STORAGE, grid); LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid); if(credential.isMap() && credential.has("identifier")) @@ -1603,7 +1636,7 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool sav credential["authenticator"] = cred->getAuthenticator(); } LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL; - setProtectedData("credential", cred->getGrid(), credential); + setProtectedData(DEFAULT_CREDENTIAL_STORAGE, cred->getGrid(), credential); //*TODO: If we're saving Agni credentials, should we write the // credentials to the legacy password.dat/etc? _writeProtectedData(); @@ -1613,11 +1646,137 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool sav void LLSecAPIBasicHandler::deleteCredential(LLPointer<LLCredential> cred) { LLSD undefVal; - deleteProtectedData("credential", cred->getGrid()); + deleteProtectedData(DEFAULT_CREDENTIAL_STORAGE, cred->getGrid()); cred->setCredentialData(undefVal, undefVal); _writeProtectedData(); } +// has map of credentials declared as specific storage +bool LLSecAPIBasicHandler::hasCredentialMap(const std::string& storage, const std::string& grid) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD credential = getProtectedData(storage, grid); + + return credential.isMap(); +} + +// Load map of credentials from specified credential store, given the grid +void LLSecAPIBasicHandler::loadCredentialMap(const std::string& storage, const std::string& grid, credential_map_t& credential_map) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD credential = getProtectedData(storage, grid); + if (credential.isMap()) + { + LLSD::map_const_iterator crd_it = credential.beginMap(); + for (; crd_it != credential.endMap(); crd_it++) + { + LLSD::String name = crd_it->first; + const LLSD &link_map = crd_it->second; + LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid); + if (link_map.has("identifier")) + { + LLSD identifier = link_map["identifier"]; + LLSD authenticator; + if (link_map.has("authenticator")) + { + authenticator = link_map["authenticator"]; + } + result->setCredentialData(identifier, authenticator); + } + credential_map[name] = result; + } + } +} + +LLPointer<LLCredential> LLSecAPIBasicHandler::loadFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid); + + LLSD credential = getProtectedData(storage, grid); + if (credential.isMap() && credential.has(userkey) && credential[userkey].has("identifier")) + { + LLSD identifier = credential[userkey]["identifier"]; + LLSD authenticator; + if (credential[userkey].has("authenticator")) + { + authenticator = credential[userkey]["authenticator"]; + } + result->setCredentialData(identifier, authenticator); + } + + return result; +} + +// add item to map of credentials from specific storage +void LLSecAPIBasicHandler::addToCredentialMap(const std::string& storage, LLPointer<LLCredential> cred, bool save_authenticator) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + std::string user_id = cred->userID(); + LLSD credential = LLSD::emptyMap(); + credential["identifier"] = cred->getIdentifier(); + if (save_authenticator) + { + credential["authenticator"] = cred->getAuthenticator(); + } + LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL; + addToProtectedMap(storage, cred->getGrid(), user_id, credential); + + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, LLPointer<LLCredential> cred) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD undefVal; + removeFromProtectedMap(storage, cred->getGrid(), cred->userID()); + cred->setCredentialData(undefVal, undefVal); + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD undefVal; + LLPointer<LLCredential> cred = loadFromCredentialMap(storage, grid, userkey); + removeFromProtectedMap(storage, grid, userkey); + cred->setCredentialData(undefVal, undefVal); + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeCredentialMap(const std::string& storage, const std::string& grid) +{ + deleteProtectedData(storage, grid); + _writeProtectedData(); +} + // load the legacy hash for agni, and decrypt it given the // mac address std::string LLSecAPIBasicHandler::_legacyLoadPassword() @@ -1656,15 +1815,18 @@ std::string LLSecAPIBasicCredential::userID() const } else if ((std::string)mIdentifier["type"] == "agent") { - return (std::string)mIdentifier["first_name"] + "_" + (std::string)mIdentifier["last_name"]; + std::string id = (std::string)mIdentifier["first_name"] + "_" + (std::string)mIdentifier["last_name"]; + LLStringUtil::toLower(id); + return id; } else if ((std::string)mIdentifier["type"] == "account") { - return (std::string)mIdentifier["account_name"]; + std::string id = (std::string)mIdentifier["account_name"]; + LLStringUtil::toLower(id); + return id; } return "unknown"; - } // return a printable user identifier diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index c35617f564905983659c33b45db4032b71b37635..426b5d392aeb1f3ecfc23fcd20318afbbb56e1cb 100644 --- a/indra/newview/llsechandler_basic.h +++ b/indra/newview/llsechandler_basic.h @@ -211,8 +211,9 @@ class LLSecAPIBasicCredential : public LLCredential public: LLSecAPIBasicCredential(const std::string& grid) : LLCredential(grid) {} virtual ~LLSecAPIBasicCredential() {} - // return a value representing the user id, (could be guid, name, whatever) - virtual std::string userID() const; + // return a value representing the user id, used for server and voice + // (could be guid, name in format "name_resident", whatever) + virtual std::string userID() const; // printible string identifying the credential. virtual std::string asString() const; @@ -246,7 +247,10 @@ class LLSecAPIBasicHandler : public LLSecAPIHandler // exists, it'll be loaded. If not, one will be created (but not // persisted) virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id); - + + // protectedData functions technically should be pretected or private, + // they are not because of llsechandler_basic_test imlementation + // persist data in a protected store virtual void setProtectedData(const std::string& data_type, const std::string& data_id, @@ -259,19 +263,64 @@ class LLSecAPIBasicHandler : public LLSecAPIHandler // delete a protected data item from the store virtual void deleteProtectedData(const std::string& data_type, const std::string& data_id); - + + // persist data in a protected store's map + virtual void addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data); + + // remove data from protected store's map + virtual void removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem); + // credential management routines virtual LLPointer<LLCredential> createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator); - + + // load single credencial from default storage virtual LLPointer<LLCredential> loadCredential(const std::string& grid); + // save credencial to default storage virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator); virtual void deleteCredential(LLPointer<LLCredential> cred); - + + // has map of credentials declared as specific storage + virtual bool hasCredentialMap(const std::string& storage, + const std::string& grid); + + // load map of credentials from specific storage + virtual void loadCredentialMap(const std::string& storage, + const std::string& grid, + credential_map_t& credential_map); + + // load single username from map of credentials from specific storage + virtual LLPointer<LLCredential> loadFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid); + + // add item to map of credentials from specific storage + virtual void addToCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred, + bool save_authenticator); + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred); + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid); + + virtual void removeCredentialMap(const std::string& storage, + const std::string& grid); + + protected: void _readProtectedData(); void _writeProtectedData(); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 90f8f84ea4c3081e5b994975f2538a4305391e50..f849fecaf6a15332fba06bb1d7da522f2fa6ff0a 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -153,6 +153,53 @@ struct LLDeRezInfo // Imports // +//----------------------------------------------------------------------------- +// ~LLSelectionCallbackData() +//----------------------------------------------------------------------------- + +LLSelectionCallbackData::LLSelectionCallbackData() +{ + LLSelectMgr *instance = LLSelectMgr::getInstance(); + LLObjectSelectionHandle selection = instance->getSelection(); + if (!selection->getNumNodes()) + { + return; + } + mSelectedObjects = new LLObjectSelection(); + + for (LLObjectSelection::iterator iter = selection->begin(); + iter != selection->end();) + { + LLObjectSelection::iterator curiter = iter++; + + LLSelectNode *nodep = *curiter; + LLViewerObject* objectp = nodep->getObject(); + + if (!objectp) + { + mSelectedObjects->mSelectType = SELECT_TYPE_WORLD; + } + else + { + LLSelectNode* new_nodep = new LLSelectNode(*nodep); + mSelectedObjects->addNode(new_nodep); + + if (objectp->isHUDAttachment()) + { + mSelectedObjects->mSelectType = SELECT_TYPE_HUD; + } + else if (objectp->isAttachment()) + { + mSelectedObjects->mSelectType = SELECT_TYPE_ATTACHMENT; + } + else + { + mSelectedObjects->mSelectType = SELECT_TYPE_WORLD; + } + } + } +} + // // Functions @@ -4119,20 +4166,20 @@ void LLSelectMgr::packMultipleUpdate(LLSelectNode* node, void *user_data) if (type & UPD_POSITION) { - htonmemcpy(&data[offset], &(object->getPosition().mV), MVT_LLVector3, 12); + htolememcpy(&data[offset], &(object->getPosition().mV), MVT_LLVector3, 12); offset += 12; } if (type & UPD_ROTATION) { LLQuaternion quat = object->getRotation(); LLVector3 vec = quat.packToVector3(); - htonmemcpy(&data[offset], &(vec.mV), MVT_LLQuaternion, 12); + htolememcpy(&data[offset], &(vec.mV), MVT_LLQuaternion, 12); offset += 12; } if (type & UPD_SCALE) { //LL_INFOS() << "Sending object scale " << object->getScale() << LL_ENDL; - htonmemcpy(&data[offset], &(object->getScale().mV), MVT_LLVector3, 12); + htolememcpy(&data[offset], &(object->getScale().mV), MVT_LLVector3, 12); offset += 12; } gMessageSystem->addBinaryDataFast(_PREHASH_Data, data, offset); @@ -4475,9 +4522,19 @@ void LLSelectMgr::selectionSetObjectSaleInfo(const LLSaleInfo& sale_info) void LLSelectMgr::sendAttach(U8 attachment_point, bool replace) { - LLViewerObject* attach_object = mSelectedObjects->getFirstRootObject(); + sendAttach(mSelectedObjects, attachment_point, replace); +} + +void LLSelectMgr::sendAttach(LLObjectSelectionHandle selection_handle, U8 attachment_point, bool replace) +{ + if (selection_handle.isNull()) + { + return; + } - if (!attach_object || !isAgentAvatarValid() || mSelectedObjects->mSelectType != SELECT_TYPE_WORLD) + LLViewerObject* attach_object = selection_handle->getFirstRootObject(); + + if (!attach_object || !isAgentAvatarValid() || selection_handle->mSelectType != SELECT_TYPE_WORLD) { return; } @@ -4495,6 +4552,7 @@ void LLSelectMgr::sendAttach(U8 attachment_point, bool replace) } sendListToRegions( + selection_handle, "ObjectAttach", packAgentIDAndSessionAndAttachment, packObjectIDAndRotation, @@ -4506,6 +4564,7 @@ void LLSelectMgr::sendAttach(U8 attachment_point, bool replace) // After "ObjectAttach" server will unsubscribe us from properties updates // so either deselect objects or resend selection after attach packet reaches server // In case of build_mode LLPanelObjectInventory::refresh() will deal with selection + // Still unsubscribe even in case selection_handle is not current selection deselectAll(); } } @@ -5047,7 +5106,17 @@ void LLSelectMgr::packPermissions(LLSelectNode* node, void *user_data) void LLSelectMgr::sendListToRegions(const std::string& message_name, void (*pack_header)(void *user_data), void (*pack_body)(LLSelectNode* node, void *user_data), - void (*log_func)(LLSelectNode* node, void *user_data), + void (*log_func)(LLSelectNode* node, void *user_data), + void *user_data, + ESendType send_type) +{ + sendListToRegions(mSelectedObjects, message_name, pack_header, pack_body, log_func, user_data, send_type); +} +void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle, + const std::string& message_name, + void (*pack_header)(void *user_data), + void (*pack_body)(LLSelectNode* node, void *user_data), + void (*log_func)(LLSelectNode* node, void *user_data), void *user_data, ESendType send_type) { @@ -5073,7 +5142,7 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, return true; } } func; - getSelection()->applyToNodes(&func); + selected_handle->applyToNodes(&func); std::queue<LLSelectNode*> nodes_to_send; @@ -5116,25 +5185,25 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, { case SEND_ONLY_ROOTS: if(message_name == "ObjectBuy") - getSelection()->applyToRootNodes(&pushroots); + selected_handle->applyToRootNodes(&pushroots); else - getSelection()->applyToRootNodes(&pushall); + selected_handle->applyToRootNodes(&pushall); break; case SEND_INDIVIDUALS: - getSelection()->applyToNodes(&pushall); + selected_handle->applyToNodes(&pushall); break; case SEND_ROOTS_FIRST: // first roots... - getSelection()->applyToNodes(&pushroots); + selected_handle->applyToNodes(&pushroots); // then children... - getSelection()->applyToNodes(&pushnonroots); + selected_handle->applyToNodes(&pushnonroots); break; case SEND_CHILDREN_FIRST: // first children... - getSelection()->applyToNodes(&pushnonroots); + selected_handle->applyToNodes(&pushnonroots); // then roots... - getSelection()->applyToNodes(&pushroots); + selected_handle->applyToNodes(&pushroots); break; default: @@ -6686,8 +6755,7 @@ void LLSelectMgr::updateSelectionCenter() if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid()) { // reset hud ZOOM - gAgentCamera.mHUDTargetZoom = 1.f; - gAgentCamera.mHUDCurZoom = 1.f; + resetAgentHUDZoom(); } mShowSelection = FALSE; @@ -7060,8 +7128,11 @@ BOOL LLSelectMgr::setForceSelection(BOOL force) void LLSelectMgr::resetAgentHUDZoom() { - gAgentCamera.mHUDTargetZoom = 1.f; - gAgentCamera.mHUDCurZoom = 1.f; + if (gAgentCamera.mHUDTargetZoom != 1) + { + gAgentCamera.mHUDTargetZoom = 1.f; + gAgentCamera.mHUDCurZoom = 1.f; + } } void LLSelectMgr::getAgentHUDZoom(F32 &target_zoom, F32 ¤t_zoom) const diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 3e8bfdb00e597bf0953a493a2ab4c8542a7ce603..3bed484b588a0897fc2180c4d824ac738a787a3e 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -239,6 +239,7 @@ class LLObjectSelection : public LLRefCount { friend class LLSelectMgr; friend class LLSafeHandle<LLObjectSelection>; + friend class LLSelectionCallbackData; protected: ~LLObjectSelection(); @@ -396,6 +397,16 @@ extern template class LLSelectMgr* LLSingleton<class LLSelectMgr>::getInstance() // For use with getFirstTest() struct LLSelectGetFirstTest; +// temporary storage, Ex: to attach objects after autopilot +class LLSelectionCallbackData +{ +public: + LLSelectionCallbackData(); + LLObjectSelectionHandle getSelection() { return mSelectedObjects; } +private: + LLObjectSelectionHandle mSelectedObjects; +}; + class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr> { LLSINGLETON(LLSelectMgr); @@ -740,6 +751,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr> // canceled void sendBuy(const LLUUID& buyer_id, const LLUUID& category_id, const LLSaleInfo sale_info); void sendAttach(U8 attachment_point, bool replace); + void sendAttach(LLObjectSelectionHandle selection_handle, U8 attachment_point, bool replace); void sendDetach(); void sendDropAttachment(); void sendLink(); @@ -787,6 +799,13 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr> void (*log_func)(LLSelectNode* node, void *user_data), void *user_data, ESendType send_type); + void sendListToRegions( LLObjectSelectionHandle selected_handle, + const std::string& message_name, + void (*pack_header)(void *user_data), + void (*pack_body)(LLSelectNode* node, void *user_data), + void (*log_func)(LLSelectNode* node, void *user_data), + void *user_data, + ESendType send_type); static void packAgentID( void *); diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4eb76c9d89fe8d5cc68fef05f5910d33c4ecd348 --- /dev/null +++ b/indra/newview/llsetkeybinddialog.cpp @@ -0,0 +1,346 @@ +/** + * @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$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llsetkeybinddialog.h" + +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "lleventtimer.h" +#include "llfloaterreg.h" +#include "llfocusmgr.h" +#include "llkeyconflict.h" +#include "llviewercontrol.h" + +class LLSetKeyBindDialog::Updater : public LLEventTimer +{ +public: + + typedef boost::function<void(MASK)> callback_t; + + Updater(callback_t cb, F32 period, MASK mask) + :LLEventTimer(period), + mMask(mask), + mCallback(cb) + { + mEventTimer.start(); + } + + virtual ~Updater(){} + +protected: + BOOL tick() + { + mCallback(mMask); + // Deletes itseft after execution + return TRUE; + } + +private: + MASK mMask; + callback_t mCallback; +}; + +bool LLSetKeyBindDialog::sRecordKeys = false; + +LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key) + : LLModalDialog(key), + pParent(NULL), + mKeyFilterMask(DEFAULT_KEY_FILTER), + pUpdater(NULL), + mContextConeOpacity(0.f), + mContextConeInAlpha(0.f), + mContextConeOutAlpha(0.f), + mContextConeFadeTime(0.f) +{ + mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); + mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); + mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); +} + +LLSetKeyBindDialog::~LLSetKeyBindDialog() +{ +} + +//virtual +BOOL LLSetKeyBindDialog::postBuild() +{ + childSetAction("SetEmpty", onBlank, this); + childSetAction("Default", onDefault, this); + childSetAction("Cancel", onCancel, this); + getChild<LLUICtrl>("Cancel")->setFocus(TRUE); + + pCheckBox = getChild<LLCheckBoxCtrl>("apply_all"); + pDesription = getChild<LLTextBase>("descritption"); + + gFocusMgr.setKeystrokesOnly(TRUE); + + return TRUE; +} + +//virtual +void LLSetKeyBindDialog::onOpen(const LLSD& data) +{ + sRecordKeys = true; + LLModalDialog::onOpen(data); +} + +//virtual +void LLSetKeyBindDialog::onClose(bool app_quiting) +{ + sRecordKeys = false; + if (pParent) + { + pParent->onCancelKeyBind(); + pParent = NULL; + } + if (pUpdater) + { + // Doubleclick timer has't fired, delete it + delete pUpdater; + pUpdater = NULL; + } + LLModalDialog::onClose(app_quiting); +} + +void LLSetKeyBindDialog::drawFrustum() +{ + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha); +} + +//virtual +void LLSetKeyBindDialog::draw() +{ + drawFrustum(); + LLModalDialog::draw(); +} + +void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask) +{ + pParent = parent; + mFrustumOrigin = frustum_origin->getHandle(); + mKeyFilterMask = key_mask; + + std::string input; + if ((key_mask & ALLOW_MOUSE) != 0) + { + input = getString("mouse"); + } + if ((key_mask & ALLOW_KEYS) != 0) + { + if (!input.empty()) + { + input += ", "; + } + input += getString("keyboard"); + } + pDesription->setText(getString("basic_description")); + pDesription->setTextArg("[INPUT]", input); +} + +// static +bool LLSetKeyBindDialog::recordKey(KEY key, MASK mask) +{ + if (sRecordKeys) + { + LLSetKeyBindDialog* dialog = LLFloaterReg::getTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD()); + if (dialog && dialog->getVisible()) + { + return dialog->recordAndHandleKey(key, mask); + } + else + { + LL_WARNS() << "Key recording was set despite no open dialog" << LL_ENDL; + sRecordKeys = false; + } + } + return false; +} + +bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask) +{ + if ((key == 'Q' && mask == MASK_CONTROL) + || key == KEY_ESCAPE) + { + sRecordKeys = false; + closeFloater(); + return true; + } + + if (key == KEY_DELETE) + { + setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false); + sRecordKeys = false; + closeFloater(); + return false; + } + + // forbidden keys + if (key == KEY_NONE + || key == KEY_RETURN + || key == KEY_BACKSPACE) + { + return false; + } + + if ((mKeyFilterMask & ALLOW_MASKS) == 0 + && (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT)) + { + // mask by themself are not allowed + return false; + } + else if ((mKeyFilterMask & ALLOW_KEYS) == 0) + { + // basic keys not allowed + return false; + } + else if ((mKeyFilterMask & ALLOW_MASK_KEYS) == 0 && mask != 0) + { + // masked keys not allowed + return false; + } + + if (LLKeyConflictHandler::isReservedByMenu(key, mask)) + { + pDesription->setText(getString("reserved_by_menu")); + pDesription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key)); + return true; + } + + setKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean()); + sRecordKeys = false; + closeFloater(); + return true; +} + +BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) +{ + BOOL result = FALSE; + if (!pParent) + { + // we already processed 'down' event, this is 'up', consume + closeFloater(); + result = TRUE; + } + if (!result && clicktype == CLICK_LEFT) + { + // try handling buttons first + if (down) + { + result = LLView::handleMouseDown(x, y, mask); + } + else + { + result = LLView::handleMouseUp(x, y, mask); + } + if (result) + { + setFocus(TRUE); + gFocusMgr.setKeystrokesOnly(TRUE); + } + // ignore selection related combinations + else if (down && (mask & (MASK_SHIFT | MASK_CONTROL)) == 0) + { + // this can be a double click, wait a bit; + if (!pUpdater) + { + // Note: default doubleclick time is 500ms, but can stretch up to 5s + pUpdater = new Updater(boost::bind(&onClickTimeout, this, _1), 0.7f, mask); + result = TRUE; + } + } + } + + if (!result + && (clicktype != CLICK_LEFT) // subcases were handled above + && ((mKeyFilterMask & ALLOW_MOUSE) != 0) + && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported + && ((mKeyFilterMask & ALLOW_MASK_MOUSE) != 0 || mask == 0)) // reserved for selection + { + setKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean()); + result = TRUE; + if (!down) + { + // wait for 'up' event before closing + // alternative: set pUpdater + closeFloater(); + } + } + + return result; +} + +//static +void LLSetKeyBindDialog::onCancel(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + self->closeFloater(); +} + +//static +void LLSetKeyBindDialog::onBlank(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + // tmp needs 'no key' button + self->setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false); + self->closeFloater(); +} + +//static +void LLSetKeyBindDialog::onDefault(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + if (self->pParent) + { + self->pParent->onDefaultKeyBind(self->pCheckBox->getValue().asBoolean()); + self->pParent = NULL; + } + self->closeFloater(); +} + +//static +void LLSetKeyBindDialog::onClickTimeout(void* user_data, MASK mask) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + + // timer will delete itself after timeout + self->pUpdater = NULL; + + self->setKeyBind(CLICK_LEFT, KEY_NONE, mask, self->pCheckBox->getValue().asBoolean()); + self->closeFloater(); +} + +void LLSetKeyBindDialog::setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes) +{ + if (pParent) + { + pParent->onSetKeyBind(click, key, mask, all_modes); + pParent = NULL; + } +} + diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h new file mode 100644 index 0000000000000000000000000000000000000000..70190230e4d025ac15ea28f1b1794a4ee74a327b --- /dev/null +++ b/indra/newview/llsetkeybinddialog.h @@ -0,0 +1,105 @@ +/** + * @file llsetkeybinddialog.h + * @brief LLSetKeyBindDialog class definition + * + * $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$ + */ + + +#ifndef LL_LLSETKEYBINDDIALOG_H +#define LL_LLSETKEYBINDDIALOG_H + +#include "llmodaldialog.h" + +class LLCheckBoxCtrl; +class LLTextBase; + +// Filters for LLSetKeyBindDialog +static const U32 ALLOW_MOUSE = 1; +static const U32 ALLOW_MASK_MOUSE = 2; +static const U32 ALLOW_KEYS = 4; //keyboard +static const U32 ALLOW_MASK_KEYS = 8; +static const U32 ALLOW_MASKS = 16; +static const U32 DEFAULT_KEY_FILTER = ALLOW_MOUSE | ALLOW_MASK_MOUSE | ALLOW_KEYS | ALLOW_MASK_KEYS; + + +class LLKeyBindResponderInterface +{ +public: + virtual ~LLKeyBindResponderInterface() {}; + + virtual void onCancelKeyBind() = 0; + virtual void onDefaultKeyBind(bool all_modes) = 0; + // returns true if parent failed to set key due to key being in use + virtual bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes) = 0; +}; + +class LLSetKeyBindDialog : public LLModalDialog +{ +public: + LLSetKeyBindDialog(const LLSD& key); + ~LLSetKeyBindDialog(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& data); + /*virtual*/ void onClose(bool app_quiting); + /*virtual*/ void draw(); + + void setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask = DEFAULT_KEY_FILTER); + + // Wrapper around recordAndHandleKey + // It does not record, it handles, but handleKey function is already in use + static bool recordKey(KEY key, MASK mask); + + BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); + static void onCancel(void* user_data); + static void onBlank(void* user_data); + static void onDefault(void* user_data); + static void onClickTimeout(void* user_data, MASK mask); + + class Updater; + +private: + bool recordAndHandleKey(KEY key, MASK mask); + void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes); + LLKeyBindResponderInterface *pParent; + LLCheckBoxCtrl *pCheckBox; + LLTextBase *pDesription; + + U32 mKeyFilterMask; + Updater *pUpdater; + + static bool sRecordKeys; // for convinience and not to check instance each time + + // drawFrustum +private: + void drawFrustum(); + + LLHandle <LLView> mFrustumOrigin; + F32 mContextConeOpacity; + F32 mContextConeInAlpha; + F32 mContextConeOutAlpha; + F32 mContextConeFadeTime; +}; + + +#endif // LL_LLSETKEYBINDDIALOG_H diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index 2503e2a5e299d45d964dd5752b682577853b6ffd..d508621b41ff29e23bc6aaaf973e29416b4f556f 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -49,6 +49,29 @@ #include "llviewerregion.h" +class PropertiesChangedCallback : public LLInventoryCallback +{ +public: + PropertiesChangedCallback(LLHandle<LLPanel> sidepanel_handle, LLUUID &item_id, S32 id) + : mHandle(sidepanel_handle), mItemId(item_id), mId(id) + {} + + void fire(const LLUUID &inv_item) + { + // inv_item can be null for some reason + LLSidepanelItemInfo* sidepanel = dynamic_cast<LLSidepanelItemInfo*>(mHandle.get()); + if (sidepanel) + { + // sidepanel waits only for most recent update + sidepanel->onUpdateCallback(mItemId, mId); + } + } +private: + LLHandle<LLPanel> mHandle; + LLUUID mItemId; + S32 mId; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLItemPropertiesObserver // @@ -68,7 +91,7 @@ class LLItemPropertiesObserver : public LLInventoryObserver } virtual void changed(U32 mask); private: - LLSidepanelItemInfo* mFloater; + LLSidepanelItemInfo* mFloater; // Not a handle because LLSidepanelItemInfo is managing LLItemPropertiesObserver }; void LLItemPropertiesObserver::changed(U32 mask) @@ -115,7 +138,7 @@ class LLObjectInventoryObserver : public LLVOInventoryListener S32 serial_num, void* user_data); private: - LLSidepanelItemInfo* mFloater; + LLSidepanelItemInfo* mFloater; // Not a handle because LLSidepanelItemInfo is managing LLObjectInventoryObserver }; /*virtual*/ @@ -138,6 +161,7 @@ LLSidepanelItemInfo::LLSidepanelItemInfo(const LLPanel::Params& p) : LLSidepanelInventorySubpanel(p) , mItemID(LLUUID::null) , mObjectInventoryObserver(NULL) + , mUpdatePendingId(-1) { mPropertiesObserver = new LLItemPropertiesObserver(this); } @@ -168,19 +192,19 @@ BOOL LLSidepanelItemInfo::postBuild() // owner permissions // Permissions debug text // group permissions - getChild<LLUICtrl>("CheckShareWithGroup")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this)); + getChild<LLUICtrl>("CheckShareWithGroup")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1)); // everyone permissions - getChild<LLUICtrl>("CheckEveryoneCopy")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this)); + getChild<LLUICtrl>("CheckEveryoneCopy")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1)); // next owner permissions - getChild<LLUICtrl>("CheckNextOwnerModify")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this)); - getChild<LLUICtrl>("CheckNextOwnerCopy")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this)); - getChild<LLUICtrl>("CheckNextOwnerTransfer")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this)); + getChild<LLUICtrl>("CheckNextOwnerModify")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1)); + getChild<LLUICtrl>("CheckNextOwnerCopy")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1)); + getChild<LLUICtrl>("CheckNextOwnerTransfer")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitPermissions, this, _1)); // Mark for sale or not, and sale info - getChild<LLUICtrl>("CheckPurchase")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this)); + getChild<LLUICtrl>("CheckPurchase")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this, _1)); // Change sale type, and sale info - getChild<LLUICtrl>("ComboBoxSaleType")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this)); + getChild<LLUICtrl>("ComboBoxSaleType")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this, _1)); // "Price" label for edit - getChild<LLUICtrl>("Edit Cost")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this)); + getChild<LLUICtrl>("Edit Cost")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitSaleInfo, this, _1)); refresh(); return TRUE; } @@ -192,11 +216,16 @@ void LLSidepanelItemInfo::setObjectID(const LLUUID& object_id) // Start monitoring changes in the object inventory to update // selected inventory item properties in Item Profile panel. See STORM-148. startObjectInventoryObserver(); + mUpdatePendingId = -1; } void LLSidepanelItemInfo::setItemID(const LLUUID& item_id) { - mItemID = item_id; + if (mItemID != item_id) + { + mItemID = item_id; + mUpdatePendingId = -1; + } } const LLUUID& LLSidepanelItemInfo::getObjectID() const @@ -209,6 +238,15 @@ const LLUUID& LLSidepanelItemInfo::getItemID() const return mItemID; } +void LLSidepanelItemInfo::onUpdateCallback(const LLUUID& item_id, S32 received_update_id) +{ + if (mItemID == item_id && mUpdatePendingId == received_update_id) + { + mUpdatePendingId = -1; + refresh(); + } +} + void LLSidepanelItemInfo::reset() { LLSidepanelInventorySubpanel::reset(); @@ -242,24 +280,16 @@ void LLSidepanelItemInfo::refresh() "LabelItemName", "LabelItemDesc", "LabelCreatorName", - "LabelOwnerName", - "CheckOwnerModify", - "CheckOwnerCopy", - "CheckOwnerTransfer", - "CheckShareWithGroup", - "CheckEveryoneCopy", - "CheckNextOwnerModify", - "CheckNextOwnerCopy", - "CheckNextOwnerTransfer", - "CheckPurchase", - "Edit Cost" + "LabelOwnerName" }; for(size_t t=0; t<LL_ARRAY_SIZE(no_item_names); ++t) { getChildView(no_item_names[t])->setEnabled(false); } - + + setPropertiesFieldsEnabled(false); + const std::string hide_names[]={ "BaseMaskDebug", "OwnerMaskDebug", @@ -297,6 +327,11 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) llassert(item); if (!item) return; + if (mUpdatePendingId != -1) + { + return; + } + // do not enable the UI for incomplete items. BOOL is_complete = item->isFinished(); const BOOL cannot_restrict_permissions = LLInventoryType::cannotRestrictPermissions(item->getInventoryType()); @@ -726,6 +761,26 @@ void LLSidepanelItemInfo::stopObjectInventoryObserver() mObjectInventoryObserver = NULL; } +void LLSidepanelItemInfo::setPropertiesFieldsEnabled(bool enabled) +{ + const std::string fields[] = { + "CheckOwnerModify", + "CheckOwnerCopy", + "CheckOwnerTransfer", + "CheckShareWithGroup", + "CheckEveryoneCopy", + "CheckNextOwnerModify", + "CheckNextOwnerCopy", + "CheckNextOwnerTransfer", + "CheckPurchase", + "Edit Cost" + }; + for (size_t t = 0; t<LL_ARRAY_SIZE(fields); ++t) + { + getChildView(fields[t])->setEnabled(false); + } +} + void LLSidepanelItemInfo::onClickCreator() { LLViewerInventoryItem* item = findItem(); @@ -793,10 +848,18 @@ void LLSidepanelItemInfo::onCommitDescription() } } -// static -void LLSidepanelItemInfo::onCommitPermissions() +void LLSidepanelItemInfo::onCommitPermissions(LLUICtrl* ctrl) +{ + if (ctrl) + { + // will be enabled by response from server + ctrl->setEnabled(false); + } + updatePermissions(); +} + +void LLSidepanelItemInfo::updatePermissions() { - //LL_INFOS() << "LLSidepanelItemInfo::onCommitPermissions()" << LL_ENDL; LLViewerInventoryItem* item = findItem(); if(!item) return; @@ -884,19 +947,17 @@ void LLSidepanelItemInfo::onCommitPermissions() } // static -void LLSidepanelItemInfo::onCommitSaleInfo() +void LLSidepanelItemInfo::onCommitSaleInfo(LLUICtrl* ctrl) { + if (ctrl) + { + // will be enabled by response from server + ctrl->setEnabled(false); + } //LL_INFOS() << "LLSidepanelItemInfo::onCommitSaleInfo()" << LL_ENDL; updateSaleInfo(); } -// static -void LLSidepanelItemInfo::onCommitSaleType() -{ - //LL_INFOS() << "LLSidepanelItemInfo::onCommitSaleType()" << LL_ENDL; - updateSaleInfo(); -} - void LLSidepanelItemInfo::updateSaleInfo() { LLViewerInventoryItem* item = findItem(); @@ -977,7 +1038,12 @@ void LLSidepanelItemInfo::onCommitChanges(LLPointer<LLViewerInventoryItem> item) if (mObjectID.isNull()) { // This is in the agent's inventory. - item->updateServer(FALSE); + // Mark update as pending and wait only for most recent one in case user requested for couple + // Once update arrives or any of ids change drop pending id. + mUpdatePendingId++; + LLPointer<LLInventoryCallback> callback = new PropertiesChangedCallback(getHandle(), mItemID, mUpdatePendingId); + update_inventory_item(item.get(), callback); + //item->updateServer(FALSE); gInventory.updateItem(item); gInventory.notifyObservers(); } @@ -1002,6 +1068,7 @@ void LLSidepanelItemInfo::onCommitChanges(LLPointer<LLViewerInventoryItem> item) // prevents flashing in content tab and some duplicated request. object->dirtyInventory(); } + setPropertiesFieldsEnabled(false); } } } @@ -1030,7 +1097,6 @@ void LLSidepanelItemInfo::save() { onCommitName(); onCommitDescription(); - onCommitPermissions(); - onCommitSaleInfo(); - onCommitSaleType(); + updatePermissions(); + updateSaleInfo(); } diff --git a/indra/newview/llsidepaneliteminfo.h b/indra/newview/llsidepaneliteminfo.h index 74cf7afe3530707e6c3fc9d5ad0b7dbfacac168f..5f29254182f9dfd5934f8efc232e1494494ae187 100644 --- a/indra/newview/llsidepaneliteminfo.h +++ b/indra/newview/llsidepaneliteminfo.h @@ -57,6 +57,9 @@ class LLSidepanelItemInfo : public LLSidepanelInventorySubpanel const LLUUID& getObjectID() const; const LLUUID& getItemID() const; + // if received update and item id (from callback) matches internal ones, update UI + void onUpdateCallback(const LLUUID& item_id, S32 received_update_id); + protected: /*virtual*/ void refresh(); /*virtual*/ void save(); @@ -71,12 +74,16 @@ class LLSidepanelItemInfo : public LLSidepanelInventorySubpanel void startObjectInventoryObserver(); void stopObjectInventoryObserver(); + void setPropertiesFieldsEnabled(bool enabled); LLUUID mItemID; // inventory UUID for the inventory item. LLUUID mObjectID; // in-world task UUID, or null if in agent inventory. LLItemPropertiesObserver* mPropertiesObserver; // for syncing changes to item LLObjectInventoryObserver* mObjectInventoryObserver; // for syncing changes to items inside an object - + + // We can send multiple properties updates simultaneously, make sure only last response counts and there won't be a race condition. + S32 mUpdatePendingId; + // // UI Elements // @@ -85,9 +92,9 @@ class LLSidepanelItemInfo : public LLSidepanelInventorySubpanel void onClickOwner(); void onCommitName(); void onCommitDescription(); - void onCommitPermissions(); - void onCommitSaleInfo(); - void onCommitSaleType(); + void onCommitPermissions(LLUICtrl* ctrl); + void updatePermissions(); + void onCommitSaleInfo(LLUICtrl* ctrl); void updateSaleInfo(); void onCommitChanges(LLPointer<LLViewerInventoryItem> item); }; diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index f03c7abc4d193bbf1d82df09f5b5836355c8b556..7fa06f51e30e51d5a84e23e6cb26d189390c2fcb 100644 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -174,9 +174,6 @@ BOOL LLSidepanelTaskInfo::postBuild() void LLSidepanelTaskInfo::disableAll() { - mDAPermModify->setEnabled(FALSE); - mDAPermModify->setValue(LLStringUtil::null); - mDACreatorName->setValue(LLStringUtil::null); mDACreatorName->setEnabled(FALSE); @@ -184,18 +181,42 @@ void LLSidepanelTaskInfo::disableAll() mDAOwnerName->setValue(LLStringUtil::null); mDAOwnerName->setEnabled(FALSE); - mDAButtonSetGroup->setEnabled(FALSE); - mDAObjectName->setValue(LLStringUtil::null); mDAObjectName->setEnabled(FALSE); mDAName->setEnabled(FALSE); mDADescription->setEnabled(FALSE); mDAObjectDescription->setValue(LLStringUtil::null); mDAObjectDescription->setEnabled(FALSE); - + + mDAPathfindingAttributes->setEnabled(FALSE); + mDAPathfindingAttributes->setValue(LLStringUtil::null); + + mDAButtonSetGroup->setEnabled(FALSE); + mDAButtonDeed->setEnabled(FALSE); + + mDAPermModify->setEnabled(FALSE); + mDAPermModify->setValue(LLStringUtil::null); + mDAEditCost->setValue(LLStringUtil::null); + mDAComboSaleType->setValue(LLSaleInfo::FS_COPY); + + disablePermissions(); + + mDAB->setVisible(FALSE); + mDAO->setVisible(FALSE); + mDAG->setVisible(FALSE); + mDAE->setVisible(FALSE); + mDAN->setVisible(FALSE); + mDAF->setVisible(FALSE); + + mOpenBtn->setEnabled(FALSE); + mPayBtn->setEnabled(FALSE); + mBuyBtn->setEnabled(FALSE); +} + +void LLSidepanelTaskInfo::disablePermissions() +{ mDACheckboxShareWithGroup->setValue(FALSE); mDACheckboxShareWithGroup->setEnabled(FALSE); - mDAButtonDeed->setEnabled(FALSE); mDACheckboxAllowEveryoneMove->setValue(FALSE); mDACheckboxAllowEveryoneMove->setEnabled(FALSE); @@ -217,33 +238,17 @@ void LLSidepanelTaskInfo::disableAll() //checkbox include in search mDASearchCheck->setValue(FALSE); mDASearchCheck->setEnabled(FALSE); - - mDAComboSaleType->setValue(LLSaleInfo::FS_COPY); + mDAComboSaleType->setEnabled(FALSE); - - mDAEditCost->setValue(LLStringUtil::null); + mDAEditCost->setEnabled(FALSE); - + mDALabelClickAction->setEnabled(FALSE); if (mDAComboClickAction) { mDAComboClickAction->setEnabled(FALSE); mDAComboClickAction->clear(); } - - mDAPathfindingAttributes->setEnabled(FALSE); - mDAPathfindingAttributes->setValue(LLStringUtil::null); - - mDAB->setVisible(FALSE); - mDAO->setVisible(FALSE); - mDAG->setVisible(FALSE); - mDAE->setVisible(FALSE); - mDAN->setVisible(FALSE); - mDAF->setVisible(FALSE); - - mOpenBtn->setEnabled(FALSE); - mPayBtn->setEnabled(FALSE); - mBuyBtn->setEnabled(FALSE); } void LLSidepanelTaskInfo::refresh() @@ -972,6 +977,12 @@ void LLSidepanelTaskInfo::onCommitPerm(LLUICtrl *ctrl, void *data, U8 field, U32 BOOL new_state = check->get(); LLSelectMgr::getInstance()->selectionSetObjectPermissions(field, new_state, perm); + + LLSidepanelTaskInfo* self = (LLSidepanelTaskInfo*)data; + if (self) + { + self->disablePermissions(); + } } // static diff --git a/indra/newview/llsidepaneltaskinfo.h b/indra/newview/llsidepaneltaskinfo.h index cbfb07874bc28c1e04fe9500a38e6f0796de5a8d..dc259cb22df6d1ff7aba41588c22e16b491364c9 100644 --- a/indra/newview/llsidepaneltaskinfo.h +++ b/indra/newview/llsidepaneltaskinfo.h @@ -95,6 +95,7 @@ class LLSidepanelTaskInfo : public LLSidepanelInventorySubpanel static void doClickAction(U8 click_action); void disableAll(); + void disablePermissions(); private: LLNameBox* mLabelGroupName; // group name diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index f5fea9decef5f9593eee9eef255b1064fe60f40c..43dc676a6352da8a466fa5b7ab6f6345d99be13d 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -65,6 +65,7 @@ F32 SHINE_WIDTH = 0.6f; F32 SHINE_OPACITY = 0.3f; F32 FALL_TIME = 0.6f; S32 BORDER_WIDTH = 6; +S32 TOP_PANEL_HEIGHT = 30; const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512 @@ -295,8 +296,8 @@ void LLSnapshotLivePreview::draw() F32 uv_width = isImageScaled() ? 1.f : llmin((F32)getWidth() / (F32)getCurrentImage()->getWidth(), 1.f); F32 uv_height = isImageScaled() ? 1.f : llmin((F32)getHeight() / (F32)getCurrentImage()->getHeight(), 1.f); gGL.pushMatrix(); - { - gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom, 0.f); + { + gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom + TOP_PANEL_HEIGHT, 0.f); gGL.begin(LLRender::QUADS); { gGL.texCoord2f(uv_width, uv_height); @@ -348,14 +349,15 @@ void LLSnapshotLivePreview::draw() F32 shine_interp = llmin(1.f, mShineAnimTimer.getElapsedTimeF32() / SHINE_TIME); // draw "shine" effect - LLLocalClipRect clip(getLocalRect()); + LLRect local_rect(0, getRect().getHeight() + TOP_PANEL_HEIGHT, getRect().getWidth(), 0); + LLLocalClipRect clip(local_rect); { // draw diagonal stripe with gradient that passes over screen S32 x1 = gViewerWindow->getWindowWidthScaled() * ll_round((clamp_rescale(shine_interp, 0.f, 1.f, -1.f - SHINE_WIDTH, 1.f))); S32 x2 = x1 + ll_round(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); S32 x3 = x2 + ll_round(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); S32 y1 = 0; - S32 y2 = gViewerWindow->getWindowHeightScaled(); + S32 y2 = gViewerWindow->getWindowHeightScaled() + TOP_PANEL_HEIGHT; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.begin(LLRender::QUADS); @@ -385,36 +387,6 @@ void LLSnapshotLivePreview::draw() } } - // draw framing rectangle - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4f(1.f, 1.f, 1.f, 1.f); - const LLRect& outline_rect = getImageRect(); - gGL.begin(LLRender::QUADS); - { - gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - gGL.vertex2i(outline_rect.mRight, outline_rect.mTop); - gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); - - gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom); - gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom); - gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); - gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); - - gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); - gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom); - gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); - gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - - gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom); - gGL.vertex2i(outline_rect.mRight, outline_rect.mTop); - gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); - } - gGL.end(); - } - // draw old image dropping away if (mFallAnimTimer.getStarted()) { @@ -588,6 +560,7 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update) if(!gViewerWindow->thumbnailSnapshot(raw, mThumbnailWidth, mThumbnailHeight, mAllowRenderUI && gSavedSettings.getBOOL("RenderUIInSnapshot"), + gSavedSettings.getBOOL("RenderHUDInSnapshot"), FALSE, mSnapshotBufferType) ) { @@ -746,6 +719,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"), previewp->getSnapshotType() == LLSnapshotModel::SNAPSHOT_TEXTURE, previewp->mAllowRenderUI && gSavedSettings.getBOOL("RenderUIInSnapshot"), + gSavedSettings.getBOOL("RenderHUDInSnapshot"), FALSE, previewp->mSnapshotBufferType, previewp->getMaxImageSize())) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 1dc1e65fe5a253d4d13e63065ed828d82fe48c69..7e6f3ef7bc83148c36b1cad724b27bf92ccb0510 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -996,7 +996,7 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) } LLSpatialGroup* group = drawablep->getSpatialGroup(); - llassert(group != NULL); + //llassert(group != NULL); if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING)) { diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index c8c39ae00f57d6c464ed1a176a35a37a391e6c8b..008dfe2a4508c4ec7f91e66ee9b763f9f8ce2356 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -106,7 +106,6 @@ //#include "llfirstuse.h" #include "llfloaterhud.h" #include "llfloaterland.h" -#include "llfloaterpreference.h" #include "llfloatertopobjects.h" #include "llfloaterworldmap.h" #include "llgesturemgr.h" @@ -158,6 +157,7 @@ #include "llviewermessage.h" #include "llviewernetwork.h" #include "llviewerobjectlist.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" @@ -236,7 +236,8 @@ LLSLURL LLStartUp::sStartSLURL; static LLPointer<LLCredential> gUserCredential; static std::string gDisplayName; -static BOOL gRememberPassword = TRUE; +static bool gRememberPassword = true; +static bool gRememberUser = true; static U64 gFirstSimHandle = 0; static LLHost gFirstSim; @@ -350,13 +351,6 @@ bool idle_startup() gIdleCallbacks.callFunctions(); gViewerWindow->updateUI(); - // There is a crash on updateClass, this is an attempt to get more information - if (LLMortician::graveyardCount()) - { - std::stringstream log_stream; - LLMortician::logClass(log_stream); - LL_INFOS() << log_stream.str() << LL_ENDL; - } LLMortician::updateClass(); const std::string delims (" "); @@ -701,19 +695,23 @@ bool idle_startup() else if (gSavedSettings.getBOOL("AutoLogin")) { // Log into last account - gRememberPassword = TRUE; - gSavedSettings.setBOOL("RememberPassword", TRUE); + gRememberPassword = true; + gRememberUser = true; + gSavedSettings.setBOOL("RememberPassword", TRUE); + gSavedSettings.setBOOL("RememberUser", TRUE); show_connect_box = false; } else if (gSavedSettings.getLLSD("UserLoginInfo").size() == 3) { // Console provided login&password gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); show_connect_box = false; } else { gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); show_connect_box = TRUE; } @@ -781,10 +779,7 @@ bool idle_startup() // Show the login dialog login_show(); // connect dialog is already shown, so fill in the names - if (gUserCredential.notNull() && !LLPanelLogin::isCredentialSet()) - { - LLPanelLogin::setFields( gUserCredential, gRememberPassword); - } + LLPanelLogin::populateFields( gUserCredential, gRememberUser, gRememberPassword); LLPanelLogin::giveFocus(); // MAINT-3231 Show first run dialog only for Desura viewer @@ -873,7 +868,7 @@ bool idle_startup() { // TODO if not use viewer auth // Load all the name information out of the login view - LLPanelLogin::getFields(gUserCredential, gRememberPassword); + LLPanelLogin::getFields(gUserCredential, gRememberUser, gRememberPassword); // end TODO // HACK: Try to make not jump on login @@ -885,14 +880,21 @@ bool idle_startup() // STATE_LOGIN_SHOW state if we've gone backwards mLoginStatePastUI = true; - // save the credentials - std::string userid = "unknown"; - if(gUserCredential.notNull()) - { - userid = gUserCredential->userID(); - gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); - } - gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + // save the credentials + std::string userid = "unknown"; + if (gUserCredential.notNull()) + { + userid = gUserCredential->userID(); + if (gRememberUser) + { + gSecAPIHandler->addToCredentialMap("login_list", gUserCredential, gRememberPassword); + // Legacy viewers use this method to store user credentials, newer viewers + // reuse it to be compatible and to remember last session + gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); + } + } + gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + gSavedSettings.setBOOL("RememberUser", gRememberUser); LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; gDebugInfo["LoginName"] = userid; @@ -1423,6 +1425,10 @@ bool idle_startup() // create a container's instance for start a controlling conversation windows // by the voice's events LLFloaterIMContainer::getInstance(); + if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2) + { + LLViewerParcelAskPlay::getInstance()->loadSettings(); + } // *Note: this is where gWorldMap used to be initialized. @@ -1632,7 +1638,14 @@ bool idle_startup() if (!gAgentMovementCompleted && timeout.getElapsedTimeF32() > STATE_AGENT_WAIT_TIMEOUT) { LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } reset_login(); } return FALSE; @@ -2367,7 +2380,14 @@ void use_circuit_callback(void**, S32 result) { // Make sure user knows something bad happened. JC LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; - LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } reset_login(); } else diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index 9eda33d3d20f22dac2309ffed79e6b1648deb87b..b8c227334da1ab21818d0fde9477abf3ead9c359 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -243,16 +243,24 @@ BOOL LLStatusBar::postBuild() mPanelNearByMedia->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT); mPanelNearByMedia->setVisible(FALSE); + updateBalancePanelPosition(); + // Hook up and init for filtering mFilterEdit = getChild<LLSearchEditor>( "search_menu_edit" ); mSearchPanel = getChild<LLPanel>( "menu_search_panel" ); - mSearchPanel->setVisible(gSavedSettings.getBOOL("MenuSearch")); + BOOL search_panel_visible = gSavedSettings.getBOOL("MenuSearch"); + mSearchPanel->setVisible(search_panel_visible); mFilterEdit->setKeystrokeCallback(boost::bind(&LLStatusBar::onUpdateFilterTerm, this)); mFilterEdit->setCommitCallback(boost::bind(&LLStatusBar::onUpdateFilterTerm, this)); collectSearchableItems(); gSavedSettings.getControl("MenuSearch")->getCommitSignal()->connect(boost::bind(&LLStatusBar::updateMenuSearchVisibility, this, _2)); + if (search_panel_visible) + { + updateMenuSearchPosition(); + } + return TRUE; } @@ -363,17 +371,7 @@ void LLStatusBar::setBalance(S32 balance) std::string label_str = getString("buycurrencylabel", string_args); mBoxBalance->setValue(label_str); - // Resize the L$ balance background to be wide enough for your balance plus the buy button - { - const S32 HPAD = 24; - LLRect balance_rect = mBoxBalance->getTextBoundingRect(); - LLRect buy_rect = getChildView("buyL")->getRect(); - LLRect shop_rect = getChildView("goShop")->getRect(); - LLView* balance_bg_view = getChildView("balance_bg"); - LLRect balance_bg_rect = balance_bg_view->getRect(); - balance_bg_rect.mLeft = balance_bg_rect.mRight - (buy_rect.getWidth() + shop_rect.getWidth() + balance_rect.getWidth() + HPAD); - balance_bg_view->setShape(balance_bg_rect); - } + updateBalancePanelPosition(); // If the search panel is shown, move this according to the new balance width. Parcel text will reshape itself in setParcelInfoText if (mSearchPanel && mSearchPanel->getVisible()) @@ -661,6 +659,19 @@ void LLStatusBar::updateMenuSearchPosition() mSearchPanel->setShape( searchRect ); } +void LLStatusBar::updateBalancePanelPosition() +{ + // Resize the L$ balance background to be wide enough for your balance plus the buy button + const S32 HPAD = 24; + LLRect balance_rect = mBoxBalance->getTextBoundingRect(); + LLRect buy_rect = getChildView("buyL")->getRect(); + LLRect shop_rect = getChildView("goShop")->getRect(); + LLView* balance_bg_view = getChildView("balance_bg"); + LLRect balance_bg_rect = balance_bg_view->getRect(); + balance_bg_rect.mLeft = balance_bg_rect.mRight - (buy_rect.getWidth() + shop_rect.getWidth() + balance_rect.getWidth() + HPAD); + balance_bg_view->setShape(balance_bg_rect); +} + // Implements secondlife:///app/balance/request to request a L$ balance // update via UDP message system. JC diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 403d590acacd2acef38f27b8281256448dc0ef78..cad877f7991ed7eb42730c0a9b859c8b2e148305 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -114,7 +114,8 @@ class LLStatusBar std::unique_ptr< ll::statusbar::SearchData > mSearchData; void collectSearchableItems(); void updateMenuSearchVisibility( const LLSD& data ); - void updateMenuSearchPosition(); + void updateMenuSearchPosition(); // depends onto balance position + void updateBalancePanelPosition(); private: LLTextBox *mTextTime; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index e5af47ab6cb69111f161585c53e9700b2bd1bed7..f3bb5741914dc6260a3a520e64832d75c9c03291 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -53,6 +53,7 @@ const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate) const S32 TEXTURE_FAST_CACHE_ENTRY_OVERHEAD = sizeof(S32) * 4; //w, h, c, level const S32 TEXTURE_FAST_CACHE_ENTRY_SIZE = 16 * 16 * 4 + TEXTURE_FAST_CACHE_ENTRY_OVERHEAD; +const F32 TEXTURE_LAZY_PURGE_TIME_LIMIT = .004f; // 4ms. Would be better to autoadjust, but there is a major cache rework in progress. class LLTextureCacheWorker : public LLWorkerClass { @@ -1669,6 +1670,91 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) LL_INFOS() << "The entire texture cache is cleared." << LL_ENDL ; } +void LLTextureCache::purgeTexturesLazy(F32 time_limit_sec) +{ + if (mReadOnly) + { + return; + } + + if (!mThreaded) + { + LLAppViewer::instance()->pauseMainloopTimeout(); + } + + // time_limit doesn't account for lock time + LLMutexLock lock(&mHeaderMutex); + + if (mPurgeEntryList.empty()) + { + // Read the entries list and form list of textures to purge + std::vector<Entry> entries; + U32 num_entries = openAndReadEntries(entries); + if (!num_entries) + { + return; // nothing to purge + } + + // Use mTexturesSizeMap to collect UUIDs of textures with bodies + typedef std::set<std::pair<U32, S32> > time_idx_set_t; + std::set<std::pair<U32, S32> > time_idx_set; + for (size_map_t::iterator iter1 = mTexturesSizeMap.begin(); + iter1 != mTexturesSizeMap.end(); ++iter1) + { + if (iter1->second > 0) + { + id_map_t::iterator iter2 = mHeaderIDMap.find(iter1->first); + if (iter2 != mHeaderIDMap.end()) + { + S32 idx = iter2->second; + time_idx_set.insert(std::make_pair(entries[idx].mTime, idx)); + } + else + { + LL_ERRS("TextureCache") << "mTexturesSizeMap / mHeaderIDMap corrupted." << LL_ENDL; + } + } + } + + S64 cache_size = mTexturesSizeTotal; + S64 purged_cache_size = (sCacheMaxTexturesSize * (S64)((1.f - TEXTURE_CACHE_PURGE_AMOUNT) * 100)) / 100; + for (time_idx_set_t::iterator iter = time_idx_set.begin(); + iter != time_idx_set.end(); ++iter) + { + S32 idx = iter->second; + if (cache_size >= purged_cache_size) + { + cache_size -= entries[idx].mBodySize; + mPurgeEntryList.push_back(std::pair<S32, Entry>(idx, entries[idx])); + } + else + { + break; + } + } + LL_DEBUGS("TextureCache") << "Formed Purge list of " << mPurgeEntryList.size() << " entries" << LL_ENDL; + } + else + { + // Remove collected entried + LLTimer timer; + while (!mPurgeEntryList.empty() && timer.getElapsedTimeF32() < time_limit_sec) + { + S32 idx = mPurgeEntryList.back().first; + Entry entry = mPurgeEntryList.back().second; + mPurgeEntryList.pop_back(); + // make sure record is still valid + id_map_t::iterator iter_header = mHeaderIDMap.find(entry.mID); + if (iter_header != mHeaderIDMap.end() && iter_header->second == idx) + { + std::string tex_filename = getTextureFileName(entry.mID); + removeEntry(idx, entry, tex_filename); + writeEntryToHeaderImmediately(idx, entry); + } + } + } +} + void LLTextureCache::purgeTextures(bool validate) { if (mReadOnly) @@ -1928,11 +2014,10 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio } if (mDoPurge) { - // NOTE: This may cause an occasional hiccup, - // but it really needs to be done on the control thread - // (i.e. here) - purgeTextures(false); - mDoPurge = FALSE; + // NOTE: Needs to be done on the control thread + // (i.e. here) + purgeTexturesLazy(TEXTURE_LAZY_PURGE_TIME_LIMIT); + mDoPurge = !mPurgeEntryList.empty(); } LLMutexLock lock(&mWorkersMutex); LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id, diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index 81ea7aeee2d98057c70f25b486bfc45b95af1d5e..da59290930d34f3f7c2cae53eb9ddbd67c359ac7 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -155,6 +155,7 @@ class LLTextureCache : public LLWorkerThread void readHeaderCache(); void clearCorruptedCache(); void purgeAllTextures(bool purge_directories); + void purgeTexturesLazy(F32 time_limit_sec); void purgeTextures(bool validate); LLAPRFile* openHeaderEntriesFile(bool readonly, S32 offset); void closeHeaderEntriesFile(); @@ -225,6 +226,8 @@ class LLTextureCache : public LLWorkerThread typedef std::map<S32, Entry> idx_entry_map_t; idx_entry_map_t mUpdatedEntryMap; + typedef std::vector<std::pair<S32, Entry> > idx_entry_vector_t; + idx_entry_vector_t mPurgeEntryList; // Statics static F32 sHeaderCacheVersion; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index e2bb904eff0ffdd003fad4596ee8e94cfde648ec..fd1c5373aed83999dc36ffd12b396fdee47e5163 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -73,9 +73,6 @@ #include "llavatarappearancedefines.h" -static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f; -static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f; -static const F32 CONTEXT_FADE_TIME = 0.08f; static const S32 LOCAL_TRACKING_ID_COLUMN = 1; @@ -442,59 +439,8 @@ BOOL LLFloaterTexturePicker::postBuild() // virtual void LLFloaterTexturePicker::draw() { - if (mOwner) - { - // draw cone of context pointing back to texture swatch - LLRect owner_rect; - mOwner->localRectToOtherView(mOwner->getLocalRect(), &owner_rect, this); - LLRect local_rect = getLocalRect(); - if (gFocusMgr.childHasKeyboardFocus(this) && mOwner->isInVisibleChain() && mContextConeOpacity > 0.001f) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); - { - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); - gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); - gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); - gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); - gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); - gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); - gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); - - - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); - gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); - gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); - } - gGL.end(); - } - } - - if (gFocusMgr.childHasMouseCapture(getDragHandle())) - { - mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME)); - } - else - { - mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME)); - } + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, mOwner); updateImageStats(); diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp index 941cb410fcab88f227754ed9eccad010a8659af1..f882fd31ee9439196bde7231e95c39b22b83cfa5 100644 --- a/indra/newview/lltoastalertpanel.cpp +++ b/indra/newview/lltoastalertpanel.cpp @@ -34,7 +34,6 @@ #include "llfontgl.h" #include "lltextbox.h" #include "llbutton.h" -#include "llcheckboxctrl.h" #include "llkeyboard.h" #include "llfocusmgr.h" #include "lliconctrl.h" @@ -62,9 +61,8 @@ static const S32 HPAD = 25; static const S32 BTN_HPAD = 8; LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal) - : LLToastPanel(notification), + : LLCheckBoxToastPanel(notification), mDefaultOption( 0 ), - mCheck(NULL), mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH), mLabel(notification->getName()), mLineEditor(NULL) @@ -347,20 +345,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal button_left += button_width + BTN_HPAD; } - std::string ignore_label; - - if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) - { - setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label); - } - if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY) - { - setCheckBox(LLNotifications::instance().getGlobalString("skipnexttimesessiononly"), ignore_label); - } - else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) - { - setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label); - } + setCheckBoxes(HPAD, VPAD); // *TODO: check necessity of this code //gFloaterView->adjustToFitScreen(this, FALSE); @@ -380,46 +365,6 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal LLTransientFloaterMgr::GLOBAL, this); } -bool LLToastAlertPanel::setCheckBox( const std::string& check_title, const std::string& check_control ) -{ - mCheck = LLUICtrlFactory::getInstance()->createFromFile<LLCheckBoxCtrl>("alert_check_box.xml", this, LLPanel::child_registry_t::instance()); - - if(!mCheck) - { - return false; - } - - const LLFontGL* font = mCheck->getFont(); - const S32 LINE_HEIGHT = font->getLineHeight(); - - std::vector<std::string> lines; - boost::split(lines, check_title, boost::is_any_of("\n")); - - // Extend dialog for "check next time" - S32 max_msg_width = LLToastPanel::getRect().getWidth() - 2 * HPAD; - S32 check_width = S32(font->getWidth(lines[0]) + 0.99f) + 16; // use width of the first line - max_msg_width = llmax(max_msg_width, check_width); - S32 dialog_width = max_msg_width + 2 * HPAD; - - S32 dialog_height = LLToastPanel::getRect().getHeight(); - dialog_height += LINE_HEIGHT * lines.size(); - dialog_height += LINE_HEIGHT / 2; - - LLToastPanel::reshape( dialog_width, dialog_height, FALSE ); - - S32 msg_x = (LLToastPanel::getRect().getWidth() - max_msg_width) / 2; - - // set check_box's attributes - LLRect check_rect; - mCheck->setRect(check_rect.setOriginAndSize(msg_x, VPAD+BTN_HEIGHT+LINE_HEIGHT/2, max_msg_width, LINE_HEIGHT*lines.size())); - mCheck->setLabel(check_title); - mCheck->setCommitCallback(boost::bind(&LLToastAlertPanel::onClickIgnore, this, _1)); - - LLToastPanel::addChild(mCheck); - - return true; -} - void LLToastAlertPanel::setVisible( BOOL visible ) { // only make the "ding" sound if it's newly visible @@ -569,16 +514,3 @@ void LLToastAlertPanel::onButtonPressed( const LLSD& data, S32 button ) mNotification->respond(response); // new notification reponse } - -void LLToastAlertPanel::onClickIgnore(LLUICtrl* ctrl) -{ - // checkbox sometimes means "hide and do the default" and - // other times means "warn me again". Yuck. JC - BOOL check = ctrl->getValue().asBoolean(); - if (mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) - { - // question was "show again" so invert value to get "ignore" - check = !check; - } - mNotification->setIgnored(check); -} diff --git a/indra/newview/lltoastalertpanel.h b/indra/newview/lltoastalertpanel.h index 15bf11d42c83ecb622b67f7be6932d29bffa935c..9b4e054bf13656618d40d188e50e386bc2e92ffb 100644 --- a/indra/newview/lltoastalertpanel.h +++ b/indra/newview/lltoastalertpanel.h @@ -46,7 +46,7 @@ class LLLineEditor; */ class LLToastAlertPanel - : public LLToastPanel + : public LLCheckBoxToastPanel { LOG_CLASS(LLToastAlertPanel); public: @@ -61,13 +61,11 @@ class LLToastAlertPanel virtual void draw(); virtual void setVisible( BOOL visible ); - bool setCheckBox( const std::string&, const std::string& ); void setCaution(BOOL val = TRUE) { mCaution = val; } // If mUnique==TRUE only one copy of this message should exist void setUnique(BOOL val = TRUE) { mUnique = val; } void setEditTextArgs(const LLSD& edit_args); - void onClickIgnore(LLUICtrl* ctrl); void onButtonPressed(const LLSD& data, S32 button); private: @@ -91,7 +89,6 @@ class LLToastAlertPanel std::vector<ButtonData> mButtonData; S32 mDefaultOption; - LLCheckBoxCtrl* mCheck; BOOL mCaution; BOOL mUnique; LLUIString mLabel; diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index a2116817a245c69bbb31000b5d5e249773d14339..bccf88128de5e436d1db2de28579ab2d1e54f22a 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -33,6 +33,7 @@ // library includes #include "lldbstrings.h" +#include "llcheckboxctrl.h" #include "lllslconstants.h" #include "llnotifications.h" #include "lluiconstants.h" @@ -55,7 +56,7 @@ const LLFontGL* LLToastNotifyPanel::sFontSmall = NULL; LLToastNotifyPanel::button_click_signal_t LLToastNotifyPanel::sButtonClickSignal; LLToastNotifyPanel::LLToastNotifyPanel(const LLNotificationPtr& notification, const LLRect& rect, bool show_images) -: LLToastPanel(notification), +: LLCheckBoxToastPanel(notification), LLInstanceTracker<LLToastNotifyPanel, LLUUID, LLInstanceTrackerReplaceOnCollision>(notification->getID()) { init(rect, show_images); @@ -162,6 +163,11 @@ void LLToastNotifyPanel::updateButtonsLayout(const std::vector<index_button_pair { left = (max_width - btn_rect.getWidth()) / 2; } + else if (left == 0 && buttons.size() == 2) + { + // Note: this and "size() == 1" shouldn't be inside the cycle, might be good idea to refactor whole placing process + left = (max_width - (btn_rect.getWidth() * 2) - h_pad) / 2; + } else if (left + btn_rect.getWidth() > max_width)// whether there is still some place for button+h_pad in the mControlPanel { // looks like we need to add button to the next row @@ -409,7 +415,20 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) //.xml file intially makes info panel only follow left/right/top. This is so that when control buttons are added the info panel //can shift upward making room for the buttons inside mControlPanel. After the buttons are added, the info panel can then be set to follow 'all'. mInfoPanel->setFollowsAll(); - snapToMessageHeight(mTextBox, LLToastPanel::MAX_TEXT_LENGTH); + + // Add checkbox (one of couple types) if nessesary. + setCheckBoxes(HPAD * 2, 0, mInfoPanel); + if (mCheck) + { + mCheck->setFollows(FOLLOWS_BOTTOM | FOLLOWS_LEFT); + } + // Snap to message, then to checkbox if present + snapToMessageHeight(mTextBox, LLToastPanel::MAX_TEXT_LENGTH); + if (mCheck) + { + S32 new_panel_height = mCheck->getRect().getHeight() + getRect().getHeight() + VPAD; + reshape(getRect().getWidth(), new_panel_height); + } // reshape the panel to its previous size if (current_rect.notEmpty()) diff --git a/indra/newview/lltoastnotifypanel.h b/indra/newview/lltoastnotifypanel.h index e4a75acfda09ec9cf7294a474b2a8c96af6b4e02..a5a637c6fac9e4de3fa9bb27f159c9b600a28623 100644 --- a/indra/newview/lltoastnotifypanel.h +++ b/indra/newview/lltoastnotifypanel.h @@ -47,7 +47,7 @@ class LLNotificationForm; * @deprecated this class will be removed after all toast panel types are * implemented in separate classes. */ -class LLToastNotifyPanel: public LLToastPanel, public LLInstanceTracker<LLToastNotifyPanel, LLUUID, LLInstanceTrackerReplaceOnCollision> +class LLToastNotifyPanel: public LLCheckBoxToastPanel, public LLInstanceTracker<LLToastNotifyPanel, LLUUID, LLInstanceTrackerReplaceOnCollision> { public: /** diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index 7c624d5b50566518267ef5dd91aa9acf78b615e4..100d5ee71359327311d51073058502fc5ad60373 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "lldbstrings.h" +#include "llcheckboxctrl.h" #include "llpanelgenerictip.h" #include "llpanelonlinestatus.h" #include "llnotifications.h" @@ -34,6 +35,8 @@ #include "lltoastpanel.h" #include "lltoastscriptquestion.h" +#include <boost/algorithm/string.hpp> + //static const S32 LLToastPanel::MIN_PANEL_HEIGHT = 40; // VPAD(4)*2 + ICON_HEIGHT(32) // 'magic numbers', consider initializing (512+20) part from xml/notifications @@ -145,3 +148,108 @@ LLToastPanel* LLToastPanel::buidPanelFromNotification( return res; } + +LLCheckBoxToastPanel::LLCheckBoxToastPanel(const LLNotificationPtr& p_ntf) +: LLToastPanel(p_ntf), +mCheck(NULL) +{ + +} + +void LLCheckBoxToastPanel::setCheckBoxes(const S32 &h_pad, const S32 &v_pad, LLView *parent_view) +{ + std::string ignore_label; + LLNotificationFormPtr form = mNotification->getForm(); + + if (form->getIgnoreType() == LLNotificationForm::IGNORE_CHECKBOX_ONLY) + { + // Normally text is only used to describe notification in preferences, + // but this one is not displayed in preferences and works on case by case + // basis. + // Display text if present, display 'always chose' if not. + std::string ignore_message = form->getIgnoreMessage(); + if (ignore_message.empty()) + { + ignore_message = LLNotifications::instance().getGlobalString("alwayschoose"); + } + setCheckBox(ignore_message, ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } + else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) + { + setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } + if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY) + { + setCheckBox(LLNotifications::instance().getGlobalString("skipnexttimesessiononly"), ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } + else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); + } +} + +bool LLCheckBoxToastPanel::setCheckBox(const std::string& check_title, + const std::string& check_control, + const commit_signal_t::slot_type& cb, + const S32 &h_pad, + const S32 &v_pad, + LLView *parent_view) +{ + mCheck = LLUICtrlFactory::getInstance()->createFromFile<LLCheckBoxCtrl>("alert_check_box.xml", this, LLPanel::child_registry_t::instance()); + + if (!mCheck) + { + return false; + } + + const LLFontGL* font = mCheck->getFont(); + const S32 LINE_HEIGHT = font->getLineHeight(); + + std::vector<std::string> lines; + boost::split(lines, check_title, boost::is_any_of("\n")); + + // Extend dialog for "check next time" + S32 max_msg_width = LLToastPanel::getRect().getWidth() - 2 * h_pad; + S32 check_width = S32(font->getWidth(lines[0]) + 0.99f) + 16; // use width of the first line + max_msg_width = llmax(max_msg_width, check_width); + S32 dialog_width = max_msg_width + 2 * h_pad; + + S32 dialog_height = LLToastPanel::getRect().getHeight(); + dialog_height += LINE_HEIGHT * lines.size(); + dialog_height += LINE_HEIGHT / 2; + + LLToastPanel::reshape(dialog_width, dialog_height, FALSE); + + S32 msg_x = (LLToastPanel::getRect().getWidth() - max_msg_width) / 2; + + // set check_box's attributes + LLRect check_rect; + // if we are part of the toast, we need to leave space for buttons + S32 msg_y = v_pad + (parent_view ? 0 : (BTN_HEIGHT + LINE_HEIGHT / 2)); + mCheck->setRect(check_rect.setOriginAndSize(msg_x, msg_y, max_msg_width, LINE_HEIGHT*lines.size())); + mCheck->setLabel(check_title); + mCheck->setCommitCallback(cb); + + if (parent_view) + { + // assume that width and height autoadjusts to toast + parent_view->addChild(mCheck); + } + else + { + LLToastPanel::addChild(mCheck); + } + + return true; +} + +void LLCheckBoxToastPanel::onCommitCheckbox(LLUICtrl* ctrl) +{ + BOOL check = ctrl->getValue().asBoolean(); + if (mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) + { + // question was "show again" so invert value to get "ignore" + check = !check; + } + mNotification->setIgnored(check); +} diff --git a/indra/newview/lltoastpanel.h b/indra/newview/lltoastpanel.h index 6a9b72a5ae56e915417c784991659d80aaac037e..f4c758ade9ef344c3be4d7155ea30fe22277d329 100644 --- a/indra/newview/lltoastpanel.h +++ b/indra/newview/lltoastpanel.h @@ -64,4 +64,23 @@ class LLToastPanel : public LLPanel { S32 computeSnappedToMessageHeight(LLTextBase* message, S32 maxLineCount); }; +class LLCheckBoxCtrl; + +// Wrapper with support for 'don't ask again' checkbox +class LLCheckBoxToastPanel : public LLToastPanel +{ +public: + LLCheckBoxToastPanel(const LLNotificationPtr& p_ntf); + virtual ~LLCheckBoxToastPanel() {}; + + // set checkboxes acording to defaults from form + void setCheckBoxes(const S32 &h_pad, const S32 &v_pad, LLView *parent_view = NULL); + // set single checkbox + bool setCheckBox(const std::string&, const std::string&, const commit_signal_t::slot_type& cb, const S32 &h_pad, const S32 &v_pad, LLView *parent_view = NULL); +protected: + void onCommitCheckbox(LLUICtrl* ctrl); + + LLCheckBoxCtrl* mCheck; +}; + #endif /* LL_TOASTPANEL_H */ diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp index b5d78f36548ebeb880dee7a62b8dc6bc249b7ef8..5235914c34884c0392c6d78d135e59cbdf706dfd 100644 --- a/indra/newview/lltool.cpp +++ b/indra/newview/lltool.cpp @@ -60,7 +60,7 @@ LLTool::~LLTool() } } -BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) +BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); @@ -83,9 +83,9 @@ BOOL LLTool::handleMouseDown(S32 x, S32 y, MASK mask) LL_INFOS() << "LLTool left mouse down" << LL_ENDL; } // by default, didn't handle it + // AGENT_CONTROL_LBUTTON_DOWN is handled by scanMouse() and scanKey() // LL_INFOS() << "LLTool::handleMouseDown" << LL_ENDL; - gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN); - return TRUE; + return FALSE; } BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask) @@ -95,8 +95,8 @@ BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask) LL_INFOS() << "LLTool left mouse up" << LL_ENDL; } // by default, didn't handle it + // AGENT_CONTROL_LBUTTON_UP is handled by scanMouse() and scanKey() // LL_INFOS() << "LLTool::handleMouseUp" << LL_ENDL; - gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP); return TRUE; } @@ -115,6 +115,12 @@ BOOL LLTool::handleScrollWheel(S32 x, S32 y, S32 clicks) return FALSE; } +BOOL LLTool::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + // by default, didn't handle it + return FALSE; +} + BOOL LLTool::handleDoubleClick(S32 x,S32 y,MASK mask) { // LL_INFOS() << "LLTool::handleDoubleClick" << LL_ENDL; diff --git a/indra/newview/lltool.h b/indra/newview/lltool.h index c5bad9d53272635821f71587dfe9764290faeebb..41a38804cea4baa16b23435b05edf47dd0f03e51 100644 --- a/indra/newview/lltool.h +++ b/indra/newview/lltool.h @@ -49,7 +49,7 @@ class LLTool virtual BOOL isView() const { return FALSE; } // Virtual functions inherited from LLMouseHandler - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); @@ -57,6 +57,7 @@ class LLTool virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index f66211ef3462e77525e20680cb19bc616f112489..7d77a8983f7de8b9ec32d22fa838230922ddebf2 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1728,6 +1728,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id)) { + // Legacy return ACCEPT_NO; } @@ -2154,6 +2155,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); if(gInventory.isObjectDescendentOf(category->getUUID(), outbox_id)) { + // Legacy return ACCEPT_NO; } diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index 3831f7d67dae7ab81943e0bde176d5617853d0bc..a4806ceaf64df5834687b2bbbe401f9778b62d86 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -721,9 +721,14 @@ void LLToolGrabBase::handleHoverActive(S32 x, S32 y, MASK mask) !objectp->isHUDAttachment() && objectp->getRoot() == gAgentAvatarp->getRoot()) { - // force focus to point in space where we were looking previously - gAgentCamera.setFocusGlobal(gAgentCamera.calcFocusPositionTargetGlobal(), LLUUID::null); - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + // we are essentially editing object position + if (!gSavedSettings.getBOOL("EditCameraMovement")) + { + // force focus to point in space where we were looking previously + // Example of use: follow cam scripts shouldn't affect you when movng objects arouns + gAgentCamera.setFocusGlobal(gAgentCamera.calcFocusPositionTargetGlobal(), LLUUID::null); + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + } } else { diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index f6eb290bc34660297224b132b9b6189440e1e294..3fcf193deca2f4688744f41cd14b7798f43e1b39 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -355,7 +355,7 @@ bool LLToolMgr::inBuildMode() bool LLToolMgr::canAccessMarketplace() { - return (LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT) || gSavedSettings.getBOOL("InventoryOutboxDisplayBoth"); + return (LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT); } void LLToolMgr::toggleMarketplace(const LLSD& sdname) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 54df5198c8c95a18d5e5e453a6c65486c6bfa98f..dd429d4ccfcc32a1e65b7a43d15be249118fddbe 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -83,7 +83,6 @@ LLToolPie::LLToolPie() mMouseOutsideSlop( false ), mMouseSteerX(-1), mMouseSteerY(-1), - mBlockClickToWalk(false), mClickAction(0), mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ), mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") ), @@ -91,7 +90,7 @@ LLToolPie::LLToolPie() { } -BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down) +BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); @@ -172,10 +171,8 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) mPick.mKeyMask = mask; mMouseButtonDown = true; - - handleLeftClickPick(); - return TRUE; + return handleLeftClickPick(); } // Spawn context menus on right mouse down so you can drag over and select @@ -208,6 +205,11 @@ BOOL LLToolPie::handleScrollWheel(S32 x, S32 y, S32 clicks) return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks); } +BOOL LLToolPie::handleScrollHWheel(S32 x, S32 y, S32 clicks) +{ + return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks); +} + // True if you selected an object. BOOL LLToolPie::handleLeftClickPick() { @@ -369,8 +371,6 @@ BOOL LLToolPie::handleLeftClickPick() // put focus back "in world" if (gFocusMgr.getKeyboardFocus()) { - // don't click to walk on attempt to give focus to world - mBlockClickToWalk = true; gFocusMgr.setKeyboardFocus(NULL); } @@ -414,7 +414,7 @@ BOOL LLToolPie::handleLeftClickPick() } object = (LLViewerObject*)object->getParent(); } - if (object && object == gAgentAvatarp && !gSavedSettings.getBOOL("ClickToWalk")) + if (object && object == gAgentAvatarp) { // we left clicked on avatar, switch to focus mode mMouseButtonDown = false; @@ -431,7 +431,6 @@ BOOL LLToolPie::handleLeftClickPick() // LLFirstUse::useLeftClickNoHit(); ///////// - // Eat the event return LLTool::handleMouseDown(x, y, mask); } @@ -538,17 +537,97 @@ void LLToolPie::resetSelection() mClickAction = 0; } -void LLToolPie::walkToClickedLocation() +bool LLToolPie::walkToClickedLocation() +{ + if (gAgent.getFlying() // don't auto-navigate while flying until that works + || !gAgentAvatarp + || gAgentAvatarp->isSitting()) + { + return false; + } + + LLPickInfo saved_pick = mPick; + mPick = gViewerWindow->pickImmediate(mHoverPick.mMousePt.mX, mHoverPick.mMousePt.mY, + FALSE /* ignore transparent */, + FALSE /* ignore rigged */, + FALSE /* ignore particles */); + + if (mPick.mPickType == LLPickInfo::PICK_OBJECT) + { + if (mPick.getObject() && mPick.getObject()->isHUDAttachment()) + { + mPick = saved_pick; + return false; + } + } + + LLViewerObject* avatar_object = mPick.getObject(); + + // get pointer to avatar + while (avatar_object && !avatar_object->isAvatar()) + { + avatar_object = (LLViewerObject*)avatar_object->getParent(); + } + + if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf()) + { + const F64 SELF_CLICK_WALK_DISTANCE = 3.0; + // pretend we picked some point a bit in front of avatar + mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE; + } + + if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || + (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) + { + gAgentCamera.setFocusOnAvatar(TRUE, TRUE); + + if (mAutoPilotDestination) { mAutoPilotDestination->markDead(); } + mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE); + mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal); + mAutoPilotDestination->setPixelSize(5); + mAutoPilotDestination->setColor(LLColor4U(170, 210, 190)); + mAutoPilotDestination->setDuration(3.f); + + LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; + gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, FALSE); + LLFirstUse::notMoving(false); + showVisualContextMenuEffect(); + return true; + } + else + { + LL_DEBUGS() << "walk target was " + << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero") + << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land") + << ", pick object was " << mPick.mObjectID + << LL_ENDL; + mPick = saved_pick; + return false; + } + return true; +} + +bool LLToolPie::teleportToClickedLocation() { - if(mAutoPilotDestination) { mAutoPilotDestination->markDead(); } - mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE); - mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal); - mAutoPilotDestination->setPixelSize(5); - mAutoPilotDestination->setColor(LLColor4U(170, 210, 190)); - mAutoPilotDestination->setDuration(3.f); - - LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; - gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, FALSE); + LLViewerObject* objp = mHoverPick.getObject(); + LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL; + + bool is_in_world = mHoverPick.mObjectID.notNull() && objp && !objp->isHUDAttachment(); + bool is_land = mHoverPick.mPickType == LLPickInfo::PICK_LAND; + bool pos_non_zero = !mHoverPick.mPosGlobal.isExactlyZero(); + bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch()); + bool has_click_action = final_click_action(objp); + + if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action))) + { + LLVector3d pos = mHoverPick.mPosGlobal; + pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot(); + gAgent.teleportViaLocationLookAt(pos); + mPick = mHoverPick; + showVisualContextMenuEffect(); + return true; + } + return false; } // When we get object properties after left-clicking on an object @@ -624,8 +703,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } else if (!mMouseOutsideSlop - && mMouseButtonDown - && gSavedSettings.getBOOL("ClickToWalk")) + && mMouseButtonDown) { S32 delta_x = x - mMouseDownX; S32 delta_y = y - mMouseDownY; @@ -710,70 +788,10 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) mDoubleClickTimer.reset(); } LLViewerObject* obj = mPick.getObject(); - U8 click_action = final_click_action(obj); - // let media have first pass at click - if (handleMediaMouseUp() || LLViewerMediaFocus::getInstance()->getFocus()) - { - mBlockClickToWalk = true; - } stopCameraSteering(); mMouseButtonDown = false; - if (click_action == CLICK_ACTION_NONE // not doing 1-click action - && gSavedSettings.getBOOL("ClickToWalk") // click to walk enabled - && !gAgent.getFlying() // don't auto-navigate while flying until that works - && gAgentAvatarp - && !gAgentAvatarp->isSitting() - && !mBlockClickToWalk // another behavior hasn't cancelled click to walk - ) - { - // We may be doing click to walk, but we don't want to use a target on - // a transparent object because the user thought they were clicking on - // whatever they were seeing through it, so recompute what was clicked on - // ignoring transparent objects - LLPickInfo savedPick = mPick; - mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY, - FALSE /* ignore transparent */, - FALSE /* ignore rigged */, - FALSE /* ignore particles */); - - if (!mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick - && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land - || mPick.mObjectID.notNull())) // or on an object - { - // handle special cases of steering picks - LLViewerObject* avatar_object = mPick.getObject(); - - // get pointer to avatar - while (avatar_object && !avatar_object->isAvatar()) - { - avatar_object = (LLViewerObject*)avatar_object->getParent(); - } - - if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf()) - { - const F64 SELF_CLICK_WALK_DISTANCE = 3.0; - // pretend we picked some point a bit in front of avatar - mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE; - } - gAgentCamera.setFocusOnAvatar(TRUE, TRUE); - walkToClickedLocation(); - LLFirstUse::notMoving(false); - - return TRUE; - } - else - { - LL_DEBUGS("maint5901") << "walk target was " - << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero") - << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land") - << ", pick object was " << mPick.mObjectID - << LL_ENDL; - // we didn't click to walk, so restore the original target - mPick = savedPick; - } - } gViewerWindow->setCursor(UI_CURSOR_ARROW); if (hasMouseCapture()) { @@ -783,7 +801,6 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) LLToolMgr::getInstance()->clearTransientTool(); gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on - mBlockClickToWalk = false; return LLTool::handleMouseUp(x, y, mask); } @@ -809,102 +826,21 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) return TRUE; } - if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f)) + if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f)) { mDoubleClickTimer.stop(); return FALSE; } mDoubleClickTimer.stop(); - if (gSavedSettings.getBOOL("DoubleClickAutoPilot")) - { - // We may be doing double click to walk, but we don't want to use a target on - // a transparent object because the user thought they were clicking on - // whatever they were seeing through it, so recompute what was clicked on - // ignoring transparent objects - LLPickInfo savedPick = mPick; - mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY, - FALSE /* ignore transparent */, - FALSE /* ignore rigged */, - FALSE /* ignore particles */); - - if(mPick.mPickType == LLPickInfo::PICK_OBJECT) - { - if (mPick.getObject() && mPick.getObject()->isHUDAttachment()) - { - mPick = savedPick; - return FALSE; - } - } - - if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || - (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) - { - walkToClickedLocation(); - return TRUE; - } - else - { - // restore the original pick for any other purpose - mPick = savedPick; - } - } - else if (gSavedSettings.getBOOL("DoubleClickTeleport")) - { - LLViewerObject* objp = mPick.getObject(); - LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL; - - bool is_in_world = mPick.mObjectID.notNull() && objp && !objp->isHUDAttachment(); - bool is_land = mPick.mPickType == LLPickInfo::PICK_LAND; - bool pos_non_zero = !mPick.mPosGlobal.isExactlyZero(); - bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch()); - bool has_click_action = final_click_action(objp); - - if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action))) - { - LLVector3d pos = mPick.mPosGlobal; - pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot(); - gAgent.teleportViaLocationLookAt(pos); - return TRUE; - } - } - return FALSE; } static bool needs_tooltip(LLSelectNode* nodep) { - if (!nodep) + if (!nodep || !nodep->mValid) return false; - - LLViewerObject* object = nodep->getObject(); - LLViewerObject *parent = (LLViewerObject *)object->getParent(); - if (object->flagHandleTouch() - || (parent && parent->flagHandleTouch()) - || object->flagTakesMoney() - || (parent && parent->flagTakesMoney()) - || object->flagAllowInventoryAdd() - ) - { - return true; - } - - U8 click_action = final_click_action(object); - if (click_action != 0) - { - return true; - } - - if (nodep->mValid) - { - bool anyone_copy = anyone_copy_selection(nodep); - bool for_sale = for_sale_selection(nodep); - if (anyone_copy || for_sale) - { - return true; - } - } - return false; + return true; } @@ -1428,7 +1364,6 @@ void LLToolPie::VisitHomePage(const LLPickInfo& info) void LLToolPie::handleSelect() { // tool is reselected when app gets focus, etc. - mBlockClickToWalk = true; } void LLToolPie::handleDeselect() @@ -1489,7 +1424,7 @@ void LLToolPie::stopCameraSteering() bool LLToolPie::inCameraSteerMode() { - return mMouseButtonDown && mMouseOutsideSlop && gSavedSettings.getBOOL("ClickToWalk"); + return mMouseButtonDown && mMouseOutsideSlop; } // true if x,y outside small box around start_x,start_y @@ -1940,7 +1875,6 @@ void LLToolPie::startCameraSteering() { LLFirstUse::notMoving(false); mMouseOutsideSlop = true; - mBlockClickToWalk = true; if (gAgentCamera.getFocusOnAvatar()) { diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 95d155a474a4ea1005df415b3784524794bfb906..ac6751aac0fad8deec86a6bdb4e1272f1f770dec 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -42,7 +42,7 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie> public: // Virtual functions inherited from LLMouseHandler - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); @@ -50,6 +50,7 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie> virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); virtual void render(); @@ -66,8 +67,8 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie> LLViewerObject* getClickActionObject() { return mClickActionObject; } LLObjectSelection* getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; } void resetSelection(); - void walkToClickedLocation(); - void blockClickToWalk() { mBlockClickToWalk = true; } + bool walkToClickedLocation(); + bool teleportToClickedLocation(); void stopClickToWalk(); static void selectionPropertiesReceived(); @@ -109,7 +110,6 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie> LLPointer<LLHUDEffectBlob> mAutoPilotDestination; LLPointer<LLHUDEffectBlob> mMouseSteerGrabPoint; bool mClockwise; - bool mBlockClickToWalk; LLUUID mMediaMouseCaptureID; LLPickInfo mPick; LLPickInfo mHoverPick; diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index 15c3dad38e6ba2e843308f40f358a282f2001463..77e950a1c9ed83bcf69f73069b25b0945758651a 100644 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -53,7 +53,7 @@ class LLWholeModelFeeObserver virtual ~LLWholeModelFeeObserver() {} virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0; - virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0; + virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result) = 0; LLHandle<LLWholeModelFeeObserver> getWholeModelFeeObserverHandle() const { return mWholeModelFeeObserverHandle; } diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index d8526e63caeed25370cb7cdcc339a74a2927d8ed..6df849674f26b56349b38b5ce5d4553ce43a1363 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1087,7 +1087,7 @@ void render_hud_attachments() // clamp target zoom level to reasonable values gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f); // smoothly interpolate current zoom level - gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLSmoothInterpolation::getInterpolant(0.03f)); + gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.getAgentHUDTargetZoom(), LLSmoothInterpolation::getInterpolant(0.03f)); if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices()) { diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index f475ab7d6630248e13fda8a6be7e8d6adc46f678..846a8e62a15393499b5fff1755805ffef731d813 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -69,6 +69,7 @@ #include "llfloaterevent.h" #include "llfloaterflickr.h" #include "llfloaterfonttest.h" +#include "llfloaterforgetuser.h" #include "llfloatergesture.h" #include "llfloatergodtools.h" #include "llfloatergridstatus.h" @@ -235,6 +236,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiencePicker>); LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFontTest>); + LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterForgetUser>); LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>); LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>); diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0718a27696a4ce1a4511f210d233d1e7d1c9b651 --- /dev/null +++ b/indra/newview/llviewerinput.cpp @@ -0,0 +1,1525 @@ +/** + * @file llviewerinput.cpp + * @brief LLViewerInput class implementation + * + * $LicenseInfo:firstyear=2005&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$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewerinput.h" + +#include "llappviewer.h" +#include "llfloaterreg.h" +#include "llmath.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llfloaterimnearbychat.h" +#include "llfocusmgr.h" +#include "llkeybind.h" // LLKeyData +#include "llmorphview.h" +#include "llmoveview.h" +#include "lltoolfocus.h" +#include "lltoolpie.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "llfloatercamera.h" +#include "llinitparam.h" + +// +// Constants +// + +const F32 FLY_TIME = 0.5f; +const F32 FLY_FRAMES = 4; + +const F32 NUDGE_TIME = 0.25f; // in seconds +const S32 NUDGE_FRAMES = 2; +const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed + +const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true); + +struct LLKeyboardActionRegistry +: public LLRegistrySingleton<std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry> +{ + LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry); +}; + +LLViewerInput gViewerInput; + +bool agent_jump( EKeystate s ) +{ + static BOOL first_fly_attempt(TRUE); + if (KEYSTATE_UP == s) + { + first_fly_attempt = TRUE; + return true; + } + F32 time = gKeyboard->getCurKeyElapsedTime(); + S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); + + if( time < FLY_TIME + || frame_count <= FLY_FRAMES + || gAgent.upGrabbed() + || !gSavedSettings.getBOOL("AutomaticFly")) + { + gAgent.moveUp(1); + } + else + { + gAgent.setFlying(TRUE, first_fly_attempt); + first_fly_attempt = FALSE; + gAgent.moveUp(1); + } + return true; +} + +bool agent_push_down( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgent.moveUp(-1); + return true; +} + +static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode) +{ + if (gAgent.mDoubleTapRunMode == mode && + gAgent.getRunning() && + !gAgent.getAlwaysRun()) + { + // Turn off temporary running. + gAgent.clearRunning(); + gAgent.sendWalkRun(gAgent.getRunning()); + } +} + +static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode) +{ + if (KEYSTATE_UP == s) + { + // Note: in case shift is already released, slide left/right run + // will be released in agent_turn_left()/agent_turn_right() + agent_check_temporary_run(mode); + } + else if (gSavedSettings.getBOOL("AllowTapTapHoldRun") && + KEYSTATE_DOWN == s && + !gAgent.getRunning()) + { + if (gAgent.mDoubleTapRunMode == mode && + gAgent.mDoubleTapRunTimer.getElapsedTimeF32() < NUDGE_TIME) + { + // Same walk-key was pushed again quickly; this is a + // double-tap so engage temporary running. + gAgent.setRunning(); + gAgent.sendWalkRun(gAgent.getRunning()); + } + + // Pressing any walk-key resets the double-tap timer + gAgent.mDoubleTapRunTimer.reset(); + gAgent.mDoubleTapRunMode = mode; + } +} + +static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode ) +{ + agent_handle_doubletap_run(s, mode); + if (KEYSTATE_UP == s) return; + + F32 time = gKeyboard->getCurKeyElapsedTime(); + S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); + + if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES) + { + gAgent.moveAtNudge(direction); + } + else + { + gAgent.moveAt(direction); + } +} + +bool camera_move_forward( EKeystate s ); + +bool agent_push_forward( EKeystate s ) +{ + if(gAgent.isMovementLocked()) return true; + + //in free camera control mode we need to intercept keyboard events for avatar movements + if (LLFloaterCamera::inFreeCameraMode()) + { + camera_move_forward(s); + } + else + { + agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD); + } + return true; +} + +bool camera_move_backward( EKeystate s ); + +bool agent_push_backward( EKeystate s ) +{ + if(gAgent.isMovementLocked()) return true; + + //in free camera control mode we need to intercept keyboard events for avatar movements + if (LLFloaterCamera::inFreeCameraMode()) + { + camera_move_backward(s); + } + else if (!gAgent.backwardGrabbed() && gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("LeaveMouselook")) + { + gAgentCamera.changeCameraToThirdPerson(); + } + else + { + agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD); + } + return true; +} + +static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode ) +{ + agent_handle_doubletap_run(s, mode); + if( KEYSTATE_UP == s ) return; + F32 time = gKeyboard->getCurKeyElapsedTime(); + S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); + + if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES) + { + gAgent.moveLeftNudge(direction); + } + else + { + gAgent.moveLeft(direction); + } +} + + +bool agent_slide_left( EKeystate s ) +{ + if(gAgent.isMovementLocked()) return true; + agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT); + return true; +} + + +bool agent_slide_right( EKeystate s ) +{ + if(gAgent.isMovementLocked()) return true; + agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT); + return true; +} + +bool camera_spin_around_cw( EKeystate s ); + +bool agent_turn_left(EKeystate s) +{ + //in free camera control mode we need to intercept keyboard events for avatar movements + if (LLFloaterCamera::inFreeCameraMode()) + { + camera_spin_around_cw(s); + return true; + } + + if(gAgent.isMovementLocked()) return false; + + if (LLToolCamera::getInstance()->mouseSteerMode()) + { + agent_slide_left(s); + } + else + { + if (KEYSTATE_UP == s) + { + // Check temporary running. In case user released 'left' key with shift already released. + agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT); + return true; + } + F32 time = gKeyboard->getCurKeyElapsedTime(); + gAgent.moveYaw( LLFloaterMove::getYawRate( time ) ); + } + return true; +} + +bool camera_spin_around_ccw( EKeystate s ); + +bool agent_turn_right( EKeystate s ) +{ + //in free camera control mode we need to intercept keyboard events for avatar movements + if (LLFloaterCamera::inFreeCameraMode()) + { + camera_spin_around_ccw(s); + return true; + } + + if(gAgent.isMovementLocked()) return false; + + if (LLToolCamera::getInstance()->mouseSteerMode()) + { + agent_slide_right(s); + } + else + { + if (KEYSTATE_UP == s) + { + // Check temporary running. In case user released 'right' key with shift already released. + agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT); + return true; + } + F32 time = gKeyboard->getCurKeyElapsedTime(); + gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) ); + } + return true; +} + +bool agent_look_up( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgent.movePitch(-1); + //gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() ); + return true; +} + + +bool agent_look_down( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgent.movePitch(1); + //gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() ); + return true; +} + +bool agent_toggle_fly( EKeystate s ) +{ + // Only catch the edge + if (KEYSTATE_DOWN == s ) + { + LLAgent::toggleFlying(); + } + return true; +} + +F32 get_orbit_rate() +{ + F32 time = gKeyboard->getCurKeyElapsedTime(); + if( time < NUDGE_TIME ) + { + F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME; + //LL_INFOS() << rate << LL_ENDL; + return rate; + } + else + { + return 1; + } +} + +bool camera_spin_around_ccw( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); + return true; +} + + +bool camera_spin_around_cw( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitRightKey( get_orbit_rate() ); + return true; +} + +bool camera_spin_around_ccw_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return true; + if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning()) + { + //send keystrokes, but do not change camera + agent_turn_right(s); + } + else + { + //change camera but do not send keystrokes + gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); + } + return true; +} + + +bool camera_spin_around_cw_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return true; + if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning()) + { + //send keystrokes, but do not change camera + agent_turn_left(s); + } + else + { + //change camera but do not send keystrokes + gAgentCamera.setOrbitRightKey( get_orbit_rate() ); + } + return true; +} + + +bool camera_spin_over( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitUpKey( get_orbit_rate() ); + return true; +} + + +bool camera_spin_under( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitDownKey( get_orbit_rate() ); + return true; +} + +bool camera_spin_over_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled()) + { + //send keystrokes, but do not change camera + agent_jump(s); + } + else + { + //change camera but do not send keystrokes + gAgentCamera.setOrbitUpKey( get_orbit_rate() ); + } + return true; +} + + +bool camera_spin_under_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled()) + { + //send keystrokes, but do not change camera + agent_push_down(s); + } + else + { + //change camera but do not send keystrokes + gAgentCamera.setOrbitDownKey( get_orbit_rate() ); + } + return true; +} + +bool camera_move_forward( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitInKey( get_orbit_rate() ); + return true; +} + + +bool camera_move_backward( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitOutKey( get_orbit_rate() ); + return true; +} + +bool camera_move_forward_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return true; + if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun())) + { + agent_push_forward(s); + } + else + { + gAgentCamera.setOrbitInKey( get_orbit_rate() ); + } + return true; +} + +bool camera_move_backward_sitting( EKeystate s ) +{ + if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return true; + + if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun())) + { + agent_push_backward(s); + } + else + { + gAgentCamera.setOrbitOutKey( get_orbit_rate() ); + } + return true; +} + +bool camera_pan_up( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanUpKey( get_orbit_rate() ); + return true; +} + +bool camera_pan_down( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanDownKey( get_orbit_rate() ); + return true; +} + +bool camera_pan_left( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanLeftKey( get_orbit_rate() ); + return true; +} + +bool camera_pan_right( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanRightKey( get_orbit_rate() ); + return true; +} + +bool camera_pan_in( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanInKey( get_orbit_rate() ); + return true; +} + +bool camera_pan_out( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setPanOutKey( get_orbit_rate() ); + return true; +} + +bool camera_move_forward_fast( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitInKey(2.5f); + return true; +} + +bool camera_move_backward_fast( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gAgentCamera.unlockView(); + gAgentCamera.setOrbitOutKey(2.5f); + return true; +} + + +bool edit_avatar_spin_ccw( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); + //gMorphView->orbitLeft( get_orbit_rate() ); + return true; +} + + +bool edit_avatar_spin_cw( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitRightKey( get_orbit_rate() ); + //gMorphView->orbitRight( get_orbit_rate() ); + return true; +} + +bool edit_avatar_spin_over( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitUpKey( get_orbit_rate() ); + //gMorphView->orbitUp( get_orbit_rate() ); + return true; +} + + +bool edit_avatar_spin_under( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitDownKey( get_orbit_rate() ); + //gMorphView->orbitDown( get_orbit_rate() ); + return true; +} + +bool edit_avatar_move_forward( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitInKey( get_orbit_rate() ); + //gMorphView->orbitIn(); + return true; +} + + +bool edit_avatar_move_backward( EKeystate s ) +{ + if( KEYSTATE_UP == s ) return true; + gMorphView->setCameraDrivenByKeys( TRUE ); + gAgentCamera.setOrbitOutKey( get_orbit_rate() ); + //gMorphView->orbitOut(); + return true; +} + +bool stop_moving( EKeystate s ) +{ + if( KEYSTATE_DOWN != s ) return true; + // stop agent + gAgent.setControlFlags(AGENT_CONTROL_STOP); + + // cancel autopilot + gAgent.stopAutoPilot(); + return true; +} + +bool start_chat( EKeystate s ) +{ + if (LLAppViewer::instance()->quitRequested()) + { + return true; // can't talk, gotta go, kthxbye! + } + if (KEYSTATE_DOWN != s) return true; + + // start chat + LLFloaterIMNearbyChat::startChat(NULL); + return true; +} + +bool start_gesture( EKeystate s ) +{ + LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + if (KEYSTATE_UP == s && + ! (focus_ctrlp && focus_ctrlp->acceptsTextInput())) + { + if ((LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"))->getCurrentChat().empty()) + { + // No existing chat in chat editor, insert '/' + LLFloaterIMNearbyChat::startChat("/"); + } + else + { + // Don't overwrite existing text in chat editor + LLFloaterIMNearbyChat::startChat(NULL); + } + } + return true; +} + +bool run_forward(EKeystate s) +{ + if (KEYSTATE_UP != s) + { + if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD) + { + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_FORWARD; + } + if (!gAgent.getRunning()) + { + gAgent.setRunning(); + gAgent.sendWalkRun(true); + } + } + else if(KEYSTATE_UP == s) + { + if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_FORWARD) + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; + gAgent.clearRunning(); + gAgent.sendWalkRun(false); + } + agent_push_forward(s); + return true; +} + +bool run_backward(EKeystate s) +{ + if (KEYSTATE_UP != s) + { + if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD) + { + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_BACKWARD; + } + if (!gAgent.getRunning()) + { + gAgent.setRunning(); + gAgent.sendWalkRun(true); + } + } + else if (KEYSTATE_UP == s) + { + if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_BACKWARD) + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; + gAgent.clearRunning(); + gAgent.sendWalkRun(false); + } + agent_push_backward(s); + return true; +} + +bool run_left(EKeystate s) +{ + if (KEYSTATE_UP != s) + { + if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT) + { + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_SLIDELEFT; + } + if (!gAgent.getRunning()) + { + gAgent.setRunning(); + gAgent.sendWalkRun(true); + } + } + else if (KEYSTATE_UP == s) + { + if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDELEFT) + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; + gAgent.clearRunning(); + gAgent.sendWalkRun(false); + } + agent_slide_left(s); + return true; +} + +bool run_right(EKeystate s) +{ + if (KEYSTATE_UP != s) + { + if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT) + { + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_SLIDERIGHT; + } + if (!gAgent.getRunning()) + { + gAgent.setRunning(); + gAgent.sendWalkRun(true); + } + } + else if (KEYSTATE_UP == s) + { + if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDERIGHT) + gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; + gAgent.clearRunning(); + gAgent.sendWalkRun(false); + } + agent_slide_right(s); + return true; +} + +bool toggle_run(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + bool run = gAgent.getAlwaysRun(); + if (run) + { + gAgent.clearAlwaysRun(); + gAgent.clearRunning(); + } + else + { + gAgent.setAlwaysRun(); + gAgent.setRunning(); + } + gAgent.sendWalkRun(!run); + return true; +} + +bool toggle_sit(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + if (gAgent.isSitting()) + { + gAgent.standUp(); + } + else + { + gAgent.sitDown(); + } + return true; +} + +bool toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar +{ + if (KEYSTATE_DOWN != s) return true; + bool pause = LLViewerMedia::isAnyMediaPlaying(); + LLViewerMedia::setAllMediaPaused(pause); + return true; +} + +bool toggle_enable_media(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + bool pause = LLViewerMedia::isAnyMediaPlaying() || LLViewerMedia::isAnyMediaShowing(); + LLViewerMedia::setAllMediaEnabled(!pause); + return true; +} + +bool walk_to(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + return LLToolPie::getInstance()->walkToClickedLocation(); +} + +bool teleport_to(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + return LLToolPie::getInstance()->teleportToClickedLocation(); +} + +bool toggle_voice(EKeystate s) +{ + if (KEYSTATE_DOWN != s) return true; + if (!LLAgent::isActionAllowed("speak")) return false; + LLVoiceClient::getInstance()->toggleUserPTTState(); + return true; +} + +bool voice_follow_key(EKeystate s) +{ + if (KEYSTATE_DOWN == s) + { + if (!LLAgent::isActionAllowed("speak")) return false; + LLVoiceClient::getInstance()->setUserPTTState(true); + return true; + } + else if (KEYSTATE_UP == s && LLVoiceClient::getInstance()->getUserPTTState()) + { + LLVoiceClient::getInstance()->setUserPTTState(false); + return true; + } + return false; +} + +bool agen_control_lbutton_handle(EKeystate s) +{ + switch (s) + { + case KEYSTATE_DOWN: + gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN); + break; + case KEYSTATE_UP: + gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP); + break; + default: + break; + } + return true; +} + +#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION); +REGISTER_KEYBOARD_ACTION("jump", agent_jump); +REGISTER_KEYBOARD_ACTION("push_down", agent_push_down); +REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward); +REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward); +REGISTER_KEYBOARD_ACTION("look_up", agent_look_up); +REGISTER_KEYBOARD_ACTION("look_down", agent_look_down); +REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly); +REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left); +REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right); +REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left); +REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right); +REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw); +REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw); +REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting); +REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting); +REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over); +REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under); +REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting); +REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting); +REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward); +REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward); +REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting); +REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting); +REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up); +REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down); +REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left); +REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right); +REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in); +REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out); +REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast); +REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast); +REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw); +REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw); +REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over); +REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under); +REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward); +REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward); +REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving); +REGISTER_KEYBOARD_ACTION("start_chat", start_chat); +REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture); +REGISTER_KEYBOARD_ACTION("run_forward", run_forward); +REGISTER_KEYBOARD_ACTION("run_backward", run_backward); +REGISTER_KEYBOARD_ACTION("run_left", run_left); +REGISTER_KEYBOARD_ACTION("run_right", run_right); +REGISTER_KEYBOARD_ACTION("toggle_run", toggle_run); +REGISTER_KEYBOARD_ACTION("toggle_sit", toggle_sit); +REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media); +REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media); +REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to); +REGISTER_KEYBOARD_ACTION("walk_to", walk_to); +REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice); +REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key); +#undef REGISTER_KEYBOARD_ACTION + +LLViewerInput::LLViewerInput() +{ + resetBindings(); + + for (S32 i = 0; i < KEY_COUNT; i++) + { + mKeyHandledByUI[i] = FALSE; + } + for (S32 i = 0; i < CLICK_COUNT; i++) + { + mMouseLevel[i] = MOUSE_STATE_SILENT; + } + // we want the UI to never see these keys so that they can always control the avatar/camera + for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++) + { + mKeysSkippedByUI.insert(k); + } +} + +// static +BOOL LLViewerInput::modeFromString(const std::string& string, S32 *mode) +{ + if (string == "FIRST_PERSON") + { + *mode = MODE_FIRST_PERSON; + return TRUE; + } + else if (string == "THIRD_PERSON") + { + *mode = MODE_THIRD_PERSON; + return TRUE; + } + else if (string == "EDIT_AVATAR") + { + *mode = MODE_EDIT_AVATAR; + return TRUE; + } + else if (string == "SITTING") + { + *mode = MODE_SITTING; + return TRUE; + } + else + { + *mode = MODE_THIRD_PERSON; + return FALSE; + } +} + +// static +BOOL LLViewerInput::mouseFromString(const std::string& string, EMouseClickType *mode) +{ + if (string == "LMB") + { + *mode = CLICK_LEFT; + return TRUE; + } + else if (string == "Double LMB") + { + *mode = CLICK_DOUBLELEFT; + return TRUE; + } + else if (string == "MMB") + { + *mode = CLICK_MIDDLE; + return TRUE; + } + else if (string == "MB4") + { + *mode = CLICK_BUTTON4; + return TRUE; + } + else if (string == "MB5") + { + *mode = CLICK_BUTTON5; + return TRUE; + } + else + { + *mode = CLICK_NONE; + return FALSE; + } +} + +BOOL LLViewerInput::handleKey(KEY translated_key, MASK translated_mask, BOOL repeated) +{ + // check for re-map + EKeyboardMode mode = gViewerInput.getMode(); + U32 keyidx = (translated_mask<<16) | translated_key; + key_remap_t::iterator iter = mRemapKeys[mode].find(keyidx); + if (iter != mRemapKeys[mode].end()) + { + translated_key = (iter->second) & 0xff; + translated_mask = (iter->second)>>16; + } + + // No repeats of F-keys + BOOL repeatable_key = (translated_key < KEY_F1 || translated_key > KEY_F12); + if (!repeatable_key && repeated) + { + return FALSE; + } + + LL_DEBUGS("UserInput") << "keydown -" << translated_key << "-" << LL_ENDL; + // skip skipped keys + if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end()) + { + mKeyHandledByUI[translated_key] = FALSE; + LL_INFOS("KeyboardHandling") << "Key wasn't handled by UI!" << LL_ENDL; + } + else + { + // it is sufficient to set this value once per call to handlekey + // without clearing it, as it is only used in the subsequent call to scanKey + mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask); + // mKeyHandledByUI is not what you think ... this indicates whether the UI has handled this keypress yet (any keypress) + // NOT whether some UI shortcut wishes to handle the keypress + + } + return mKeyHandledByUI[translated_key]; +} + +BOOL LLViewerInput::handleKeyUp(KEY translated_key, MASK translated_mask) +{ + return gViewerWindow->handleKeyUp(translated_key, translated_mask); +} + +BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name) +{ + S32 index; + typedef boost::function<bool(EKeystate)> function_t; + function_t function = NULL; + std::string name; + + // Allow remapping of F2-F12 + if (function_name[0] == 'F') + { + int c1 = function_name[1] - '0'; + int c2 = function_name[2] ? function_name[2] - '0' : -1; + if (c1 >= 0 && c1 <= 9 && c2 >= -1 && c2 <= 9) + { + int idx = c1; + if (c2 >= 0) + idx = idx*10 + c2; + if (idx >=2 && idx <= 12) + { + U32 keyidx = ((mask<<16)|key); + (mRemapKeys[mode])[keyidx] = ((0<<16)|(KEY_F1+(idx-1))); + return TRUE; + } + } + } + + // Not remapped, look for a function + + function_t* result = LLKeyboardActionRegistry::getValue(function_name); + if (result) + { + function = *result; + } + + if (!function) + { + LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; + return FALSE; + } + + // check for duplicate first and overwrite + S32 size = mKeyBindings[mode].size(); + for (index = 0; index < size; index++) + { + if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask) + break; + } + + if (mode >= MODE_COUNT) + { + LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL; + return FALSE; + } + + LLKeyboardBinding bind; + bind.mKey = key; + bind.mMask = mask; + bind.mFunction = function; + + mKeyBindings[mode].push_back(bind); + + return TRUE; +} + +BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const std::string& function_name) +{ + S32 index; + typedef boost::function<bool(EKeystate)> function_t; + function_t function = NULL; + + function_t* result = LLKeyboardActionRegistry::getValue(function_name); + if (result) + { + function = *result; + } + + if (!function) + { + LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; + return FALSE; + } + + // check for duplicate first and overwrite + S32 size = mMouseBindings[mode].size(); + for (index = 0; index < size; index++) + { + if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask) + break; + } + + if (mode >= MODE_COUNT) + { + LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL; + return FALSE; + } + + LLMouseBinding bind; + bind.mMouse = mouse; + bind.mMask = mask; + bind.mFunction = function; + + mMouseBindings[mode].push_back(bind); + + return TRUE; +} + +LLViewerInput::KeyBinding::KeyBinding() +: key("key"), + mouse("mouse"), + mask("mask"), + command("command") +{} + +LLViewerInput::KeyMode::KeyMode() +: bindings("binding") +{} + +LLViewerInput::Keys::Keys() +: first_person("first_person"), + third_person("third_person"), + sitting("sitting"), + edit_avatar("edit_avatar") +{} + +void LLViewerInput::resetBindings() +{ + for (S32 i = 0; i < MODE_COUNT; i++) + { + mKeyBindings[i].clear(); + mMouseBindings[i].clear(); + } +} + +S32 LLViewerInput::loadBindingsXML(const std::string& filename) +{ + resetBindings(); + + S32 binding_count = 0; + Keys keys; + LLSimpleXUIParser parser; + + if (parser.readXUI(filename, keys) + && keys.validateBlock()) + { + binding_count += loadBindingMode(keys.first_person, MODE_FIRST_PERSON); + binding_count += loadBindingMode(keys.third_person, MODE_THIRD_PERSON); + binding_count += loadBindingMode(keys.sitting, MODE_SITTING); + binding_count += loadBindingMode(keys.edit_avatar, MODE_EDIT_AVATAR); + } + return binding_count; +} + +S32 count_masks(const MASK &mask) +{ + S32 res = 0; + if (mask & MASK_CONTROL) + { + res++; + } + if (mask & MASK_SHIFT) + { + res++; + } + if (mask & MASK_ALT) + { + res++; + } + return res; +} + +bool compare_key_by_mask(LLKeyboardBinding i1, LLKeyboardBinding i2) +{ + return (count_masks(i1.mMask) > count_masks(i2.mMask)); +} + +bool compare_mouse_by_mask(LLMouseBinding i1, LLMouseBinding i2) +{ + return (count_masks(i1.mMask) > count_masks(i2.mMask)); +} + +S32 LLViewerInput::loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode) +{ + S32 binding_count = 0; + for (LLInitParam::ParamIterator<KeyBinding>::const_iterator it = keymode.bindings.begin(), + end_it = keymode.bindings.end(); + it != end_it; + ++it) + { + bool processed = false; + std::string key_str = it->key.getValue(); + if (!key_str.empty() && key_str != "NONE") + { + KEY key; + LLKeyboard::keyFromString(key_str, &key); + if (key != KEY_NONE) + { + MASK mask; + LLKeyboard::maskFromString(it->mask, &mask); + bindKey(mode, key, mask, it->command); + processed = true; + } + else + { + LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL; + } + } + if (!processed && it->mouse.isProvided() && !it->mouse.getValue().empty()) + { + EMouseClickType mouse; + mouseFromString(it->mouse.getValue(), &mouse); + if (mouse != CLICK_NONE) + { + MASK mask; + LLKeyboard::maskFromString(it->mask, &mask); + bindMouse(mode, mouse, mask, it->command); + processed = true; + } + else + { + LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL; + } + } + if (processed) + { + // total + binding_count++; + } + } + + // sort lists by mask (so that Shift+W is executed before W, if both are assigned, but if Shift+W is not assigned W should be executed) + std::sort(mKeyBindings[mode].begin(), mKeyBindings[mode].end(), compare_key_by_mask); + std::sort(mMouseBindings[mode].begin(), mMouseBindings[mode].end(), compare_mouse_by_mask); + + return binding_count; +} + +EKeyboardMode LLViewerInput::getMode() const +{ + if ( gAgentCamera.cameraMouselook() ) + { + return MODE_FIRST_PERSON; + } + else if ( gMorphView && gMorphView->getVisible()) + { + return MODE_EDIT_AVATAR; + } + else if (isAgentAvatarValid() && gAgentAvatarp->isSitting()) + { + return MODE_SITTING; + } + else + { + return MODE_THIRD_PERSON; + } +} + +bool LLViewerInput::scanKey(const std::vector<LLKeyboardBinding> &binding, + S32 binding_count, + KEY key, + MASK mask, + BOOL key_down, + BOOL key_up, + BOOL key_level, + bool repeat) const +{ + for (S32 i = 0; i < binding_count; i++) + { + if (binding[i].mKey == key) + { + if ((binding[i].mMask & mask) == binding[i].mMask) + { + bool res = false; + if (key_down && !repeat) + { + // ...key went down this frame, call function + res = binding[i].mFunction( KEYSTATE_DOWN ); + return true; + } + else if (key_up) + { + // ...key went down this frame, call function + res = binding[i].mFunction( KEYSTATE_UP ); + } + else if (key_level) + { + // ...key held down from previous frame + // Not windows, just call the function. + res = binding[i].mFunction( KEYSTATE_LEVEL ); + }//if + // Key+Mask combinations are supposed to be unique, so we won't find anything else + return res; + }//if + }//if + }//for + return false; +} + +// Called from scanKeyboard. +bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const +{ + if (LLApp::isExiting()) + { + return false; + } + + S32 mode = getMode(); + // Consider keyboard scanning as NOT mouse event. JC + MASK mask = gKeyboard->currentMask(FALSE); + + if (mKeyHandledByUI[key]) + { + return false; + } + + // don't process key down on repeated keys + BOOL repeat = gKeyboard->getKeyRepeated(key); + + bool res = scanKey(mKeyBindings[mode], mKeyBindings[mode].size(), key, mask, key_down, key_up, key_level, repeat); + + if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask)) + { + if (key_down && !repeat) + { + res = agen_control_lbutton_handle(KEYSTATE_DOWN); + } + if (key_up) + { + res = agen_control_lbutton_handle(KEYSTATE_UP); + } + } + return res; +} + +BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down) +{ + BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down); + + if (clicktype != CLICK_NONE) + { + // Special case + // If UI doesn't handle double click, LMB click is issued, so supres LMB 'down' when doubleclick is set + // handle !down as if we are handling doubleclick + + bool double_click_sp = (clicktype == CLICK_LEFT + && (mMouseLevel[CLICK_DOUBLELEFT] != MOUSE_STATE_SILENT) + && mMouseLevel[CLICK_LEFT] == MOUSE_STATE_SILENT); + if (double_click_sp && !down) + { + // Process doubleclick instead + clicktype = CLICK_DOUBLELEFT; + } + + + if (double_click_sp && down) + { + // Consume click. + // Due to handling, double click that is not handled will be immediately followed by LMB click + } + // If UI handled 'down', it should handle 'up' as well + // If we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI + else if (handled) + { + // UI handled new 'down' so iterupt whatever state we were in. + if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT) + { + if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN) + { + mMouseLevel[clicktype] = MOUSE_STATE_CLICK; + } + else + { + mMouseLevel[clicktype] = MOUSE_STATE_UP; + } + } + } + else if (down) + { + if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN) + { + // this is repeated hit (mouse does not repeat event until release) + // for now treat rapid clicking like mouse being held + mMouseLevel[clicktype] = MOUSE_STATE_LEVEL; + } + else + { + mMouseLevel[clicktype] = MOUSE_STATE_DOWN; + } + } + else if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT) + { + // Released mouse key + if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN) + { + mMouseLevel[clicktype] = MOUSE_STATE_CLICK; + } + else + { + mMouseLevel[clicktype] = MOUSE_STATE_UP; + } + } + } + + return handled; +} + +bool LLViewerInput::scanMouse(const std::vector<LLMouseBinding> &binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const +{ + for (S32 i = 0; i < binding_count; i++) + { + if (binding[i].mMouse == mouse && (binding[i].mMask & mask) == binding[i].mMask) + { + bool res = false; + switch (state) + { + case MOUSE_STATE_DOWN: + res = binding[i].mFunction(KEYSTATE_DOWN); + break; + case MOUSE_STATE_CLICK: + // Button went down and up in scope of single frame + // might not work best with some functions, + // but some function need specific states specifically + res = binding[i].mFunction(KEYSTATE_DOWN); + res |= binding[i].mFunction(KEYSTATE_UP); + break; + case MOUSE_STATE_LEVEL: + res = binding[i].mFunction(KEYSTATE_LEVEL); + break; + case MOUSE_STATE_UP: + res = binding[i].mFunction(KEYSTATE_UP); + break; + default: + break; + } + // Key+Mask combinations are supposed to be unique, no need to continue + return res; + } + } + return false; +} + +// todo: this recods key, scanMouse() triggers functions with EKeystate +bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const +{ + bool res = false; + S32 mode = getMode(); + MASK mask = gKeyboard->currentMask(TRUE); + res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state); + // no user defined actions found or those actions can't handle the key/button, handle control if nessesary + if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask)) + { + switch (state) + { + case MOUSE_STATE_DOWN: + agen_control_lbutton_handle(KEYSTATE_DOWN); + res = true; + break; + case MOUSE_STATE_CLICK: + // might not work best with some functions, + // but some function need specific states too specifically + agen_control_lbutton_handle(KEYSTATE_DOWN); + agen_control_lbutton_handle(KEYSTATE_UP); + res = true; + break; + case MOUSE_STATE_UP: + agen_control_lbutton_handle(KEYSTATE_UP); + res = true; + break; + default: + break; + } + } + return res; +} + +void LLViewerInput::scanMouse() +{ + for (S32 i = 0; i < CLICK_COUNT; i++) + { + if (mMouseLevel[i] != MOUSE_STATE_SILENT) + { + scanMouse((EMouseClickType)i, mMouseLevel[i]); + if (mMouseLevel[i] == MOUSE_STATE_DOWN) + { + // mouse doesn't support 'continued' state, so after handling, switch to LEVEL + mMouseLevel[i] = MOUSE_STATE_LEVEL; + } + else if (mMouseLevel[i] == MOUSE_STATE_UP || mMouseLevel[i] == MOUSE_STATE_CLICK) + { + mMouseLevel[i] = MOUSE_STATE_SILENT; + } + } + } +} diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h new file mode 100644 index 0000000000000000000000000000000000000000..1fe55bd585f247b2c82d652d25e109dd8096485f --- /dev/null +++ b/indra/newview/llviewerinput.h @@ -0,0 +1,177 @@ +/** + * @file llviewerinput.h + * @brief LLViewerInput class header file + * + * $LicenseInfo:firstyear=2005&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$ + */ + +#ifndef LL_LLVIEWERINPUT_H +#define LL_LLVIEWERINPUT_H + +#include "llkeyboard.h" // For EKeystate +#include "llinitparam.h" + +const S32 MAX_KEY_BINDINGS = 128; // was 60 + +class LLNamedFunction +{ +public: + LLNamedFunction() : mFunction(NULL) { }; + ~LLNamedFunction() { }; + + std::string mName; + LLKeyFunc mFunction; +}; + +class LLKeyboardBinding +{ +public: + KEY mKey; + MASK mMask; + + LLKeyFunc mFunction; +}; + +class LLMouseBinding +{ +public: + EMouseClickType mMouse; + MASK mMask; + + LLKeyFunc mFunction; +}; + + +typedef enum e_keyboard_mode +{ + MODE_FIRST_PERSON, + MODE_THIRD_PERSON, + MODE_EDIT_AVATAR, + MODE_SITTING, + MODE_COUNT +} EKeyboardMode; + +class LLWindow; + +void bind_keyboard_functions(); + +class LLViewerInput +{ +public: + struct KeyBinding : public LLInitParam::Block<KeyBinding> + { + Mandatory<std::string> key, + mask, + command; + Optional<std::string> mouse; // Note, not mandatory for the sake of backward campatibility with keys.xml + + KeyBinding(); + }; + + struct KeyMode : public LLInitParam::Block<KeyMode> + { + Multiple<KeyBinding> bindings; + + KeyMode(); + }; + + struct Keys : public LLInitParam::Block<Keys> + { + Optional<KeyMode> first_person, + third_person, + sitting, + edit_avatar; + + Keys(); + }; + + LLViewerInput(); + + BOOL handleKey(KEY key, MASK mask, BOOL repeated); + BOOL handleKeyUp(KEY key, MASK mask); + + S32 loadBindingsXML(const std::string& filename); // returns number bound, 0 on error + EKeyboardMode getMode() const; + + static BOOL modeFromString(const std::string& string, S32 *mode); // False on failure + static BOOL mouseFromString(const std::string& string, EMouseClickType *mode);// False on failure + + bool scanKey(KEY key, + BOOL key_down, + BOOL key_up, + BOOL key_level) const; + + // handleMouse() records state, scanMouse() goes through states, scanMouse(click) processes individual saved states after UI is done with them + BOOL handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down); + void scanMouse(); + +private: + bool scanKey(const std::vector<LLKeyboardBinding> &binding, + S32 binding_count, + KEY key, + MASK mask, + BOOL key_down, + BOOL key_up, + BOOL key_level, + bool repeat) const; + + enum EMouseState + { + MOUSE_STATE_DOWN, // key down this frame + MOUSE_STATE_CLICK, // key went up and down in scope of same frame + MOUSE_STATE_LEVEL, // clicked again fast, or never released + MOUSE_STATE_UP, // went up this frame + MOUSE_STATE_SILENT // notified about 'up', do not notify again + }; + bool scanMouse(EMouseClickType click, EMouseState state) const; + bool scanMouse(const std::vector<LLMouseBinding> &binding, + S32 binding_count, + EMouseClickType mouse, + MASK mask, + EMouseState state) const; + + S32 loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode); + BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name); + BOOL bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const std::string& function_name); + void resetBindings(); + + // Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here + + // TODO: at some point it is better to remake this, especially keyaboard part + // would be much better to send to functions actual state of the button than + // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown) + std::vector<LLKeyboardBinding> mKeyBindings[MODE_COUNT]; + std::vector<LLMouseBinding> mMouseBindings[MODE_COUNT]; + + typedef std::map<U32, U32> key_remap_t; + key_remap_t mRemapKeys[MODE_COUNT]; + std::set<KEY> mKeysSkippedByUI; + BOOL mKeyHandledByUI[KEY_COUNT]; // key processed successfully by UI + + // This is indentical to what llkeyboard does (mKeyRepeated, mKeyLevel, mKeyDown e t c), + // just instead of remembering individually as bools, we record state as enum + EMouseState mMouseLevel[CLICK_COUNT]; // records of key state +}; + +extern LLViewerInput gViewerInput; + +#endif // LL_LLVIEWERINPUT_H diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 9d7da115ac8b4afd9b74112b5983facf13602b41..6ff02ffe66b3999b13c011993e35e31f2376b5ee 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1745,7 +1745,7 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge, { std::string type_name = userdata.asString(); - if (("inbox" == type_name) || ("outbox" == type_name) || ("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name)) + if (("inbox" == type_name) || ("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name)) { LLFolderType::EType preferred_type = LLFolderType::lookup(type_name); diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp deleted file mode 100644 index e930eb20d3cf185affae53bb182d622dc0a0b2d3..0000000000000000000000000000000000000000 --- a/indra/newview/llviewerkeyboard.cpp +++ /dev/null @@ -1,1032 +0,0 @@ -/** - * @file llviewerkeyboard.cpp - * @brief LLViewerKeyboard class implementation - * - * $LicenseInfo:firstyear=2005&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llappviewer.h" -#include "llfloaterreg.h" -#include "llviewerkeyboard.h" -#include "llmath.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llfloaterimnearbychat.h" -#include "llviewercontrol.h" -#include "llfocusmgr.h" -#include "llmorphview.h" -#include "llmoveview.h" -#include "lltoolfocus.h" -#include "llviewerwindow.h" -#include "llvoavatarself.h" -#include "llfloatercamera.h" -#include "llinitparam.h" - -// -// Constants -// - -const F32 FLY_TIME = 0.5f; -const F32 FLY_FRAMES = 4; - -const F32 NUDGE_TIME = 0.25f; // in seconds -const S32 NUDGE_FRAMES = 2; -const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed - -struct LLKeyboardActionRegistry -: public LLRegistrySingleton<std::string, boost::function<void (EKeystate keystate)>, LLKeyboardActionRegistry> -{ - LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry); -}; - -LLViewerKeyboard gViewerKeyboard; - -void agent_jump( EKeystate s ) -{ - static BOOL first_fly_attempt(TRUE); - if (KEYSTATE_UP == s) - { - first_fly_attempt = TRUE; - return; - } - F32 time = gKeyboard->getCurKeyElapsedTime(); - S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); - - if( time < FLY_TIME - || frame_count <= FLY_FRAMES - || gAgent.upGrabbed() - || !gSavedSettings.getBOOL("AutomaticFly")) - { - gAgent.moveUp(1); - } - else - { - gAgent.setFlying(TRUE, first_fly_attempt); - first_fly_attempt = FALSE; - gAgent.moveUp(1); - } -} - -void agent_push_down( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgent.moveUp(-1); -} - -static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode) -{ - if (gAgent.mDoubleTapRunMode == mode && - gAgent.getRunning() && - !gAgent.getAlwaysRun()) - { - // Turn off temporary running. - gAgent.clearRunning(); - gAgent.sendWalkRun(gAgent.getRunning()); - } -} - -static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode) -{ - if (KEYSTATE_UP == s) - { - // Note: in case shift is already released, slide left/right run - // will be released in agent_turn_left()/agent_turn_right() - agent_check_temporary_run(mode); - } - else if (gSavedSettings.getBOOL("AllowTapTapHoldRun") && - KEYSTATE_DOWN == s && - !gAgent.getRunning()) - { - if (gAgent.mDoubleTapRunMode == mode && - gAgent.mDoubleTapRunTimer.getElapsedTimeF32() < NUDGE_TIME) - { - // Same walk-key was pushed again quickly; this is a - // double-tap so engage temporary running. - gAgent.setRunning(); - gAgent.sendWalkRun(gAgent.getRunning()); - } - - // Pressing any walk-key resets the double-tap timer - gAgent.mDoubleTapRunTimer.reset(); - gAgent.mDoubleTapRunMode = mode; - } -} - -static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode ) -{ - agent_handle_doubletap_run(s, mode); - if (KEYSTATE_UP == s) return; - - F32 time = gKeyboard->getCurKeyElapsedTime(); - S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); - - if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES) - { - gAgent.moveAtNudge(direction); - } - else - { - gAgent.moveAt(direction); - } -} - -void camera_move_forward( EKeystate s ); - -void agent_push_forward( EKeystate s ) -{ - if(gAgent.isMovementLocked()) return; - - //in free camera control mode we need to intercept keyboard events for avatar movements - if (LLFloaterCamera::inFreeCameraMode()) - { - camera_move_forward(s); - } - else - { - agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD); - } -} - -void camera_move_backward( EKeystate s ); - -void agent_push_backward( EKeystate s ) -{ - if(gAgent.isMovementLocked()) return; - - //in free camera control mode we need to intercept keyboard events for avatar movements - if (LLFloaterCamera::inFreeCameraMode()) - { - camera_move_backward(s); - } - else if (!gAgent.backwardGrabbed() && gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("LeaveMouselook")) - { - gAgentCamera.changeCameraToThirdPerson(); - } - else - { - agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD); - } -} - -static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode ) -{ - agent_handle_doubletap_run(s, mode); - if( KEYSTATE_UP == s ) return; - F32 time = gKeyboard->getCurKeyElapsedTime(); - S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); - - if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES) - { - gAgent.moveLeftNudge(direction); - } - else - { - gAgent.moveLeft(direction); - } -} - - -void agent_slide_left( EKeystate s ) -{ - if(gAgent.isMovementLocked()) return; - agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT); -} - - -void agent_slide_right( EKeystate s ) -{ - if(gAgent.isMovementLocked()) return; - agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT); -} - -void camera_spin_around_cw( EKeystate s ); - -void agent_turn_left( EKeystate s ) -{ - //in free camera control mode we need to intercept keyboard events for avatar movements - if (LLFloaterCamera::inFreeCameraMode()) - { - camera_spin_around_cw(s); - return; - } - - if(gAgent.isMovementLocked()) return; - - if (LLToolCamera::getInstance()->mouseSteerMode()) - { - agent_slide_left(s); - } - else - { - if (KEYSTATE_UP == s) - { - // Check temporary running. In case user released 'left' key with shift already released. - agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT); - return; - } - F32 time = gKeyboard->getCurKeyElapsedTime(); - gAgent.moveYaw( LLFloaterMove::getYawRate( time ) ); - } -} - -void camera_spin_around_ccw( EKeystate s ); - -void agent_turn_right( EKeystate s ) -{ - //in free camera control mode we need to intercept keyboard events for avatar movements - if (LLFloaterCamera::inFreeCameraMode()) - { - camera_spin_around_ccw(s); - return; - } - - if(gAgent.isMovementLocked()) return; - - if (LLToolCamera::getInstance()->mouseSteerMode()) - { - agent_slide_right(s); - } - else - { - if (KEYSTATE_UP == s) - { - // Check temporary running. In case user released 'right' key with shift already released. - agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT); - return; - } - F32 time = gKeyboard->getCurKeyElapsedTime(); - gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) ); - } -} - -void agent_look_up( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgent.movePitch(-1); - //gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() ); -} - - -void agent_look_down( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgent.movePitch(1); - //gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() ); -} - -void agent_toggle_fly( EKeystate s ) -{ - // Only catch the edge - if (KEYSTATE_DOWN == s ) - { - LLAgent::toggleFlying(); - } -} - -F32 get_orbit_rate() -{ - F32 time = gKeyboard->getCurKeyElapsedTime(); - if( time < NUDGE_TIME ) - { - F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME; - //LL_INFOS() << rate << LL_ENDL; - return rate; - } - else - { - return 1; - } -} - -void camera_spin_around_ccw( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); -} - - -void camera_spin_around_cw( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitRightKey( get_orbit_rate() ); -} - -void camera_spin_around_ccw_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return; - if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning()) - { - //send keystrokes, but do not change camera - agent_turn_right(s); - } - else - { - //change camera but do not send keystrokes - gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); - } -} - - -void camera_spin_around_cw_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return; - if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning()) - { - //send keystrokes, but do not change camera - agent_turn_left(s); - } - else - { - //change camera but do not send keystrokes - gAgentCamera.setOrbitRightKey( get_orbit_rate() ); - } -} - - -void camera_spin_over( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitUpKey( get_orbit_rate() ); -} - - -void camera_spin_under( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitDownKey( get_orbit_rate() ); -} - -void camera_spin_over_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled()) - { - //send keystrokes, but do not change camera - agent_jump(s); - } - else - { - //change camera but do not send keystrokes - gAgentCamera.setOrbitUpKey( get_orbit_rate() ); - } -} - - -void camera_spin_under_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled()) - { - //send keystrokes, but do not change camera - agent_push_down(s); - } - else - { - //change camera but do not send keystrokes - gAgentCamera.setOrbitDownKey( get_orbit_rate() ); - } -} - -void camera_move_forward( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitInKey( get_orbit_rate() ); -} - - -void camera_move_backward( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitOutKey( get_orbit_rate() ); -} - -void camera_move_forward_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return; - if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun())) - { - agent_push_forward(s); - } - else - { - gAgentCamera.setOrbitInKey( get_orbit_rate() ); - } -} - - -void camera_move_backward_sitting( EKeystate s ) -{ - if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return; - - if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun())) - { - agent_push_backward(s); - } - else - { - gAgentCamera.setOrbitOutKey( get_orbit_rate() ); - } -} - -void camera_pan_up( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanUpKey( get_orbit_rate() ); -} - -void camera_pan_down( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanDownKey( get_orbit_rate() ); -} - -void camera_pan_left( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanLeftKey( get_orbit_rate() ); -} - -void camera_pan_right( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanRightKey( get_orbit_rate() ); -} - -void camera_pan_in( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanInKey( get_orbit_rate() ); -} - -void camera_pan_out( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setPanOutKey( get_orbit_rate() ); -} - -void camera_move_forward_fast( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitInKey(2.5f); -} - -void camera_move_backward_fast( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gAgentCamera.unlockView(); - gAgentCamera.setOrbitOutKey(2.5f); -} - - -void edit_avatar_spin_ccw( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitLeftKey( get_orbit_rate() ); - //gMorphView->orbitLeft( get_orbit_rate() ); -} - - -void edit_avatar_spin_cw( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitRightKey( get_orbit_rate() ); - //gMorphView->orbitRight( get_orbit_rate() ); -} - -void edit_avatar_spin_over( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitUpKey( get_orbit_rate() ); - //gMorphView->orbitUp( get_orbit_rate() ); -} - - -void edit_avatar_spin_under( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitDownKey( get_orbit_rate() ); - //gMorphView->orbitDown( get_orbit_rate() ); -} - -void edit_avatar_move_forward( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitInKey( get_orbit_rate() ); - //gMorphView->orbitIn(); -} - - -void edit_avatar_move_backward( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - gMorphView->setCameraDrivenByKeys( TRUE ); - gAgentCamera.setOrbitOutKey( get_orbit_rate() ); - //gMorphView->orbitOut(); -} - -void stop_moving( EKeystate s ) -{ - if( KEYSTATE_UP == s ) return; - // stop agent - gAgent.setControlFlags(AGENT_CONTROL_STOP); - - // cancel autopilot - gAgent.stopAutoPilot(); -} - -void start_chat( EKeystate s ) -{ - if (LLAppViewer::instance()->quitRequested()) - { - return; // can't talk, gotta go, kthxbye! - } - - // start chat - LLFloaterIMNearbyChat::startChat(NULL); -} - -void start_gesture( EKeystate s ) -{ - LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); - if (KEYSTATE_UP == s && - ! (focus_ctrlp && focus_ctrlp->acceptsTextInput())) - { - if ((LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"))->getCurrentChat().empty()) - { - // No existing chat in chat editor, insert '/' - LLFloaterIMNearbyChat::startChat("/"); - } - else - { - // Don't overwrite existing text in chat editor - LLFloaterIMNearbyChat::startChat(NULL); - } - } -} - -#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION); -REGISTER_KEYBOARD_ACTION("jump", agent_jump); -REGISTER_KEYBOARD_ACTION("push_down", agent_push_down); -REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward); -REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward); -REGISTER_KEYBOARD_ACTION("look_up", agent_look_up); -REGISTER_KEYBOARD_ACTION("look_down", agent_look_down); -REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly); -REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left); -REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right); -REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left); -REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right); -REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw); -REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw); -REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting); -REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting); -REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over); -REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under); -REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting); -REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting); -REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward); -REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward); -REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting); -REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting); -REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up); -REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down); -REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left); -REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right); -REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in); -REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out); -REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast); -REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast); -REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw); -REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw); -REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over); -REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under); -REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward); -REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward); -REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving); -REGISTER_KEYBOARD_ACTION("start_chat", start_chat); -REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture); -#undef REGISTER_KEYBOARD_ACTION - -LLViewerKeyboard::LLViewerKeyboard() -{ - for (S32 i = 0; i < MODE_COUNT; i++) - { - mBindingCount[i] = 0; - } - - for (S32 i = 0; i < KEY_COUNT; i++) - { - mKeyHandledByUI[i] = FALSE; - } - // we want the UI to never see these keys so that they can always control the avatar/camera - for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++) - { - mKeysSkippedByUI.insert(k); - } -} - -BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode) -{ - if (string == "FIRST_PERSON") - { - *mode = MODE_FIRST_PERSON; - return TRUE; - } - else if (string == "THIRD_PERSON") - { - *mode = MODE_THIRD_PERSON; - return TRUE; - } - else if (string == "EDIT") - { - *mode = MODE_EDIT; - return TRUE; - } - else if (string == "EDIT_AVATAR") - { - *mode = MODE_EDIT_AVATAR; - return TRUE; - } - else if (string == "SITTING") - { - *mode = MODE_SITTING; - return TRUE; - } - else - { - *mode = MODE_THIRD_PERSON; - return FALSE; - } -} - -BOOL LLViewerKeyboard::handleKey(KEY translated_key, MASK translated_mask, BOOL repeated) -{ - // check for re-map - EKeyboardMode mode = gViewerKeyboard.getMode(); - U32 keyidx = (translated_mask<<16) | translated_key; - key_remap_t::iterator iter = mRemapKeys[mode].find(keyidx); - if (iter != mRemapKeys[mode].end()) - { - translated_key = (iter->second) & 0xff; - translated_mask = (iter->second)>>16; - } - - // No repeats of F-keys - BOOL repeatable_key = (translated_key < KEY_F1 || translated_key > KEY_F12); - if (!repeatable_key && repeated) - { - return FALSE; - } - - LL_DEBUGS("UserInput") << "keydown -" << translated_key << "-" << LL_ENDL; - // skip skipped keys - if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end()) - { - mKeyHandledByUI[translated_key] = FALSE; - LL_INFOS("KeyboardHandling") << "Key wasn't handled by UI!" << LL_ENDL; - } - else - { - // it is sufficient to set this value once per call to handlekey - // without clearing it, as it is only used in the subsequent call to scanKey - mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask); - // mKeyHandledByUI is not what you think ... this indicates whether the UI has handled this keypress yet (any keypress) - // NOT whether some UI shortcut wishes to handle the keypress - - } - return mKeyHandledByUI[translated_key]; -} - -BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask) -{ - return gViewerWindow->handleKeyUp(translated_key, translated_mask); -} - -BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name) -{ - S32 index; - typedef boost::function<void(EKeystate)> function_t; - function_t function = NULL; - std::string name; - - // Allow remapping of F2-F12 - if (function_name[0] == 'F') - { - int c1 = function_name[1] - '0'; - int c2 = function_name[2] ? function_name[2] - '0' : -1; - if (c1 >= 0 && c1 <= 9 && c2 >= -1 && c2 <= 9) - { - int idx = c1; - if (c2 >= 0) - idx = idx*10 + c2; - if (idx >=2 && idx <= 12) - { - U32 keyidx = ((mask<<16)|key); - (mRemapKeys[mode])[keyidx] = ((0<<16)|(KEY_F1+(idx-1))); - return TRUE; - } - } - } - - // Not remapped, look for a function - - function_t* result = LLKeyboardActionRegistry::getValue(function_name); - if (result) - { - function = *result; - } - - if (!function) - { - LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; - return FALSE; - } - - // check for duplicate first and overwrite - for (index = 0; index < mBindingCount[mode]; index++) - { - if (key == mBindings[mode][index].mKey && mask == mBindings[mode][index].mMask) - break; - } - - if (index >= MAX_KEY_BINDINGS) - { - LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL; - return FALSE; - } - - if (mode >= MODE_COUNT) - { - LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL; - return FALSE; - } - - mBindings[mode][index].mKey = key; - mBindings[mode][index].mMask = mask; - mBindings[mode][index].mFunction = function; - - if (index == mBindingCount[mode]) - mBindingCount[mode]++; - - return TRUE; -} - -LLViewerKeyboard::KeyBinding::KeyBinding() -: key("key"), - mask("mask"), - command("command") -{} - -LLViewerKeyboard::KeyMode::KeyMode(EKeyboardMode _mode) -: bindings("binding"), - mode(_mode) -{} - -LLViewerKeyboard::Keys::Keys() -: first_person("first_person", KeyMode(MODE_FIRST_PERSON)), - third_person("third_person", KeyMode(MODE_THIRD_PERSON)), - edit("edit", KeyMode(MODE_EDIT)), - sitting("sitting", KeyMode(MODE_SITTING)), - edit_avatar("edit_avatar", KeyMode(MODE_EDIT_AVATAR)) -{} - -S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename) -{ - S32 binding_count = 0; - Keys keys; - LLSimpleXUIParser parser; - - if (parser.readXUI(filename, keys) - && keys.validateBlock()) - { - binding_count += loadBindingMode(keys.first_person); - binding_count += loadBindingMode(keys.third_person); - binding_count += loadBindingMode(keys.edit); - binding_count += loadBindingMode(keys.sitting); - binding_count += loadBindingMode(keys.edit_avatar); - } - return binding_count; -} - -S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode) -{ - S32 binding_count = 0; - for (LLInitParam::ParamIterator<KeyBinding>::const_iterator it = keymode.bindings.begin(), - end_it = keymode.bindings.end(); - it != end_it; - ++it) - { - KEY key; - MASK mask; - LLKeyboard::keyFromString(it->key, &key); - LLKeyboard::maskFromString(it->mask, &mask); - bindKey(keymode.mode, key, mask, it->command); - binding_count++; - } - - return binding_count; -} - -S32 LLViewerKeyboard::loadBindings(const std::string& filename) -{ - LLFILE *fp; - const S32 BUFFER_SIZE = 2048; - char buffer[BUFFER_SIZE]; /* Flawfinder: ignore */ - // *NOTE: This buffer size is hard coded into scanf() below. - char mode_string[MAX_STRING] = ""; /* Flawfinder: ignore */ - char key_string[MAX_STRING] = ""; /* Flawfinder: ignore */ - char mask_string[MAX_STRING] = ""; /* Flawfinder: ignore */ - char function_string[MAX_STRING] = ""; /* Flawfinder: ignore */ - S32 mode = MODE_THIRD_PERSON; - KEY key = 0; - MASK mask = 0; - S32 tokens_read; - S32 binding_count = 0; - S32 line_count = 0; - - if(filename.empty()) - { - LL_ERRS() << " No filename specified" << LL_ENDL; - return 0; - } - - fp = LLFile::fopen(filename, "r"); - - if (!fp) - { - return 0; - } - - - while (!feof(fp)) - { - line_count++; - if (!fgets(buffer, BUFFER_SIZE, fp)) - break; - - // skip over comments, blank lines - if (buffer[0] == '#' || buffer[0] == '\n') continue; - - // grab the binding strings - tokens_read = sscanf( /* Flawfinder: ignore */ - buffer, - "%254s %254s %254s %254s", - mode_string, - key_string, - mask_string, - function_string); - - if (tokens_read == EOF) - { - LL_INFOS() << "Unexpected end-of-file at line " << line_count << " of key binding file " << filename << LL_ENDL; - fclose(fp); - return 0; - } - else if (tokens_read < 4) - { - LL_INFOS() << "Can't read line " << line_count << " of key binding file " << filename << LL_ENDL; - continue; - } - - // convert mode - if (!modeFromString(mode_string, &mode)) - { - LL_INFOS() << "Unknown mode on line " << line_count << " of key binding file " << filename << LL_ENDL; - LL_INFOS() << "Mode must be one of FIRST_PERSON, THIRD_PERSON, EDIT, EDIT_AVATAR" << LL_ENDL; - continue; - } - - // convert key - if (!LLKeyboard::keyFromString(key_string, &key)) - { - LL_INFOS() << "Can't interpret key on line " << line_count << " of key binding file " << filename << LL_ENDL; - continue; - } - - // convert mask - if (!LLKeyboard::maskFromString(mask_string, &mask)) - { - LL_INFOS() << "Can't interpret mask on line " << line_count << " of key binding file " << filename << LL_ENDL; - continue; - } - - // bind key - if (bindKey(mode, key, mask, function_string)) - { - binding_count++; - } - } - - fclose(fp); - - return binding_count; -} - - -EKeyboardMode LLViewerKeyboard::getMode() -{ - if ( gAgentCamera.cameraMouselook() ) - { - return MODE_FIRST_PERSON; - } - else if ( gMorphView && gMorphView->getVisible()) - { - return MODE_EDIT_AVATAR; - } - else if (isAgentAvatarValid() && gAgentAvatarp->isSitting()) - { - return MODE_SITTING; - } - else - { - return MODE_THIRD_PERSON; - } -} - - -// Called from scanKeyboard. -void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) -{ - S32 mode = getMode(); - // Consider keyboard scanning as NOT mouse event. JC - MASK mask = gKeyboard->currentMask(FALSE); - - LLKeyBinding* binding = mBindings[mode]; - S32 binding_count = mBindingCount[mode]; - - - if (mKeyHandledByUI[key]) - { - return; - } - - // don't process key down on repeated keys - BOOL repeat = gKeyboard->getKeyRepeated(key); - - for (S32 i = 0; i < binding_count; i++) - { - //for (S32 key = 0; key < KEY_COUNT; key++) - if (binding[i].mKey == key) - { - //if (binding[i].mKey == key && binding[i].mMask == mask) - if (binding[i].mMask == mask) - { - if (key_down && !repeat) - { - // ...key went down this frame, call function - binding[i].mFunction( KEYSTATE_DOWN ); - } - else if (key_up) - { - // ...key went down this frame, call function - binding[i].mFunction( KEYSTATE_UP ); - } - else if (key_level) - { - // ...key held down from previous frame - // Not windows, just call the function. - binding[i].mFunction( KEYSTATE_LEVEL ); - }//if - }//if - }//for - }//for -} diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h deleted file mode 100644 index 110dc89d2895bfb14fe33cd89c8f0233924bf521..0000000000000000000000000000000000000000 --- a/indra/newview/llviewerkeyboard.h +++ /dev/null @@ -1,118 +0,0 @@ -/** - * @file llviewerkeyboard.h - * @brief LLViewerKeyboard class header file - * - * $LicenseInfo:firstyear=2005&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$ - */ - -#ifndef LL_LLVIEWERKEYBOARD_H -#define LL_LLVIEWERKEYBOARD_H - -#include "llkeyboard.h" // For EKeystate -#include "llinitparam.h" - -const S32 MAX_NAMED_FUNCTIONS = 100; -const S32 MAX_KEY_BINDINGS = 128; // was 60 - -class LLNamedFunction -{ -public: - LLNamedFunction() : mFunction(NULL) { }; - ~LLNamedFunction() { }; - - std::string mName; - LLKeyFunc mFunction; -}; - -typedef enum e_keyboard_mode -{ - MODE_FIRST_PERSON, - MODE_THIRD_PERSON, - MODE_EDIT, - MODE_EDIT_AVATAR, - MODE_SITTING, - MODE_COUNT -} EKeyboardMode; - - -void bind_keyboard_functions(); - -class LLViewerKeyboard -{ -public: - struct KeyBinding : public LLInitParam::Block<KeyBinding> - { - Mandatory<std::string> key, - mask, - command; - - KeyBinding(); - }; - - struct KeyMode : public LLInitParam::Block<KeyMode> - { - Multiple<KeyBinding> bindings; - EKeyboardMode mode; - KeyMode(EKeyboardMode mode); - }; - - struct Keys : public LLInitParam::Block<Keys> - { - Optional<KeyMode> first_person, - third_person, - edit, - sitting, - edit_avatar; - - Keys(); - }; - - LLViewerKeyboard(); - - BOOL handleKey(KEY key, MASK mask, BOOL repeated); - BOOL handleKeyUp(KEY key, MASK mask); - - S32 loadBindings(const std::string& filename); // returns number bound, 0 on error - S32 loadBindingsXML(const std::string& filename); // returns number bound, 0 on error - EKeyboardMode getMode(); - - BOOL modeFromString(const std::string& string, S32 *mode); // False on failure - - void scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level); - -private: - S32 loadBindingMode(const LLViewerKeyboard::KeyMode& keymode); - BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name); - - // Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here - S32 mBindingCount[MODE_COUNT]; - LLKeyBinding mBindings[MODE_COUNT][MAX_KEY_BINDINGS]; - - typedef std::map<U32, U32> key_remap_t; - key_remap_t mRemapKeys[MODE_COUNT]; - std::set<KEY> mKeysSkippedByUI; - BOOL mKeyHandledByUI[KEY_COUNT]; // key processed successfully by UI -}; - -extern LLViewerKeyboard gViewerKeyboard; - -#endif // LL_LLVIEWERKEYBOARD_H diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 6cfc22a4e596d31141c5527f7f6541c04f8ef5d0..700462ad75564a92f4de72d7469ad0f6460fb55e 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -57,6 +57,7 @@ #include "llviewercontrol.h" #include "llviewermenufile.h" // LLFilePickerThread #include "llviewernetwork.h" +#include "llviewerparcelaskplay.h" #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" @@ -1018,12 +1019,14 @@ void LLViewerMedia::setAllMediaPaused(bool val) } } + LLParcel *agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + // Also do Parcel Media and Parcel Audio if (!val) { if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia()) { - LLViewerParcelMedia::getInstance()->play(LLViewerParcelMgr::getInstance()->getAgentParcel()); + LLViewerParcelMedia::getInstance()->play(agent_parcel); } static LLCachedControl<bool> audio_streaming_music(gSavedSettings, "AudioStreamingMusic", true); @@ -1051,6 +1054,12 @@ void LLViewerMedia::setAllMediaPaused(bool val) LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade(); } } + + // remove play choice for current parcel + if (agent_parcel && gAgent.getRegion()) + { + LLViewerParcelAskPlay::getInstance()->resetSetting(gAgent.getRegion()->getRegionID(), agent_parcel->getLocalID()); + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -2285,14 +2294,14 @@ void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button) } ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask) +void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, S32 scroll_x, S32 scroll_y, MASK mask) { scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; if (mMediaSource) { - mMediaSource->scrollEvent(x, y, mask); + mMediaSource->scrollEvent(x, y, scroll_x, scroll_y, mask); } } @@ -3754,7 +3763,7 @@ void LLViewerMediaImpl::setTextureID(LLUUID id) bool LLViewerMediaImpl::isAutoPlayable() const { return (mMediaAutoPlay && - gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && + gSavedSettings.getS32("ParcelMediaAutoPlayEnable") != 0 && gSavedSettings.getBOOL("MediaTentativeAutoPlay")); } diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 014f9048f0849559f17007dcb8f923f527495f00..2b604d3a7a9aa06400ed6f9180ae774130d4b6b3 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -79,7 +79,6 @@ class LLViewerMedia: public LLSingleton<LLViewerMedia> public: // String to get/set media autoplay in gSavedSettings - static const char* AUTO_PLAY_MEDIA_SETTING; static const char* SHOW_MEDIA_ON_OTHERS_SETTING; static const char* SHOW_MEDIA_WITHIN_PARCEL_SETTING; static const char* SHOW_MEDIA_OUTSIDE_PARCEL_SETTING; @@ -235,7 +234,7 @@ class LLViewerMediaImpl void mouseMove(const LLVector2& texture_coords, MASK mask); void mouseDoubleClick(const LLVector2& texture_coords, MASK mask); void mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button = 0); - void scrollWheel(S32 x, S32 y, MASK mask); + void scrollWheel(S32 x, S32 y, S32 scroll_x, S32 scroll_y, MASK mask); void mouseCapture(); void navigateBack(); @@ -320,6 +319,7 @@ class LLViewerMediaImpl /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) { return FALSE; }; /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; }; + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks) { return FALSE; }; /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; }; /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) { return FALSE; }; diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index f4a64a8e55c41ded10ad734cfd0df3ca5d8833e2..69ab0a71af459ecc9abe6e44ddd16faac300ddb4 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -377,12 +377,7 @@ BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks) LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); if(media_impl && media_impl->hasMedia()) { - // the scrollEvent() API's x and y are not the same as handleScrollWheel's x and y. - // The latter is the position of the mouse at the time of the event - // The former is the 'scroll amount' in x and y, respectively. - // All we have for 'scroll amount' here is 'clicks'. - // We're also not passed the keyboard modifier mask, but we can get that from gKeyboard. - media_impl->getMediaPlugin()->scrollEvent(0, clicks, gKeyboard->currentMask(TRUE)); + media_impl->scrollWheel(x, y, 0, clicks, gKeyboard->currentMask(TRUE)); retval = TRUE; } return retval; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index dc82719109b91d3bee6f9c9c89c11c8d97c28ade..a49218858be0e4fc9b1f9867582ef64a11ea4e67 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -401,23 +401,20 @@ void set_merchant_SLM_menu() void check_merchant_status(bool force) { - if (!gSavedSettings.getBOOL("InventoryOutboxDisplayBoth")) + if (force) { - if (force) - { - // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() - LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); - } - // Hide SLM related menu item - gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(FALSE); - - // Also disable the toolbar button for Marketplace Listings - LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings"); - gToolBarView->enableCommand(command->id(), false); - - // Launch an SLM test connection to get the merchant status - LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu)); + // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() + LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); } + // Hide SLM related menu item + gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(FALSE); + + // Also disable the toolbar button for Marketplace Listings + LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings"); + gToolBarView->enableCommand(command->id(), false); + + // Launch an SLM test connection to get the merchant status + LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu)); } void init_menus() @@ -6672,10 +6669,10 @@ class LLObjectAttachToAvatar : public view_listener_t static void onNearAttachObject(BOOL success, void *user_data); void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point); - - struct CallbackData + class CallbackData : public LLSelectionCallbackData { - CallbackData(LLViewerJointAttachment* point, bool replace) : mAttachmentPoint(point), mReplace(replace) {} + public: + CallbackData(LLViewerJointAttachment* point, bool replace) : LLSelectionCallbackData(), mAttachmentPoint(point), mReplace(replace) {} LLViewerJointAttachment* mAttachmentPoint; bool mReplace; @@ -6716,8 +6713,8 @@ void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data) // interpret 0 as "default location" attachment_id = 0; } - LLSelectMgr::getInstance()->sendAttach(attachment_id, cb_data->mReplace); - } + LLSelectMgr::getInstance()->sendAttach(cb_data->getSelection(), attachment_id, cb_data->mReplace); + } LLObjectAttachToAvatar::setObjectSelection(NULL); delete cb_data; @@ -8003,7 +8000,6 @@ BOOL LLViewerMenuHolderGL::hideMenus() if (LLMenuHolderGL::hideMenus()) { - LLToolPie::instance().blockClickToWalk(); handled = TRUE; } diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index a9a91b158b1b5b3aa98e431950ea42884957c3a4..687a48e7c183c922bc895e8da97901b09226d292 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -595,10 +595,16 @@ class LLFileTakeSnapshotToDisk : public view_listener_t S32 width = gViewerWindow->getWindowWidthRaw(); S32 height = gViewerWindow->getWindowHeightRaw(); + bool render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot"); + bool render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot"); + if (gSavedSettings.getBOOL("HighResSnapshot")) { width *= 2; height *= 2; + // not compatible wirh UI/HUD + render_ui = false; + render_hud = false; } if (gViewerWindow->rawSnapshot(raw, @@ -606,7 +612,8 @@ class LLFileTakeSnapshotToDisk : public view_listener_t height, TRUE, FALSE, - gSavedSettings.getBOOL("RenderUIInSnapshot"), + render_ui, + render_hud, FALSE)) { LLPointer<LLImageFormatted> formatted; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index b0ad81614a1c1c2fd5748f4a356616fc6d20a280..12a9757f71422b308269898169a205ef4382c26b 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -374,6 +374,11 @@ void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_ LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL; if(can_afford_transaction(amount)) { + if (uuid.isNull()) + { + LL_WARNS() << "Failed to send L$ gift to to Null UUID." << LL_ENDL; + return; + } // gStatusBar->debitBalance(amount); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_MoneyTransferRequest); @@ -1671,8 +1676,20 @@ void LLOfferInfo::fromLLSD(const LLSD& params) *this = params; } -void LLOfferInfo::send_auto_receive_response(void) -{ +void LLOfferInfo::sendReceiveResponse(bool accept, const LLUUID &destination_folder_id) +{ + if(IM_INVENTORY_OFFERED == mIM) + { + // add buddy to recent people list + LLRecentPeople::instance().add(mFromID); + } + + if (mTransactionID.isNull()) + { + // Not provided, message won't work + return; + } + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ImprovedInstantMessage); msg->nextBlockFast(_PREHASH_AgentData); @@ -1691,23 +1708,42 @@ void LLOfferInfo::send_auto_receive_response(void) msg->addU32Fast(_PREHASH_ParentEstateID, 0); msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); - - // Auto Receive Message. The math for the dialog works, because the accept + + // ACCEPT. The math for the dialog works, because the accept // for inventory_offered, task_inventory_offer or // group_notice_inventory is 1 greater than the offer integer value. // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED - msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData), - sizeof(mFolderID.mData)); - // send the message - msg->sendReliable(mHost); - - if(IM_INVENTORY_OFFERED == mIM) + // Decline for inventory_offered, task_inventory_offer or + // group_notice_inventory is 2 greater than the offer integer value. + + EInstantMessage im = mIM; + if (mIM == IM_GROUP_NOTICE_REQUESTED) { - // add buddy to recent people list - LLRecentPeople::instance().add(mFromID); + // Request has no responder dialogs + im = IM_GROUP_NOTICE; + } + + if (accept) + { + msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 1)); + msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(destination_folder_id.mData), + sizeof(destination_folder_id.mData)); + } + else + { + msg->addU8Fast(_PREHASH_Dialog, (U8)(im + 2)); + msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE); } + // send the message + msg->sendReliable(mHost); + + // transaction id is usable only once + // Note: a bit of a hack, clicking group notice attachment will not close notice + // so we reset no longer usable transaction id to know not to send message again + // Once capabilities for responses will be implemented LLOfferInfo will have to + // remember that it already responded in another way and ignore IOR_DECLINE + mTransactionID.setNull(); } void LLOfferInfo::handleRespond(const LLSD& notification, const LLSD& response) @@ -1767,7 +1803,10 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here: from_string = chatHistory_string = mFromName; - + + // accept goes to proper folder, decline gets accepted to trash, muted gets declined + bool accept_to_trash = true; + LLNotificationFormPtr modified_form(notification_ptr ? new LLNotificationForm(*notification_ptr->getForm()) : new LLNotificationForm()); switch(button) @@ -1799,11 +1838,11 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& } break; case IM_GROUP_NOTICE: + case IM_GROUP_NOTICE_REQUESTED: opener = new LLOpenTaskGroupOffer; - send_auto_receive_response(); + sendReceiveResponse(true, mFolderID); break; case IM_TASK_INVENTORY_OFFERED: - case IM_GROUP_NOTICE_REQUESTED: // This is an offer from a task or group. // We don't use a new instance of an opener // We instead use the singular observer gOpenTaskOffer @@ -1838,6 +1877,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& { modified_form->setElementEnabled("Mute", false); } + accept_to_trash = false; // for notices, but IOR_MUTE normally doesn't happen for notices // MUTE falls through to decline case IOR_DECLINE: { @@ -1851,21 +1891,32 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269 { chat.mMuted = TRUE; + accept_to_trash = false; // will send decline message } // *NOTE dzaporozhan // Disabled logging to old chat floater to fix crash in group notices - EXT-4149 // LLFloaterChat::addChatHistory(chat); - LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); - discard_agent_offer->startFetch(); - if ((catp && gInventory.isCategoryComplete(mObjectID)) || (itemp && itemp->isFinished())) + if (mObjectID.notNull()) //make sure we can discard { - discard_agent_offer->done(); + LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); + discard_agent_offer->startFetch(); + if ((catp && gInventory.isCategoryComplete(mObjectID)) || (itemp && itemp->isFinished())) + { + discard_agent_offer->done(); + } + else + { + opener = discard_agent_offer; + } } - else + else if (mIM == IM_GROUP_NOTICE) { - opener = discard_agent_offer; + // group notice needs to request object to trash so that user will see it later + // Note: muted agent offers go to trash, not sure if we should do same for notices + LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + sendReceiveResponse(accept_to_trash, trash); } if (modified_form != NULL) @@ -1878,9 +1929,14 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& } default: // close button probably - // The item has already been fetched and is in your inventory, we simply won't highlight it + // In case of agent offers item has already been fetched and is in your inventory, we simply won't highlight it // OR delete it if the notification gets killed, since we don't want that to be a vector for // losing inventory offers. + if (mIM == IM_GROUP_NOTICE) + { + LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + sendReceiveResponse(true, trash); + } break; } @@ -1925,29 +1981,10 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const } } } - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ImprovedInstantMessage); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MessageBlock); - msg->addBOOLFast(_PREHASH_FromGroup, FALSE); - msg->addUUIDFast(_PREHASH_ToAgentID, mFromID); - msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); - msg->addUUIDFast(_PREHASH_ID, mTransactionID); - msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary - std::string name; - LLAgentUI::buildFullname(name); - msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, ""); - msg->addU32Fast(_PREHASH_ParentEstateID, 0); - msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); - msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); - LLInventoryObserver* opener = NULL; - + std::string from_string; // Used in the pop-up. std::string chatHistory_string; // Used in chat history. + if (mFromObject == TRUE) { if (mFromGroup) @@ -1991,23 +2028,15 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const from_string = chatHistory_string = mFromName; } - bool is_do_not_disturb = gAgent.isDoNotDisturb(); - + LLUUID destination; + bool accept = true; + + // If user accepted, accept to proper folder, if user discarded, accept to trash. switch(button) { case IOR_ACCEPT: - // ACCEPT. The math for the dialog works, because the accept - // for inventory_offered, task_inventory_offer or - // group_notice_inventory is 1 greater than the offer integer value. - // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, - // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED - msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData), - sizeof(mFolderID.mData)); - // send the message - msg->sendReliable(mHost); - - //don't spam them if they are getting flooded + destination = mFolderID; + //don't spam user if flooded if (check_offer_throttle(mFromName, true)) { log_message = "<nolink>" + chatHistory_string + "</nolink> " + LLTrans::getString("InvOfferGaveYou") + " " + getSanitizedDescription() + LLTrans::getString("."); @@ -2015,66 +2044,24 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const args["MESSAGE"] = log_message; LLNotificationsUtil::add("SystemMessageTip", args); } - - // we will want to open this item when it comes back. - LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID - << LL_ENDL; - switch (mIM) - { - case IM_TASK_INVENTORY_OFFERED: - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_REQUESTED: - { - // This is an offer from a task or group. - // We don't use a new instance of an opener - // We instead use the singular observer gOpenTaskOffer - // Since it already exists, we don't need to actually do anything - } - break; - default: - LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL; - break; - } // end switch (mIM) break; - case IOR_MUTE: // MUTE falls through to decline + accept = false; case IOR_DECLINE: - // DECLINE. The math for the dialog works, because the decline - // for inventory_offered, task_inventory_offer or - // group_notice_inventory is 2 greater than the offer integer value. - // Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED, - // or IM_GROUP_NOTICE_INVENTORY_DECLINED default: // close button probably (or any of the fall-throughs from above) - msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 2)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE); - // send the message - msg->sendReliable(mHost); - - if (gSavedSettings.getBOOL("LogInventoryDecline")) - { - LLStringUtil::format_map_t log_message_args; - log_message_args["DESC"] = mDesc; - log_message_args["NAME"] = mFromName; - log_message = LLTrans::getString("InvOfferDecline", log_message_args); - - LLSD args; - args["MESSAGE"] = log_message; - LLNotificationsUtil::add("SystemMessageTip", args); - } - - if (is_do_not_disturb && (!mFromGroup && !mFromObject)) + destination = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (accept && LLMuteList::getInstance()->isMuted(mFromID, mFromName)) { - send_do_not_disturb_message(msg,mFromID); + // Note: muted offers are usually declined automatically, + // but user can mute object after receiving message + accept = false; } break; } - - if(opener) - { - gInventory.addObserver(opener); - } + + sendReceiveResponse(accept, destination); if(!mPersist) { @@ -4045,6 +4032,8 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList); + LL_DEBUGS("Messaging", "Motion") << "Processing " << num_blocks << " Animations" << LL_ENDL; + //clear animation flags avatarp->mSignaledAnimations.clear(); @@ -4057,8 +4046,6 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); - LL_DEBUGS("Messaging") << "Anim sequence ID: " << anim_sequence_id << LL_ENDL; - avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; // *HACK: Disabling flying mode if it has been enabled shortly before the agent @@ -4097,6 +4084,14 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id)); } } + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id + << " From block: " << object_id << LL_ENDL; + } + else + { + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id << LL_ENDL; } } } @@ -5108,7 +5103,14 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) std::string snap_filename = gDirUtilp->getLindenUserDir(); snap_filename += gDirUtilp->getDirDelimiter(); snap_filename += LLStartUp::getScreenHomeFilename(); - gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG); + gViewerWindow->saveSnapshot(snap_filename, + gViewerWindow->getWindowWidthRaw(), + gViewerWindow->getWindowHeightRaw(), + FALSE, //UI + gSavedSettings.getBOOL("RenderHUDInSnapshot"), + FALSE, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + LLSnapshotModel::SNAPSHOT_FORMAT_PNG); } if (notificationID == "RegionRestartMinutes" || @@ -5163,12 +5165,27 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) } } - // Error Notification can come with and without reason - if (notificationID == "JoinGroupError" && llsdBlock.has("reason")) - { - LLNotificationsUtil::add("JoinGroupErrorReason", llsdBlock); - return true; - } + // Error Notification can come with and without reason + if (notificationID == "JoinGroupError") + { + if (llsdBlock.has("reason")) + { + LLNotificationsUtil::add("JoinGroupErrorReason", llsdBlock); + return true; + } + if (llsdBlock.has("group_id")) + { + LLGroupData agent_gdatap; + bool is_member = gAgent.getGroupData(llsdBlock["group_id"].asUUID(), agent_gdatap); + if (is_member) + { + LLSD args; + args["reason"] = LLTrans::getString("AlreadyInGroup"); + LLNotificationsUtil::add("JoinGroupErrorReason", args); + return true; + } + } + } LLNotificationsUtil::add(notificationID, llsdBlock); return true; @@ -5191,7 +5208,14 @@ static void process_special_alert_messages(const std::string & message) std::string snap_filename = gDirUtilp->getLindenUserDir(); snap_filename += gDirUtilp->getDirDelimiter(); snap_filename += LLStartUp::getScreenHomeFilename(); - gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG); + gViewerWindow->saveSnapshot(snap_filename, + gViewerWindow->getWindowWidthRaw(), + gViewerWindow->getWindowHeightRaw(), + FALSE, + gSavedSettings.getBOOL("RenderHUDInSnapshot"), + FALSE, + LLSnapshotModel::SNAPSHOT_TYPE_COLOR, + LLSnapshotModel::SNAPSHOT_FORMAT_PNG); } } diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index 2d6636f30ddfc7e60e2f1ba8bbeee163c24513a3..78829a6a568151f7a9c3da0cda5f122ddaa1b5f9 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -254,7 +254,7 @@ class LLOfferInfo : public LLNotificationResponderInterface /*virtual*/ void fromLLSD(const LLSD& params); /*virtual*/ void handleRespond(const LLSD& notification, const LLSD& response); - void send_auto_receive_response(void); + void send_auto_receive_response() { sendReceiveResponse(true, mFolderID); } // TODO - replace all references with handleRespond() bool inventory_offer_callback(const LLSD& notification, const LLSD& response); @@ -264,6 +264,7 @@ class LLOfferInfo : public LLNotificationResponderInterface void initRespondFunctionMap(); std::string getSanitizedDescription(); + void sendReceiveResponse(bool accept, const LLUUID &destination_folder_id); typedef boost::function<bool (const LLSD&, const LLSD&)> respond_function_t; typedef std::map<std::string, respond_function_t> respond_function_map_t; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index c7a77d4d2ab82c363f6ebf3ef963586aaa544d2a..05230c17e0421bae9dd161c4b33cc44bd669c97e 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -142,6 +142,9 @@ const F32 PHYSICS_TIMESTEP = 1.f / 45.f; const U32 MAX_INV_FILE_READ_FAILS = 25; const S32 MAX_OBJECT_BINARY_DATA_SIZE = 60 + 16; +const F64 INVENTORY_UPDATE_WAIT_TIME_DESYNC = 5; // seconds +const F64 INVENTORY_UPDATE_WAIT_TIME_OUTDATED = 1; + static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object"); // static @@ -265,10 +268,12 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mData(NULL), mAudioSourcep(NULL), mAudioGain(1.f), + mSoundCutOffRadius(0.f), mAppAngle(0.f), mPixelArea(1024.f), mInventory(NULL), mInventorySerialNum(0), + mExpectedInventorySerialNum(0), mInvRequestState(INVENTORY_REQUEST_STOPPED), mInvRequestXFerId(0), mInventoryDirty(FALSE), @@ -1241,6 +1246,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, LLUUID audio_uuid; LLUUID owner_id; // only valid if audio_uuid or particle system is not null F32 gain; + F32 cutoff; U8 sound_flags; mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_CRC, crc, block_num); @@ -1249,6 +1255,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // HACK: Owner id only valid if non-null sound id or particle system mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, block_num ); mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num ); + mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Radius, cutoff, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Flags, sound_flags, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Material, material, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num); @@ -1257,6 +1264,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num, MAX_OBJECT_BINARY_DATA_SIZE); mTotalCRC = crc; + mSoundCutOffRadius = cutoff; // Owner ID used for sound muting or particle system muting setAttachedSound(audio_uuid, owner_id, gain, sound_flags); @@ -1279,7 +1287,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { case (60 + 16): // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); // fall through @@ -1287,23 +1295,23 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, this_update_precision = 32; // this is a terse update // pos - htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // vel - htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // acc - htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // theta { LLVector3 vec; - htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); new_rot.unpackFromVector3(vec); } count += sizeof(LLVector3); // omega - htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); if (new_angv.isExactlyZero()) { // reset rotation time @@ -1319,7 +1327,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, break; case(32 + 16): // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); // fall through @@ -1329,7 +1337,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // This is a terse 16 update, so treat data as an array of U16's. #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1340,7 +1348,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1351,7 +1359,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U16_to_F32(val[VZ], -size, size))); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1362,7 +1370,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U16_to_F32(val[VZ], -size, size))); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 4); + htolememcpy(valswizzle, &data[count], MVT_U16Quat, 4); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1374,7 +1382,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1570,7 +1578,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { case(60 + 16): // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); // fall through @@ -1578,23 +1586,23 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // this is a terse 32 update // pos this_update_precision = 32; - htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // vel - htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // acc - htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); // theta { LLVector3 vec; - htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); new_rot.unpackFromVector3(vec); } count += sizeof(LLVector3); // omega - htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + htolememcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); if (new_angv.isExactlyZero()) { // reset rotation time @@ -1610,7 +1618,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, break; case(32 + 16): // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); // fall through @@ -1620,7 +1628,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1631,7 +1639,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1642,7 +1650,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U16_to_F32(val[VZ], -size, size)); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1653,7 +1661,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U16_to_F32(val[VZ], -size, size)); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8); + htolememcpy(valswizzle, &data[count], MVT_U16Quat, 8); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1665,7 +1673,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *) &data[count]; @@ -1953,6 +1961,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } mTotalCRC = crc; + mSoundCutOffRadius = cutoff; setAttachedSound(sound_uuid, owner_id, gain, sound_flags); @@ -2802,13 +2811,13 @@ void LLViewerObject::doUpdateInventory( { // best guess. perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), item->getPermissions().getGroup(), is_atomic); - --mInventorySerialNum; + --mExpectedInventorySerialNum; } else { // dummy it up. perm.setOwnerAndGroup(LLUUID::null, LLUUID::null, LLUUID::null, is_atomic); - --mInventorySerialNum; + --mExpectedInventorySerialNum; } } LLViewerInventoryItem* oldItem = item; @@ -2816,7 +2825,11 @@ void LLViewerObject::doUpdateInventory( new_item->setPermissions(perm); mInventory->push_front(new_item); doInventoryCallback(); - ++mInventorySerialNum; + ++mExpectedInventorySerialNum; + } + else if (is_new) + { + ++mExpectedInventorySerialNum; } } @@ -2883,7 +2896,7 @@ void LLViewerObject::moveInventory(const LLUUID& folder_id, if(!item->getPermissions().allowCopyBy(gAgent.getID())) { deleteInventoryItem(item_id); - ++mInventorySerialNum; + ++mExpectedInventorySerialNum; } } } @@ -2974,6 +2987,8 @@ void LLViewerObject::fetchInventoryFromServer() if (!isInventoryPending()) { delete mInventory; + + // Results in processTaskInv LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_RequestTaskInventory); msg->nextBlockFast(_PREHASH_AgentData); @@ -2983,11 +2998,44 @@ void LLViewerObject::fetchInventoryFromServer() msg->addU32Fast(_PREHASH_LocalID, mLocalID); msg->sendReliable(mRegionp->getHost()); - // this will get reset by dirtyInventory or doInventoryCallback + // This will get reset by doInventoryCallback or processTaskInv mInvRequestState = INVENTORY_REQUEST_PENDING; } } +void LLViewerObject::fetchInventoryDelayed(const F64 &time_seconds) +{ + // unless already waiting, drop previous request and shedule an update + if (mInvRequestState != INVENTORY_REQUEST_WAIT) + { + if (mInvRequestXFerId != 0) + { + // abort download. + gXferManager->abortRequestById(mInvRequestXFerId, -1); + mInvRequestXFerId = 0; + } + mInvRequestState = INVENTORY_REQUEST_WAIT; // affects isInventoryPending() + LLCoros::instance().launch("LLViewerObject::fetchInventoryDelayedCoro()", + boost::bind(&LLViewerObject::fetchInventoryDelayedCoro, mID, time_seconds)); + } +} + +//static +void LLViewerObject::fetchInventoryDelayedCoro(const LLUUID task_inv, const F64 time_seconds) +{ + llcoro::suspendUntilTimeout(time_seconds); + LLViewerObject *obj = gObjectList.findObject(task_inv); + if (obj) + { + // Might be good idea to prolong delay here in case expected serial changed. + // As it is, it will get a response with obsolete serial and will delay again. + + // drop waiting state to unlock isInventoryPending() + obj->mInvRequestState = INVENTORY_REQUEST_STOPPED; + obj->fetchInventoryFromServer(); + } +} + LLControlAvatar *LLViewerObject::getControlAvatar() { return getRootEdit()->mControlAvatar.get(); @@ -3146,74 +3194,97 @@ S32 LLFilenameAndTask::sCount = 0; // static void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) { - LLUUID task_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id); - LLViewerObject* object = gObjectList.findObject(task_id); - if(!object) - { - LL_WARNS() << "LLViewerObject::processTaskInv object " - << task_id << " does not exist." << LL_ENDL; - return; - } + LLUUID task_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id); + LLViewerObject* object = gObjectList.findObject(task_id); + if (!object) + { + LL_WARNS() << "LLViewerObject::processTaskInv object " + << task_id << " does not exist." << LL_ENDL; + return; + } - LLFilenameAndTask* ft = new LLFilenameAndTask; - ft->mTaskID = task_id; - // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update - msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial); + LLFilenameAndTask* ft = new LLFilenameAndTask; + ft->mTaskID = task_id; + // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update + msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial); - if (ft->mSerial < object->mInventorySerialNum) - { - // viewer did some changes to inventory that were not saved yet. - LL_DEBUGS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client serial: " << object->mInventorySerialNum << LL_ENDL; - object->mInventorySerialNum = ft->mSerial; - } + if (ft->mSerial == object->mInventorySerialNum + && ft->mSerial < object->mExpectedInventorySerialNum) + { + // Loop Protection. + // We received same serial twice. + // Viewer did some changes to inventory that couldn't be saved server side + // or something went wrong to cause serial to be out of sync. + // Drop xfer and restart after some time, assign server's value as expected + LL_WARNS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client expected serial: " << object->mExpectedInventorySerialNum << LL_ENDL; + object->mExpectedInventorySerialNum = ft->mSerial; + object->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_DESYNC); + } + else if (ft->mSerial < object->mExpectedInventorySerialNum) + { + // Out of date message, record to current serial for loop protection, but do not load it + // Drop xfer and restart after some time + if (ft->mSerial < object->mInventorySerialNum) + { + LL_WARNS() << "Task serial decreased. Potentially out of order packet or desync." << LL_ENDL; + } + object->mInventorySerialNum = ft->mSerial; + object->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_OUTDATED); + } + else if (ft->mSerial >= object->mExpectedInventorySerialNum) + { + // We received version we expected or newer. Load it. + object->mInventorySerialNum = ft->mSerial; + object->mExpectedInventorySerialNum = ft->mSerial; - std::string unclean_filename; - msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); - ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); + std::string unclean_filename; + msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); + ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); - if(ft->mFilename.empty()) - { - LL_DEBUGS() << "Task has no inventory" << LL_ENDL; - // mock up some inventory to make a drop target. - if(object->mInventory) - { - object->mInventory->clear(); // will deref and delete it - } - else - { - object->mInventory = new LLInventoryObject::object_list_t(); - } - LLPointer<LLInventoryObject> obj; - obj = new LLInventoryObject(object->mID, LLUUID::null, - LLAssetType::AT_CATEGORY, - "Contents"); - object->mInventory->push_front(obj); - object->doInventoryCallback(); - delete ft; - return; - } - U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), - ft->mFilename, LL_PATH_CACHE, - object->mRegionp->getHost(), - TRUE, - &LLViewerObject::processTaskInvFile, - (void**)ft, - LLXferManager::HIGH_PRIORITY); - if (object->mInvRequestState == INVENTORY_XFER) - { - if (new_id > 0 && new_id != object->mInvRequestXFerId) - { - // we started new download. - gXferManager->abortRequestById(object->mInvRequestXFerId, -1); - object->mInvRequestXFerId = new_id; - } - } - else - { - object->mInvRequestState = INVENTORY_XFER; - object->mInvRequestXFerId = new_id; - } + if (ft->mFilename.empty()) + { + LL_DEBUGS() << "Task has no inventory" << LL_ENDL; + // mock up some inventory to make a drop target. + if (object->mInventory) + { + object->mInventory->clear(); // will deref and delete it + } + else + { + object->mInventory = new LLInventoryObject::object_list_t(); + } + LLPointer<LLInventoryObject> obj; + obj = new LLInventoryObject(object->mID, LLUUID::null, + LLAssetType::AT_CATEGORY, + "Contents"); + object->mInventory->push_front(obj); + object->doInventoryCallback(); + delete ft; + return; + } + U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), + ft->mFilename, LL_PATH_CACHE, + object->mRegionp->getHost(), + TRUE, + &LLViewerObject::processTaskInvFile, + (void**)ft, + LLXferManager::HIGH_PRIORITY); + if (object->mInvRequestState == INVENTORY_XFER) + { + if (new_id > 0 && new_id != object->mInvRequestXFerId) + { + // we started new download. + gXferManager->abortRequestById(object->mInvRequestXFerId, -1); + object->mInvRequestXFerId = new_id; + } + } + else + { + object->mInvRequestState = INVENTORY_XFER; + object->mInvRequestXFerId = new_id; + } + } } void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status) @@ -3227,6 +3298,13 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS && ft->mSerial >= object->mInventorySerialNum) { object->mInventorySerialNum = ft->mSerial; + LL_DEBUGS() << "Receiving inventory task file for serial " << object->mInventorySerialNum << " taskid: " << ft->mTaskID << LL_ENDL; + if (ft->mSerial < object->mExpectedInventorySerialNum) + { + // User managed to change something while inventory was loading + LL_DEBUGS() << "Processing file that is potentially out of date for task: " << ft->mTaskID << LL_ENDL; + } + if (object->loadTaskInvFile(ft->mFilename)) { @@ -3376,7 +3454,7 @@ void LLViewerObject::removeInventory(const LLUUID& item_id) msg->addUUIDFast(_PREHASH_ItemID, item_id); msg->sendReliable(mRegionp->getHost()); deleteInventoryItem(item_id); - ++mInventorySerialNum; + ++mExpectedInventorySerialNum; } bool LLViewerObject::isTextureInInventory(LLViewerInventoryItem* item) @@ -5839,6 +5917,8 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow if( gAgent.canAccessMaturityAtGlobal(this->getPositionGlobal()) ) { //LL_INFOS() << "Playing attached sound " << audio_uuid << LL_ENDL; + // recheck cutoff radius in case this update was an object-update with new value + mAudioSourcep->checkCutOffRadius(); mAudioSourcep->play(audio_uuid); } } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 873b300489bc8c609e96880f13075a91e2b4fd01..03c5403a1e596ae3cb016006d4edf0143f755897 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -403,6 +403,7 @@ class LLViewerObject // Owner id is this object's owner void setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags); void adjustAudioGain(const F32 gain); + F32 getSoundCutOffRadius() const { return mSoundCutOffRadius; } void clearAttachedSound() { mAudioSourcep = NULL; } // Create if necessary @@ -474,6 +475,8 @@ class LLViewerObject void updateInventoryLocal(LLInventoryItem* item, U8 key); // Update without messaging. void updateTextureInventory(LLViewerInventoryItem* item, U8 key, bool is_new); LLInventoryObject* getInventoryObject(const LLUUID& item_id); + + // Get content except for root category void getInventoryContents(LLInventoryObject::object_list_t& objects); LLInventoryObject* getInventoryRoot(); LLViewerInventoryItem* getInventoryItemByAsset(const LLUUID& asset_id); @@ -623,9 +626,13 @@ class LLViewerObject static void initObjectDataMap(); - // forms task inventory request if none are pending + // forms task inventory request if none are pending, marks request as pending void fetchInventoryFromServer(); + // forms task inventory request after some time passed, marks request as pending + void fetchInventoryDelayed(const F64 &time_seconds); + static void fetchInventoryDelayedCoro(const LLUUID task_inv, const F64 time_seconds); + public: // // Viewer-side only types - use the LL_PCODE_APP mask. @@ -784,6 +791,7 @@ class LLViewerObject LLPointer<LLViewerPartSourceScript> mPartSourcep; // Particle source associated with this object. LLAudioSourceVO* mAudioSourcep; F32 mAudioGain; + F32 mSoundCutOffRadius; F32 mAppAngle; // Apparent visual arc in degrees F32 mPixelArea; // Apparent area in pixels @@ -804,12 +812,14 @@ class LLViewerObject typedef std::list<LLInventoryCallbackInfo*> callback_list_t; callback_list_t mInventoryCallbacks; S16 mInventorySerialNum; + S16 mExpectedInventorySerialNum; enum EInventoryRequestState { INVENTORY_REQUEST_STOPPED, - INVENTORY_REQUEST_PENDING, - INVENTORY_XFER + INVENTORY_REQUEST_WAIT, // delay before requesting + INVENTORY_REQUEST_PENDING, // just did fetchInventoryFromServer() + INVENTORY_XFER // processed response from 'fetch', now doing an xfer }; EInventoryRequestState mInvRequestState; U64 mInvRequestXFerId; diff --git a/indra/newview/llviewerparcelaskplay.cpp b/indra/newview/llviewerparcelaskplay.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4aa783f120a08bc084e5f84ed4929a4ce307626 --- /dev/null +++ b/indra/newview/llviewerparcelaskplay.cpp @@ -0,0 +1,301 @@ +/** + * @file llviewerparcelaskplay.cpp + * @brief stores data about parcel media user wants to auto-play and shows related notifications + * + * $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$ + */ + + +#include "llviewerprecompiledheaders.h" + +#include "llviewerparcelaskplay.h" + +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llparcel.h" +#include "llstartup.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llagent.h" +#include "llsdserialize.h" + +#include <boost/lexical_cast.hpp> + + +// class LLViewerParcelAskPlay + +LLViewerParcelAskPlay::LLViewerParcelAskPlay() : +pNotification(NULL) +{ +} + +LLViewerParcelAskPlay::~LLViewerParcelAskPlay() +{ + +} + +void LLViewerParcelAskPlay::initSingleton() +{ + +} +void LLViewerParcelAskPlay::cleanupSingleton() +{ + cancelNotification(); +} + +void LLViewerParcelAskPlay::askToPlay(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, ask_callback cb) +{ + EAskPlayMode mode = getPlayMode(region_id, parcel_id); + + switch (mode) + { + case ASK_PLAY_IGNORE: + cb(region_id, parcel_id, url, false); + break; + case ASK_PLAY_PLAY: + cb(region_id, parcel_id, url, true); + break; + case ASK_PLAY_ASK: + default: + { + // create or re-create notification + cancelNotification(); + + if (LLStartUp::getStartupState() > STATE_PRECACHE) + { + LLSD args; + args["URL"] = url; + LLSD payload; + payload["url"] = url; // or we can extract it from notification["substitutions"] + payload["parcel_id"] = parcel_id; + payload["region_id"] = region_id; + pNotification = LLNotificationsUtil::add("ParcelPlayingMedia", args, payload, boost::bind(onAskPlayResponse, _1, _2, cb)); + } + else + { + // workaround: avoid 'new notifications arrived' on startup and just play + // (alternative: move to different channel, may be create new one...) + cb(region_id, parcel_id, url, true); + } + } + } +} + +void LLViewerParcelAskPlay::cancelNotification() +{ + if (pNotification) + { + if (!pNotification->isCancelled()) + { + // Force a responce + // Alternative is to mark notification as unique + pNotification->setIgnored(false); + LLNotifications::getInstance()->cancel(pNotification); + } + pNotification = NULL; + } +} + +void LLViewerParcelAskPlay::resetCurrentParcelSetting() +{ + LLParcel *agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (agent_parcel && gAgent.getRegion()) + { + LLViewerParcelAskPlay::resetSetting(gAgent.getRegion()->getRegionID(), agent_parcel->getLocalID()); + } +} + +void LLViewerParcelAskPlay::resetSetting(const LLUUID ®ion_id, const S32 &parcel_id) +{ + region_map_t::iterator found = mRegionMap.find(region_id); + if (found != mRegionMap.end()) + { + found->second.erase(parcel_id); + } +} + +void LLViewerParcelAskPlay::resetSettings() +{ + if (LLViewerParcelAskPlay::instanceExists()) + { + LLViewerParcelAskPlay::getInstance()->mRegionMap.clear(); + } + LLFile::remove(getAskPlayFilename()); +} + +void LLViewerParcelAskPlay::setSetting(const LLUUID ®ion_id, const S32 &parcel_id, const LLViewerParcelAskPlay::ParcelData &data) +{ + mRegionMap[region_id][parcel_id] = data; +} + +LLViewerParcelAskPlay::ParcelData* LLViewerParcelAskPlay::getSetting(const LLUUID ®ion_id, const S32 &parcel_id) +{ + region_map_t::iterator found = mRegionMap.find(region_id); + if (found != mRegionMap.end()) + { + parcel_data_map_t::iterator found_parcel = found->second.find(parcel_id); + if (found_parcel != found->second.end()) + { + return &(found_parcel->second); + } + } + return NULL; +} + +LLViewerParcelAskPlay::EAskPlayMode LLViewerParcelAskPlay::getPlayMode(const LLUUID ®ion_id, const S32 &parcel_id) +{ + EAskPlayMode mode = ASK_PLAY_ASK; + ParcelData* data = getSetting(region_id, parcel_id); + if (data) + { + mode = data->mMode; + // refresh date + data->mDate = LLDate::now(); + } + return mode; +} + +void LLViewerParcelAskPlay::setPlayMode(const LLUUID ®ion_id, const S32 &parcel_id, LLViewerParcelAskPlay::EAskPlayMode mode) +{ + ParcelData data; + data.mMode = mode; + data.mDate = LLDate::now(); + setSetting(region_id, parcel_id, data); +} + +//static +void LLViewerParcelAskPlay::onAskPlayResponse(const LLSD& notification, const LLSD& response, ask_callback cb) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + LLUUID region_id = notification["payload"]["region_id"]; + S32 parcel_id = notification["payload"]["parcel_id"]; + std::string url = notification["payload"]["url"]; + + bool play = option == 1; + + cb(region_id, parcel_id, url, play); + + LLViewerParcelAskPlay *inst = getInstance(); + bool save_choice = inst->pNotification->isIgnored(); // checkbox selected + if (save_choice) + { + EAskPlayMode mode = (play) ? ASK_PLAY_PLAY : ASK_PLAY_IGNORE; + inst->setPlayMode(region_id, parcel_id, mode); + } +} + +// static +std::string LLViewerParcelAskPlay::getAskPlayFilename() +{ + return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_autoplay.xml"); +} + +void LLViewerParcelAskPlay::loadSettings() +{ + mRegionMap.clear(); + + std::string path = getAskPlayFilename(); + if (!gDirUtilp->fileExists(path)) + { + return; + } + + LLSD autoplay_llsd; + llifstream file; + file.open(path.c_str()); + if (!file.is_open()) + { + return; + } + S32 status = LLSDSerialize::fromXML(autoplay_llsd, file); + file.close(); + + if (status == LLSDParser::PARSE_FAILURE || !autoplay_llsd.isMap()) + { + return; + } + + for (LLSD::map_const_iterator iter_region = autoplay_llsd.beginMap(); + iter_region != autoplay_llsd.endMap(); ++iter_region) + { + LLUUID region_id = LLUUID(iter_region->first); + mRegionMap[region_id] = parcel_data_map_t(); + + const LLSD &parcel_map = iter_region->second; + + if (parcel_map.isMap()) + { + for (LLSD::map_const_iterator iter_parcel = parcel_map.beginMap(); + iter_parcel != parcel_map.endMap(); ++iter_parcel) + { + if (!iter_parcel->second.isMap()) + { + break; + } + S32 parcel_id = boost::lexical_cast<S32>(iter_parcel->first.c_str()); + ParcelData data; + data.mMode = (EAskPlayMode)(iter_parcel->second["mode"].asInteger()); + data.mDate = iter_parcel->second["date"].asDate(); + mRegionMap[region_id][parcel_id] = data; + } + } + } +} + +void LLViewerParcelAskPlay::saveSettings() +{ + LLSD write_llsd; + std::string key; + for (region_map_t::iterator iter_region = mRegionMap.begin(); + iter_region != mRegionMap.end(); ++iter_region) + { + if (iter_region->second.empty()) + { + continue; + } + key = iter_region->first.asString(); + write_llsd[key] = LLSD(); + + for (parcel_data_map_t::iterator iter_parcel = iter_region->second.begin(); + iter_parcel != iter_region->second.end(); ++iter_parcel) + { + if ((iter_parcel->second.mDate.secondsSinceEpoch() + (F64SecondsImplicit)U32Days(30)) > LLTimer::getTotalSeconds()) + { + // write unexpired parcels + std::string parcel_id = boost::lexical_cast<std::string>(iter_parcel->first); + write_llsd[key][parcel_id] = LLSD(); + write_llsd[key][parcel_id]["mode"] = (LLSD::Integer)iter_parcel->second.mMode; + write_llsd[key][parcel_id]["date"] = iter_parcel->second.mDate; + } + } + } + + llofstream file; + file.open(getAskPlayFilename().c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(write_llsd, file); + file.close(); + } +} + diff --git a/indra/newview/llviewerparcelaskplay.h b/indra/newview/llviewerparcelaskplay.h new file mode 100644 index 0000000000000000000000000000000000000000..dc711917d29368f1e755d6ecd0594a6833782e31 --- /dev/null +++ b/indra/newview/llviewerparcelaskplay.h @@ -0,0 +1,89 @@ +/** + * @file llviewerparcelaskplay.h + * @brief stores data about parcel media user wants to auto-play and shows related notifications + * + * $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$ + */ + +#ifndef LLVIEWERPARCELASKPLAY_H +#define LLVIEWERPARCELASKPLAY_H + +#include "llnotificationptr.h" +#include "lluuid.h" + +class LLViewerParcelAskPlay : public LLSingleton<LLViewerParcelAskPlay> +{ + LLSINGLETON(LLViewerParcelAskPlay); + ~LLViewerParcelAskPlay(); + void initSingleton(); + void cleanupSingleton(); +public: + // functor expects functor(region_id, parcel_id, url, play/stop) + typedef boost::function<void(const LLUUID&, const S32&, const std::string&, const bool&)> ask_callback; + void askToPlay(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, ask_callback cb); + void cancelNotification(); + + void resetCurrentParcelSetting(); + void resetSetting(const LLUUID ®ion_id, const S32 &parcel_id); + static void resetSettings(); + + void loadSettings(); + void saveSettings(); + + S32 hasData() { return !mRegionMap.empty(); } // subsitution for 'isInitialized' + +private: + enum EAskPlayMode{ + ASK_PLAY_IGNORE = 0, + ASK_PLAY_PLAY, + ASK_PLAY_ASK + }; + + class ParcelData + { + public: + LLDate mDate; + EAskPlayMode mMode; + }; + + void setSetting(const LLUUID ®ion_id, const S32 &parcel_id, const ParcelData &data); + ParcelData* getSetting(const LLUUID ®ion_id, const S32 &parcel_id); + EAskPlayMode getPlayMode(const LLUUID ®ion_id, const S32 &parcel_id); + void setPlayMode(const LLUUID ®ion_id, const S32 &parcel_id, EAskPlayMode); + + static void onAskPlayResponse(const LLSD& notification, const LLSD& response, ask_callback cb); + + static std::string getAskPlayFilename(); + +private: + // Variables + + typedef std::map<S32, ParcelData> parcel_data_map_t; + typedef std::map<LLUUID, parcel_data_map_t> region_map_t; + region_map_t mRegionMap; + + // only one notification is supposed to exists and be visible + LLNotificationPtr pNotification; +}; + + +#endif // LLVIEWERPARCELASKPLAY_H diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp index b5a76ccba2a9c2d4fca938e9e417650da45951d0..54d9804b9c5bb46026a094a606a0552d270ee3c5 100644 --- a/indra/newview/llviewerparcelmediaautoplay.cpp +++ b/indra/newview/llviewerparcelmediaautoplay.cpp @@ -24,17 +24,20 @@ * $/LicenseInfo$ */ + #include "llviewerprecompiledheaders.h" + #include "llviewerparcelmediaautoplay.h" -#include "llviewerparcelmedia.h" + +#include "llparcel.h" #include "llviewercontrol.h" #include "llviewermedia.h" -#include "llviewerregion.h" -#include "llparcel.h" +#include "llviewerparcelaskplay.h" +#include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" -#include "lluuid.h" -#include "message.h" +#include "llviewerregion.h" #include "llviewertexturelist.h" // for texture stats +#include "message.h" #include "llagent.h" #include "llmimetypes.h" @@ -122,11 +125,28 @@ BOOL LLViewerParcelMediaAutoPlay::tick() { if (this_parcel) { - if (gSavedSettings.getBOOL("ParcelMediaAutoPlayEnable")) + static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable"); + + switch (autoplay_mode()) { - // and last but not least, only play when autoplay is enabled - LLViewerParcelMedia::getInstance()->play(this_parcel); - } + case 0: + // Disabled + break; + case 1: + // Play, default value for ParcelMediaAutoPlayEnable + LLViewerParcelMedia::getInstance()->play(this_parcel); + break; + case 2: + default: + { + // Ask + LLViewerParcelAskPlay::getInstance()->askToPlay(this_region->getRegionID(), + this_parcel->getLocalID(), + this_parcel->getMediaURL(), + onStartMusicResponse); + break; + } + } } mPlayed = TRUE; @@ -139,5 +159,18 @@ BOOL LLViewerParcelMediaAutoPlay::tick() return FALSE; // continue ticking forever please. } - +//static +void LLViewerParcelMediaAutoPlay::onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play) +{ + if (play) + { + LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + + // make sure we are still there + if (parcel->getLocalID() == parcel_id && gAgent.getRegion()->getRegionID() == region_id) + { + LLViewerParcelMedia::play(parcel); + } + } +} diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h index 33565307f285e2c5ab84d5c79593c18edaccff4c..cf8e9a97e76149346c1ab932bf930a795de9b40d 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -38,6 +38,9 @@ class LLViewerParcelMediaAutoPlay : LLEventTimer, public LLSingleton<LLViewerPar virtual BOOL tick(); static void playStarted(); + private: + static void onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); + private: S32 mLastParcelID; LLUUID mLastRegionID; diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 6cc88d0c0be698ba7956a4469ed5c94d464b0cd8..d91d0abb991ecb81f4b7e5457a50935f48531287 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -42,6 +42,7 @@ // Viewer includes #include "llagent.h" #include "llagentaccess.h" +#include "llviewerparcelaskplay.h" #include "llviewerwindow.h" #include "llviewercontrol.h" //#include "llfirstuse.h" @@ -1832,6 +1833,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use // Only update stream if parcel changed (recreated) or music is playing (enabled) if (!agent_parcel_update || gSavedSettings.getBOOL("MediaTentativeAutoPlay")) { + LLViewerParcelAskPlay::getInstance()->cancelNotification(); std::string music_url_raw = parcel->getMusicURL(); // Trim off whitespace from front and back @@ -1843,7 +1845,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use { if (music_url.substr(0, 7) == "http://") { - optionally_start_music(music_url); + LLViewerRegion *region = LLWorld::getInstance()->getRegion(msg->getSender()); + optionally_start_music(music_url, parcel->mLocalID, region->getRegionID()); } else { @@ -1864,25 +1867,61 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use else { // Public land has no music + LLViewerParcelAskPlay::getInstance()->cancelNotification(); LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade(); } }//if gAudiop }; } -void LLViewerParcelMgr::optionally_start_music(const std::string& music_url) +//static +void LLViewerParcelMgr::onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play) { - if (gSavedSettings.getBOOL("AudioStreamingMusic")) + if (play) + { + LL_INFOS("ParcelMgr") << "Starting parcel music " << url << LL_ENDL; + LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(url); + } +} + +void LLViewerParcelMgr::optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id) +{ + static LLCachedControl<bool> streaming_music(gSavedSettings, "AudioStreamingMusic", true); + if (streaming_music) { + static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable", 1); + static LLCachedControl<bool> tentative_autoplay(gSavedSettings, "MediaTentativeAutoPlay", true); // only play music when you enter a new parcel if the UI control for this // was not *explicitly* stopped by the user. (part of SL-4878) LLPanelNearByMedia* nearby_media_panel = gStatusBar->getNearbyMediaPanel(); - if ((nearby_media_panel && - nearby_media_panel->getParcelAudioAutoStart()) || - // or they have expressed no opinion in the UI, but have autoplay on... - (!nearby_media_panel && - gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay"))) + + // ask mode //todo constants + if (autoplay_mode == 2) + { + // stop previous stream + LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); + + // if user set media to play - ask + if ((nearby_media_panel && nearby_media_panel->getParcelAudioAutoStart()) + || (!nearby_media_panel && tentative_autoplay)) + { + LLViewerParcelAskPlay::getInstance()->askToPlay(region_id, + local_id, + music_url, + onStartMusicResponse); + } + else + { + LLViewerParcelAskPlay::getInstance()->cancelNotification(); + } + } + // autoplay + else if ((nearby_media_panel + && nearby_media_panel->getParcelAudioAutoStart()) + // or they have expressed no opinion in the UI, but have autoplay on... + || (!nearby_media_panel + && autoplay_mode == 1 + && tentative_autoplay)) { LL_INFOS("ParcelMgr") << "Starting parcel music " << music_url << LL_ENDL; LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(music_url); diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 29219843c9ef20b3ea5161a9d28dcd65b37882d4..288077fafc8a9624cf25b59446c6d37c108abf53 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -268,7 +268,8 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr> // *NOTE: Taken out 2005-03-21. Phoenix. //void makeLandmarkAtSelection(); - static void optionally_start_music(const std::string& music_url); + static void onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); + static void optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id); static void processParcelOverlay(LLMessageSystem *msg, void **user_data); static void processParcelProperties(LLMessageSystem *msg, void **user_data); diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 15b2ac8acf0d90501259e9b80b715e61afbd8b74..85d87a43af72a1fbbef76519563a0f6e031d6b44 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -359,16 +359,19 @@ void update_statistics() record(LLStatViewer::REBUILD_STACKTIME, last_frame_recording.getSum(*stat_type_t::getInstance("Sort Draw State"))); record(LLStatViewer::RENDER_STACKTIME, last_frame_recording.getSum(*stat_type_t::getInstance("Render Geometry"))); - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost()); - if (cdp) + if (gAgent.getRegion() && isAgentAvatarValid()) { - sample(LLStatViewer::SIM_PING, F64Milliseconds (cdp->getPingDelay())); - gAvgSimPing = ((gAvgSimPing * gSimPingCount) + cdp->getPingDelay()) / (gSimPingCount + 1); - gSimPingCount++; - } - else - { - sample(LLStatViewer::SIM_PING, U32Seconds(10)); + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost()); + if (cdp) + { + sample(LLStatViewer::SIM_PING, F64Milliseconds(cdp->getPingDelay())); + gAvgSimPing = ((gAvgSimPing * gSimPingCount) + cdp->getPingDelay()) / (gSimPingCount + 1); + gSimPingCount++; + } + else + { + sample(LLStatViewer::SIM_PING, U32Seconds(10)); + } } if (LLViewerStats::instance().getRecording().getSum(LLStatViewer::FPS)) diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 06524847d1780783df9272812a8d2a33f24b2148..561319ca5d2b4eb61e555f3b4e9bbbc4271d7c17 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1385,8 +1385,6 @@ S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, fl { max_texmem = (S32Megabytes)128; } - - LL_WARNS() << "VRAM amount not detected, defaulting to " << max_texmem << " MB" << LL_ENDL; } S32Megabytes system_ram = gSysMemory.getPhysicalMemoryKB(); // In MB @@ -1428,6 +1426,11 @@ void LLViewerTextureList::updateMaxResidentTexMem(S32Megabytes mem) return; //listener will re-enter this function } + if (gGLManager.mVRAM == 0) + { + LL_WARNS() << "VRAM amount not detected, defaulting to " << mem << " MB" << LL_ENDL; + } + // TODO: set available resident texture mem based on use by other subsystems // currently max(12MB, VRAM/4) assumed... diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 61f4ee463dc70d95d222a6ec108255f6c46c7bc7..7f87836644fa2ba6773dc035abe1475e6a8d5e58 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -45,7 +45,8 @@ #include "llmeshrepository.h" #include "llnotificationhandler.h" #include "llpanellogin.h" -#include "llviewerkeyboard.h" +#include "llsetkeybinddialog.h" +#include "llviewerinput.h" #include "llviewermenu.h" #include "llviewquery.h" @@ -173,7 +174,7 @@ #include "llviewergesture.h" #include "llviewertexturelist.h" #include "llviewerinventory.h" -#include "llviewerkeyboard.h" +#include "llviewerinput.h" #include "llviewermedia.h" #include "llviewermediafocus.h" #include "llviewermenu.h" @@ -898,7 +899,18 @@ LLViewerWindow::Params::Params() {} -BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) +void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask) +{ + if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized()) + { + // If the current tool didn't process the click, we should show + // the pie menu. This can be done by passing the event to the pie + // menu tool. + LLToolPie::getInstance()->handleRightMouseDown(x, y, mask); + } +} + +BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down) { const char* buttonname = ""; const char* buttonstatestr = ""; @@ -922,22 +934,30 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK switch (clicktype) { - case LLMouseHandler::CLICK_LEFT: + case CLICK_LEFT: mLeftMouseDown = down; buttonname = "Left"; break; - case LLMouseHandler::CLICK_RIGHT: + case CLICK_RIGHT: mRightMouseDown = down; buttonname = "Right"; break; - case LLMouseHandler::CLICK_MIDDLE: + case CLICK_MIDDLE: mMiddleMouseDown = down; buttonname = "Middle"; break; - case LLMouseHandler::CLICK_DOUBLELEFT: + case CLICK_DOUBLELEFT: mLeftMouseDown = down; buttonname = "Left Double Click"; break; + case CLICK_BUTTON4: + buttonname = "Button 4"; + break; + case CLICK_BUTTON5: + buttonname = "Button 5"; + break; + default: + break; // COUNT and NONE } LLView::sMouseHandlerMessage.clear(); @@ -988,6 +1008,11 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname)); } + else if (down && clicktype == CLICK_RIGHT) + { + handlePieMenu(x, y, mask); + r = TRUE; + } return r; } @@ -1034,7 +1059,12 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK return TRUE; } - + if (down && clicktype == CLICK_RIGHT) + { + handlePieMenu(x, y, mask); + return TRUE; + } + // If we got this far on a down-click, it wasn't handled. // Up-clicks, though, are always handled as far as the OS is concerned. BOOL default_rtn = !down; @@ -1053,7 +1083,8 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask mMouseDownTimer.reset(); } BOOL down = TRUE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); + //handleMouse() loops back to LLViewerWindow::handleAnyMouseClick + return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down); } BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask) @@ -1061,8 +1092,7 @@ BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK ma // try handling as a double-click first, then a single-click if that // wasn't handled. BOOL down = TRUE; - if (handleAnyMouseClick(window, pos, mask, - LLMouseHandler::CLICK_DOUBLELEFT, down)) + if (gViewerInput.handleMouse(window, pos, mask, CLICK_DOUBLELEFT, down)) { return TRUE; } @@ -1076,47 +1106,24 @@ BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) mMouseDownTimer.stop(); } BOOL down = FALSE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); + return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down); } - - BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) { - S32 x = pos.mX; - S32 y = pos.mY; - x = ll_round((F32)x / mDisplayScale.mV[VX]); - y = ll_round((F32)y / mDisplayScale.mV[VY]); - BOOL down = TRUE; - BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); - if (handle) - return handle; - - // *HACK: this should be rolled into the composite tool logic, not - // hardcoded at the top level. - if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized()) - { - // If the current tool didn't process the click, we should show - // the pie menu. This can be done by passing the event to the pie - // menu tool. - LLToolPie::getInstance()->handleRightMouseDown(x, y, mask); - // show_context_menu( x, y, mask ); - } - - return TRUE; + return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down); } BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = FALSE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); + return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down); } BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = TRUE; - LLVoiceClient::getInstance()->middleMouseState(true); - handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down); // Always handled as far as the OS is concerned. return TRUE; @@ -1267,17 +1274,44 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi return result; } - + BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = FALSE; - LLVoiceClient::getInstance()->middleMouseState(false); - handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down); // Always handled as far as the OS is concerned. return TRUE; } +BOOL LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask, S32 button, bool down) +{ + switch (button) + { + case 4: + gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON4, down); + break; + case 5: + gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON5, down); + break; + default: + break; + } + + // Always handled as far as the OS is concerned. + return TRUE; +} + +BOOL LLViewerWindow::handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button) +{ + return handleOtherMouse(window, pos, mask, button, TRUE); +} + +BOOL LLViewerWindow::handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button) +{ + return handleOtherMouse(window, pos, mask, button, FALSE); +} + // WARNING: this is potentially called multiple times per frame void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask) { @@ -1404,9 +1438,6 @@ void LLViewerWindow::handleFocusLost(LLWindow *window) BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) { - // Let the voice chat code check for its PTT key. Note that this never affects event processing. - LLVoiceClient::getInstance()->keyDown(key, mask); - if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME) { gAgent.clearAFK(); @@ -1425,14 +1456,12 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) return FALSE; } - return gViewerKeyboard.handleKey(key, mask, repeated); + // remaps, handles ignored cases and returns back to viewer window. + return gViewerInput.handleKey(key, mask, repeated); } BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask) { - // Let the voice chat code check for its PTT key. Note that this never affects event processing. - LLVoiceClient::getInstance()->keyUp(key, mask); - // Let the inspect tool code check for ALT key to set LLToolSelectRect active instead LLToolCamera LLToolCompInspect * tool_inspectp = LLToolCompInspect::getInstance(); if (LLToolMgr::getInstance()->getCurrentTool() == tool_inspectp) @@ -1440,13 +1469,13 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask) tool_inspectp->keyUp(key, mask); } - return gViewerKeyboard.handleKeyUp(key, mask); + return gViewerInput.handleKeyUp(key, mask); } void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) { LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true); - gViewerKeyboard.scanKey(key, key_down, key_up, key_level); + gViewerInput.scanKey(key, key_down, key_up, key_level); return; // Be clear this function returns nothing } @@ -1551,6 +1580,11 @@ void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks) handleScrollWheel( clicks ); } +void LLViewerWindow::handleScrollHWheel(LLWindow *window, S32 clicks) +{ + handleScrollHWheel(clicks); +} + void LLViewerWindow::handleWindowBlock(LLWindow *window) { send_agent_pause(); @@ -1951,6 +1985,11 @@ void LLViewerWindow::initBase() LLPanel* panel_holder = main_view->getChild<LLPanel>("toolbar_view_holder"); // Load the toolbar view from file gToolBarView = LLUICtrlFactory::getInstance()->createFromFile<LLToolBarView>("panel_toolbar_view.xml", panel_holder, LLDefaultChildRegistry::instance()); + if (!gToolBarView) + { + LL_ERRS() << "Failed to initialize viewer: Viewer couldn't process file panel_toolbar_view.xml, " + << "if this problem happens again, please validate your installation." << LL_ENDL; + } gToolBarView->setShape(panel_holder->getLocalRect()); // Hide the toolbars for the moment: we'll make them visible after logging in world (see LLViewerWindow::initWorldUI()) gToolBarView->setVisible(FALSE); @@ -2676,6 +2715,14 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) // hide tooltips on keypress LLToolTipMgr::instance().blockToolTips(); + // let menus handle navigation keys for navigation + if (LLSetKeyBindDialog::recordKey(key, mask)) + { + LL_DEBUGS() << "Key handled by LLSetKeyBindDialog" << LL_ENDL; + LLViewerEventRecorder::instance().logKeyEvent(key,mask); + return TRUE; + } + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); if (keyboard_focus @@ -2836,7 +2883,8 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook, // no view has keyboard focus, this is a printable character key (and no modifier key is // pressed except shift), then give focus to nearby chat (STORM-560) - if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && + if ( LLStartUp::getStartupState() >= STATE_STARTED && + gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) ) { // Initialize nearby chat if it's missing @@ -2890,7 +2938,8 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask) { if (mask != MASK_ALT) { - return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN)); + // remaps, handles ignored cases and returns back to viewer window. + return gViewerInput.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN)); } } @@ -2966,6 +3015,49 @@ void LLViewerWindow::handleScrollWheel(S32 clicks) return; } +void LLViewerWindow::handleScrollHWheel(S32 clicks) +{ + LLUI::resetMouseIdleTimer(); + + LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); + if (mouse_captor) + { + S32 local_x; + S32 local_y; + mouse_captor->screenPointToLocal(mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y); + mouse_captor->handleScrollHWheel(local_x, local_y, clicks); + if (LLView::sDebugMouseHandling) + { + LL_INFOS() << "Scroll Horizontal Wheel handled by captor " << mouse_captor->getName() << LL_ENDL; + } + return; + } + + LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); + if (top_ctrl) + { + S32 local_x; + S32 local_y; + top_ctrl->screenPointToLocal(mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y); + if (top_ctrl->handleScrollHWheel(local_x, local_y, clicks)) return; + } + + if (mRootView->handleScrollHWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks)) + { + if (LLView::sDebugMouseHandling) + { + LL_INFOS() << "Scroll Horizontal Wheel" << LLView::sMouseHandlerMessage << LL_ENDL; + } + return; + } + else if (LLView::sDebugMouseHandling) + { + LL_INFOS() << "Scroll Horizontal Wheel not handled by view" << LL_ENDL; + } + + return; +} + void LLViewerWindow::addPopup(LLView* popup) { if (mPopupView) @@ -3329,7 +3421,8 @@ void LLViewerWindow::updateUI() LLRect screen_sticky_rect = mRootView->getLocalRect(); S32 local_x, local_y; - if (gSavedSettings.getBOOL("DebugShowXUINames")) + static LLCachedControl<bool> debug_show_xui_names(gSavedSettings, "DebugShowXUINames", 0); + if (debug_show_xui_names) { LLToolTip::Params params; @@ -4485,12 +4578,12 @@ void LLViewerWindow::movieSize(S32 new_width, S32 new_height) } } -BOOL LLViewerWindow::saveSnapshot(const std::string& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, LLSnapshotModel::ESnapshotFormat format) +BOOL LLViewerWindow::saveSnapshot(const std::string& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, LLSnapshotModel::ESnapshotFormat format) { LL_INFOS() << "Saving snapshot to: " << filepath << LL_ENDL; LLPointer<LLImageRaw> raw = new LLImageRaw; - BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild); + BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, show_hud, do_rebuild); if (success) { @@ -4549,16 +4642,16 @@ void LLViewerWindow::resetSnapshotLoc() const gSavedPerAccountSettings.setString("SnapshotBaseDir", std::string()); } -BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type) +BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type) { - return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type); + return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, show_hud, do_rebuild, type); } // Saves the image from the screen to a raw image // Since the required size might be bigger than the available screen, this method rerenders the scene in parts (called subimages) and copy // the results over to the final raw image. BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, - BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, S32 max_size) + BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, S32 max_size) { if (!raw) { @@ -4592,7 +4685,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI); } - BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments; + BOOL hide_hud = !show_hud && LLPipeline::sShowHUDAttachments; if (hide_hud) { LLPipeline::sShowHUDAttachments = FALSE; @@ -4632,7 +4725,8 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei if ((image_width <= gGLManager.mGLMaxTextureSize && image_height <= gGLManager.mGLMaxTextureSize) && (image_width > window_width || image_height > window_height) && LLPipeline::sRenderDeferred && !show_ui) { - if (scratch_space.allocate(image_width, image_height, GL_DEPTH_COMPONENT, true, true)) + U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA; + if (scratch_space.allocate(image_width, image_height, color_fmt, true, true)) { original_width = gPipeline.mDeferredScreen.getWidth(); original_height = gPipeline.mDeferredScreen.getHeight(); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 071a3632ddb5be7c2c422f486e87ab7891162d0a..1f49c0756c98e5fe0ef78928728ee82896ad4cf2 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -175,8 +175,9 @@ class LLViewerWindow : public LLWindowCallbacks void initWorldUI(); void setUIVisibility(bool); bool getUIVisibility(); + void handlePieMenu(S32 x, S32 y, MASK mask); - BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down); + BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down); // // LLWindowCallback interface implementation @@ -192,7 +193,10 @@ class LLViewerWindow : public LLWindowCallbacks /*virtual*/ BOOL handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); - /*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + /*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + /*virtual*/ BOOL handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); + /*virtual*/ BOOL handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); + BOOL handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask, S32 button, bool down); /*virtual*/ LLWindowCallbacks::DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data); void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); void handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask); @@ -205,6 +209,7 @@ class LLViewerWindow : public LLWindowCallbacks /*virtual*/ void handleMenuSelect(LLWindow *window, S32 menu_item); /*virtual*/ BOOL handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height); /*virtual*/ void handleScrollWheel(LLWindow *window, S32 clicks); + /*virtual*/ void handleScrollHWheel(LLWindow *window, S32 clicks); /*virtual*/ BOOL handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ void handleWindowBlock(LLWindow *window); /*virtual*/ void handleWindowUnblock(LLWindow *window); @@ -323,6 +328,7 @@ class LLViewerWindow : public LLWindowCallbacks BOOL handleKey(KEY key, MASK mask); BOOL handleKeyUp(KEY key, MASK mask); void handleScrollWheel (S32 clicks); + void handleScrollHWheel (S32 clicks); // add and remove views from "popup" layer void addPopup(LLView* popup); @@ -347,10 +353,10 @@ class LLViewerWindow : public LLWindowCallbacks // snapshot functionality. // perhaps some of this should move to llfloatershapshot? -MG - BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::ESnapshotFormat format = LLSnapshotModel::SNAPSHOT_FORMAT_BMP); + BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL show_hud = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::ESnapshotFormat format = LLSnapshotModel::SNAPSHOT_FORMAT_BMP); BOOL rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE, - BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE); - BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type); + BOOL show_ui = TRUE, BOOL show_hud = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE); + BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type); BOOL isSnapshotLocSet() const; void resetSnapshotLoc() const; diff --git a/indra/newview/llviewerwindowlistener.cpp b/indra/newview/llviewerwindowlistener.cpp index 97b405c1d0943ed0f61f0cf72d79ba00e12f8bf1..acf25b9792fc4cfc3636b051fac07d34972c2b8c 100644 --- a/indra/newview/llviewerwindowlistener.cpp +++ b/indra/newview/llviewerwindowlistener.cpp @@ -50,10 +50,11 @@ LLViewerWindowListener::LLViewerWindowListener(LLViewerWindow* llviewerwindow): // saveSnapshotArgs["width"] = LLSD::Integer(); // saveSnapshotArgs["height"] = LLSD::Integer(); // saveSnapshotArgs["showui"] = LLSD::Boolean(); +// saveSnapshotArgs["showhud"] = LLSD::Boolean(); // saveSnapshotArgs["rebuild"] = LLSD::Boolean(); // saveSnapshotArgs["type"] = LLSD::String(); add("saveSnapshot", - "Save screenshot: [\"filename\"], [\"width\"], [\"height\"], [\"showui\"], [\"rebuild\"], [\"type\"]\n" + "Save screenshot: [\"filename\"], [\"width\"], [\"height\"], [\"showui\"], [\"showhud\"], [\"rebuild\"], [\"type\"]\n" "type: \"COLOR\", \"DEPTH\"\n" "Post on [\"reply\"] an event containing [\"ok\"]", &LLViewerWindowListener::saveSnapshot, @@ -83,6 +84,9 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const bool showui = true; if (event.has("showui")) showui = event["showui"].asBoolean(); + bool showhud = true; + if (event.has("showhud")) + showhud = event["showhud"].asBoolean(); bool rebuild(event["rebuild"]); // defaults to false LLSnapshotModel::ESnapshotLayerType type(LLSnapshotModel::SNAPSHOT_TYPE_COLOR); if (event.has("type")) @@ -96,7 +100,7 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const } type = found->second; } - bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, rebuild, type); + bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, showhud, rebuild, type); sendReply(LLSDMap("ok", ok), event); } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index ca1216b89db6790c1eae95f14f5404cc0be26f36..3c4c785a42512548a38525cb3b45dcba29b4e8bb 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -78,6 +78,7 @@ #include "llselectmgr.h" #include "llsprite.h" #include "lltargetingmotion.h" +#include "lltoolmgr.h" #include "lltoolmorph.h" #include "llviewercamera.h" #include "llviewertexlayer.h" @@ -882,8 +883,9 @@ BOOL LLVOAvatar::hasGray() const S32 LLVOAvatar::getRezzedStatus() const { if (getIsCloud()) return 0; - if (isFullyTextured() && allBakedTexturesCompletelyDownloaded()) return 3; - if (isFullyTextured()) return 2; + bool textured = isFullyTextured(); + if (textured && allBakedTexturesCompletelyDownloaded()) return 3; + if (textured) return 2; llassert(hasGray()); return 1; // gray } @@ -2044,8 +2046,10 @@ void LLVOAvatar::resetSkeleton(bool reset_animations) LL_ERRS() << "Error resetting skeleton" << LL_ENDL; } - // Reset attachment points (buildSkeleton only does bones and CVs) - bool ignore_hud_joints = true; + // Reset attachment points + // BuildSkeleton only does bones and CVs but we still need to reinit huds + // since huds can be animated. + bool ignore_hud_joints = !isSelf(); initAttachmentPoints(ignore_hud_joints); // Fix up collision volumes @@ -4803,6 +4807,15 @@ U32 LLVOAvatar::renderSkinned() BOOL first_pass = TRUE; if (!LLDrawPoolAvatar::sSkipOpaque) { + if (isUIAvatar() && mIsDummy) + { + LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR); + if (hair_mesh) + { + num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy); + } + first_pass = FALSE; + } if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) { if (isTextureVisible(TEX_HEAD_BAKED) || isUIAvatar()) @@ -4810,7 +4823,7 @@ U32 LLVOAvatar::renderSkinned() LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD); if (head_mesh) { - num_indices += head_mesh->render(mAdjustedPixelArea, TRUE, mIsDummy); + num_indices += head_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy); } first_pass = FALSE; } @@ -5646,7 +5659,7 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL } else { - LL_WARNS() << "Failed to start motion!" << LL_ENDL; + LL_WARNS("Motion") << "Failed to start motion!" << LL_ENDL; } } else //stop animation @@ -5753,13 +5766,13 @@ LLUUID LLVOAvatar::remapMotionID(const LLUUID& id) //----------------------------------------------------------------------------- BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) { - LL_DEBUGS() << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << LL_ENDL; + LL_DEBUGS("Motion") << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << LL_ENDL; LLUUID remap_id = remapMotionID(id); if (remap_id != id) { - LL_DEBUGS() << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << LL_ENDL; + LL_DEBUGS("Motion") << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << LL_ENDL; } if (isSelf() && remap_id == ANIM_AGENT_AWAY) @@ -5775,13 +5788,13 @@ BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) //----------------------------------------------------------------------------- BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate) { - LL_DEBUGS() << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << LL_ENDL; + LL_DEBUGS("Motion") << "Motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << LL_ENDL; LLUUID remap_id = remapMotionID(id); if (remap_id != id) { - LL_DEBUGS() << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << LL_ENDL; + LL_DEBUGS("Motion") << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << LL_ENDL; } if (isSelf()) @@ -6575,7 +6588,7 @@ void LLVOAvatar::initAttachmentPoints(bool ignore_hud_joints) LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter; if (info->mIsHUDAttachment && (!isSelf() || ignore_hud_joints)) { - //don't process hud joint for other avatars, or when doing a skeleton reset. + //don't process hud joint for other avatars. continue; } @@ -7320,6 +7333,19 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object) { gAgentCamera.changeCameraToMouselook(); } + + if (gAgentCamera.getFocusOnAvatar() && LLToolMgr::getInstance()->inEdit()) + { + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node && node->mValid) + { + LLViewerObject* root_object = node->getObject(); + if (root_object == sit_object) + { + LLFloaterTools::sPreviousFocusOnAvatar = true; + } + } + } } if (mDrawable.isNull()) @@ -7600,14 +7626,13 @@ bool LLVOAvatar::getIsCloud() const ); } -void LLVOAvatar::updateRezzedStatusTimers() +void LLVOAvatar::updateRezzedStatusTimers(S32 rez_status) { // State machine for rezzed status. Statuses are -1 on startup, 0 // = cloud, 1 = gray, 2 = downloading, 3 = full. // Purpose is to collect time data for each it takes avatar to reach // various loading landmarks: gray, textured (partial), textured fully. - S32 rez_status = getRezzedStatus(); if (rez_status != mLastRezzedStatus) { LL_DEBUGS("Avatar") << avString() << "rez state change: " << mLastRezzedStatus << " -> " << rez_status << LL_ENDL; @@ -7777,8 +7802,13 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse // returns true if the value has changed. BOOL LLVOAvatar::updateIsFullyLoaded() { - const bool loading = getIsCloud(); - updateRezzedStatusTimers(); + S32 rez_status = getRezzedStatus(); + bool loading = getIsCloud(); + if (mFirstFullyVisible && !mIsControlAvatar && rez_status < 3) + { + loading = ((rez_status < 2) || !isFullyBaked()); + } + updateRezzedStatusTimers(rez_status); updateRuthTimer(loading); return processFullyLoadedChange(loading); } @@ -7814,13 +7844,22 @@ void LLVOAvatar::updateRuthTimer(bool loading) BOOL LLVOAvatar::processFullyLoadedChange(bool loading) { - // we wait a little bit before giving the all clear, - // to let textures settle down - const F32 PAUSE = 1.f; + // We wait a little bit before giving the 'all clear', to let things to + // settle down (models to snap into place, textures to get first packets) + const F32 LOADED_DELAY = 1.f; + const F32 FIRST_USE_DELAY = 3.f; + if (loading) mFullyLoadedTimer.reset(); - - mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE); + + if (mFirstFullyVisible) + { + mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > FIRST_USE_DELAY); + } + else + { + mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > LOADED_DELAY); + } if (!mPreviousFullyLoaded && !loading && mFullyLoaded) { diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 00dccc5d1215c66a7503f61109583bb79b96c403..e352a6c1fafccb82d624eb53ef3b8dd73f2de7e7 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -348,7 +348,7 @@ class LLVOAvatar : BOOL isFullyTextured() const; BOOL hasGray() const; S32 getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = textured, 3 = textured and fully downloaded. - void updateRezzedStatusTimers(); + void updateRezzedStatusTimers(S32 status); S32 mLastRezzedStatus; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 63ace4fe5298931dcd190779cc4673915ef77700..16b27fd1445cd3283639c6087b3d50e7d5396f2a 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1250,7 +1250,7 @@ BOOL LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id) gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id); - gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); + gMessageSystem->sendReliable(gAgent.getRegionHost()); // This object might have been selected, so let the selection manager know it's gone now LLViewerObject *found_obj = gObjectList.findObject(item_id); diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index d8c8cb04614f5d6e414f108435871484f9542890..fca8de7410c354a8e87101b5cecdec6ca70f0798 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -125,7 +125,7 @@ LLVoiceClient::LLVoiceClient(LLPumpIO *pump) mPTTDirty(true), mPTT(true), mUsePTT(true), - mPTTIsMiddleMouse(false), + mPTTMouseButton(0), mPTTKey(0), mPTTIsToggle(false), mUserPTTState(false), @@ -200,8 +200,6 @@ const LLVoiceVersionInfo LLVoiceClient::getVersion() void LLVoiceClient::updateSettings() { setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled")); - std::string keyString = gSavedSettings.getString("PushToTalkButton"); - setPTTKey(keyString); setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle")); mDisableMic = gSavedSettings.getBOOL("VoiceDisableMic"); @@ -637,23 +635,6 @@ bool LLVoiceClient::getPTTIsToggle() return mPTTIsToggle; } -void LLVoiceClient::setPTTKey(std::string &key) -{ - if(key == "MiddleMouse") - { - mPTTIsMiddleMouse = true; - } - else - { - mPTTIsMiddleMouse = false; - if(!LLKeyboard::keyFromString(key, &mPTTKey)) - { - // If the call failed, don't match any key. - key = KEY_NONE; - } - } -} - void LLVoiceClient::inputUserControlState(bool down) { if(mPTTIsToggle) @@ -674,43 +655,6 @@ void LLVoiceClient::toggleUserPTTState(void) setUserPTTState(!getUserPTTState()); } -void LLVoiceClient::keyDown(KEY key, MASK mask) -{ - if (gKeyboard->getKeyRepeated(key)) - { - // ignore auto-repeat keys - return; - } - - if (!mPTTIsMiddleMouse && LLAgent::isActionAllowed("speak") && (key == mPTTKey)) - { - bool down = gKeyboard->getKeyDown(mPTTKey); - if (down) - { - inputUserControlState(down); - } - } - -} -void LLVoiceClient::keyUp(KEY key, MASK mask) -{ - if (!mPTTIsMiddleMouse && (key == mPTTKey)) - { - bool down = gKeyboard->getKeyDown(mPTTKey); - if (!down) - { - inputUserControlState(down); - } - } -} -void LLVoiceClient::middleMouseState(bool down) -{ - if(mPTTIsMiddleMouse && LLAgent::isActionAllowed("speak")) - { - inputUserControlState(down); - } -} - //------------------------------------------- // nearby speaker accessors diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index f95b853c31daf475ee8b2936e639189576e14cda..cecaac7f856421e7e9a9ac6409e9b692d045ed80 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -408,17 +408,11 @@ class LLVoiceClient: public LLParamSingleton<LLVoiceClient> void setUsePTT(bool usePTT); void setPTTIsToggle(bool PTTIsToggle); bool getPTTIsToggle(); - void setPTTKey(std::string &key); - + void updateMicMuteLogic(); - + BOOL lipSyncEnabled(); - - // PTT key triggering - void keyDown(KEY key, MASK mask); - void keyUp(KEY key, MASK mask); - void middleMouseState(bool down); - + boost::signals2::connection MicroChangedCallback(const micro_changed_signal_t::slot_type& cb ) { return mMicroChangedSignal.connect(cb); } @@ -486,7 +480,7 @@ class LLVoiceClient: public LLParamSingleton<LLVoiceClient> bool mPTT; bool mUsePTT; - bool mPTTIsMiddleMouse; + S32 mPTTMouseButton; KEY mPTTKey; bool mPTTIsToggle; bool mUserPTTState; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 739f7bd47cb340687760bc8a5937d746d14cce30..530adb89754d943579a40e5b2d4af9ea80dda3cc 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -5158,6 +5158,7 @@ void LLVivoxVoiceClient::setVoiceEnabled(bool enabled) { // Turning voice off looses your current channel -- this makes sure the UI isn't out of sync when you re-enable it. LLVoiceChannel::getCurrentVoiceChannel()->deactivate(); + gAgent.setVoiceConnected(false); status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED; } diff --git a/indra/newview/llwindowlistener.cpp b/indra/newview/llwindowlistener.cpp index 9e4297baafc13a903d8ae97dc6436cd11d8aed51..aa8c79b0d280a89e6cb30860017f94c18cc854aa 100644 --- a/indra/newview/llwindowlistener.cpp +++ b/indra/newview/llwindowlistener.cpp @@ -37,7 +37,7 @@ #include "llview.h" #include "llviewinject.h" #include "llviewerwindow.h" -#include "llviewerkeyboard.h" +#include "llviewerinput.h" #include "llrootview.h" #include "llsdutil.h" #include "stringize.h" @@ -279,7 +279,7 @@ void LLWindowListener::keyDown(LLSD const & evt) response.setResponse(target_view->getInfo()); gFocusMgr.setKeyboardFocus(target_view); - gViewerKeyboard.handleKey(key, mask, false); + gViewerInput.handleKey(key, mask, false); if(key < 0x80) mWindow->handleUnicodeChar(key, mask); } else @@ -291,7 +291,7 @@ void LLWindowListener::keyDown(LLSD const & evt) } else { - gViewerKeyboard.handleKey(key, mask, false); + gViewerInput.handleKey(key, mask, false); if(key < 0x80) mWindow->handleUnicodeChar(key, mask); } } diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 9bc3a2a33bc59b3e838e64d53daf3b320afa5f0f..a6df0792233581c1aabe4c1c268298b99a0003c4 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -1154,7 +1154,7 @@ void LLWorldMapView::drawAvatar(F32 x_pixels, { const F32 HEIGHT_THRESHOLD = 7.f; LLUIImagePtr dot_image = sAvatarLevelImage; - if (unknown_relative_z) + if (unknown_relative_z && llabs(relative_z) > HEIGHT_THRESHOLD) { dot_image = sAvatarUnknownImage; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index bd73c234a6a40d2f90fdcd13f702eea8937b2ce9..eb2d3bf8737714a4e9a16764cbb8c667a7425e3f 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -973,7 +973,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) mDeferredLight.release(); } - F32 scale = RenderShadowResolutionScale; + F32 scale = llmax(0.f, RenderShadowResolutionScale); if (shadow_detail > 0) { //allocate 4 sun shadow maps @@ -8685,8 +8685,8 @@ void LLPipeline::renderDeferredLighting() } const LLViewerObject *vobj = drawablep->getVObj(); - if(vobj && vobj->getAvatar() - && (vobj->getAvatar()->isTooComplex() || vobj->getAvatar()->isInMuteList())) + if((vobj && vobj->getAvatar() && (vobj->getAvatar()->isTooComplex() || vobj->getAvatar()->isInMuteList())) + || (vobj && dist_vec(vobj->getPosition(), LLViewerCamera::getInstance()->getOrigin()) > RenderFarClip)) { continue; } diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 5aba0546f3cd042c79bb67d9feebe23232f37b1a..9b18dbc2e26a069e38081b37da7ccad791d91908 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -144,7 +144,6 @@ with the same filename but different name <texture name="Command_MiniCart_Icon" file_name="toolbar_icons/mini_cart.png" preload="true" /> <texture name="Command_MiniMap_Icon" file_name="toolbar_icons/mini_map.png" preload="true" /> <texture name="Command_Move_Icon" file_name="toolbar_icons/move.png" preload="true" /> - <texture name="Command_Outbox_Icon" file_name="toolbar_icons/outbox.png" preload="true" /> <texture name="Command_People_Icon" file_name="toolbar_icons/people.png" preload="true" /> <texture name="Command_Picks_Icon" file_name="toolbar_icons/picks.png" preload="true" /> <texture name="Command_Places_Icon" file_name="toolbar_icons/places.png" preload="true" /> diff --git a/indra/newview/skins/default/xui/de/floater_about_land.xml b/indra/newview/skins/default/xui/de/floater_about_land.xml index 4dd64cba2ae0b3f29428270db4d151baa5dec74e..8f55b3297f57ca1c5fceee9c70055fcd761ecb57 100644 --- a/indra/newview/skins/default/xui/de/floater_about_land.xml +++ b/indra/newview/skins/default/xui/de/floater_about_land.xml @@ -30,7 +30,7 @@ <floater.string name="Always"> Immer </floater.string> - <tab_container name="landtab" tab_min_width="40" width="489"> + <tab_container name="landtab" tab_min_width="40"> <panel label="ALLGEMEIN" name="land_general_panel"> <panel.string name="new users only"> Nur neue Benutzer diff --git a/indra/newview/skins/default/xui/de/panel_preferences_chat.xml b/indra/newview/skins/default/xui/de/panel_preferences_chat.xml index 550a99fe0a5aff8c0e233bddfb4b13a65ba11fd2..51c82c97f88cfc1793d4a1740102fe246b8bcbee 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_chat.xml @@ -13,7 +13,7 @@ <item label="Mittel" name="Medium" value="1"/> <item label="Groß" name="Large" value="2"/> </combo_box> - <check_box label="Blasen-Chat" name="bubble_text_chat"/> + <check_box label="Blasen-Chat" name="bubble_text_chat" left_delta="8"/> </panel> <panel name="im_notification_settings"> <text name="friend_ims"> diff --git a/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml index ff0a6614bd9bd5f2cc5bc838c468f08e608c9c61..e0aa9fe4a97ab2fe765ba8405772a537fa44ae35 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml @@ -3,10 +3,10 @@ <text name="preset_text"> (Keine) </text> - <text name="QualitySpeed"> + <text name="QualitySpeed" top_delta="20"> Qualität und Geschwindigkeit: </text> - <text name="ShadersPrefText"> + <text name="ShadersPrefText" top_delta="15"> Niedrig </text> <text name="ShadersPrefText2"> diff --git a/indra/newview/skins/default/xui/en/control_table_contents.xml b/indra/newview/skins/default/xui/en/control_table_contents.xml new file mode 100644 index 0000000000000000000000000000000000000000..7b777befeef631c77b6a76e33fb21ecb609e858f --- /dev/null +++ b/indra/newview/skins/default/xui/en/control_table_contents.xml @@ -0,0 +1,625 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<contents> + <columns + relative_width="0.34" + label="Action" + name="lst_action" /> + <columns + relative_width="0.22" + label="Primary Control" + name="lst_ctrl1" /> + <columns + relative_width="0.22" + label="Alternate 1" + name="lst_ctrl2" /> + <columns + relative_width="0.22" + label="Alternate 2" + name="lst_ctrl3" /> + <rows + enabled="false" + name="move_actions" + value=""> + <columns + type="icontext" + column="lst_action" + font="SansSerif" + halign="left" + label="Move Actions" + name="lst_action" + value="Move_Walk_Off" /> + </rows> + <rows + name="walk_to" + value="walk_to"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Walk to location mouse cursor points to" + value="Walk to" /> + </rows> + <rows + name="teleport_to" + value="teleport_to"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Teleport to location mouse cursor points to, but not all locations allow direct teleportation so you might be teleported closer to destination instead" + value="Teleport to" /> + </rows> + <rows + name="push_forward" + value="push_forward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Move Forward" /> + </rows> + <rows + name="push_backward" + value="push_backward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Move Backward" /> + </rows> + <rows + name="turn_left" + value="turn_left"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Left" /> + </rows> + <rows + name="turn_right" + value="turn_right"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Right" /> + </rows> + <rows + name="slide_left" + value="slide_left"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Strafe left" /> + </rows> + <rows + name="slide_right" + value="slide_right"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Strafe right" /> + </rows> + <rows + name="jump" + value="jump"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Jump/Up" /> + </rows> + <rows + name="push_down" + value="push_down"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Down" /> + </rows> + <rows + name="run_forward" + value="run_forward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Run Forward" /> + </rows> + <rows + name="run_backward" + value="run_backward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Run Backward" /> + </rows> + <rows + name="run_left" + value="run_left"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Run Left" /> + </rows> + <rows + name="run_right" + value="run_right"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Run Right" /> + </rows> + <rows + name="toggle_run" + value="toggle_run"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Toggle Run" /> + </rows> + <rows + name="toggle_fly" + value="toggle_fly"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Fly/Stop flying" /> + </rows> + <rows + name="toggle_sit" + value="toggle_sit"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Sit/Stand" /> + </rows> + <rows + name="stop_moving" + value="stop_moving"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Stop Moving" /> + </rows> + <rows + enabled="false"> + <columns + type="icon" + color="0 0 0 0.7" + halign="center" + value="menu_separator" /> + </rows> + <rows + enabled="false" + name="camera_actions" + value=""> + <columns + type="icontext" + column="lst_action" + font="SansSerif" + halign="left" + label="Camera" + name="lst_action" + value="Cam_FreeCam_Off" /> + </rows> + <rows + name="look_up" + value="look_up"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Look Up" /> + </rows> + <rows + name="look_down" + value="look_down"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Look Down" /> + </rows> + <rows + name="move_forward" + value="move_forward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Forward" /> + </rows> + <rows + name="move_backward" + value="move_backward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Backward" /> + </rows> + <rows + name="move_forward_fast" + value="move_forward_fast"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Forward Fast" /> + </rows> + <rows + name="move_backward_fast" + value="move_backward_fast"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Backward Fast" /> + </rows> + <rows + name="move_forward_sitting" + value="move_forward_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Forward Sitting" /> + </rows> + <rows + name="move_backward_sitting" + value="move_backward_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Backward Sitting" /> + </rows> + <rows + name="spin_over" + value="spin_over"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Spin Over" /> + </rows> + <rows + name="spin_under" + value="spin_under"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Spin Under" /> + </rows> + <rows + name="spin_over_sitting" + value="spin_over_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Spin Over" /> + </rows> + <rows + name="spin_under_sitting" + value="spin_under_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Spin Under" /> + </rows> + <rows + name="pan_up" + value="pan_up"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan Up" /> + </rows> + <rows + name="pan_down" + value="pan_down"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan Down" /> + </rows> + <rows + name="pan_left" + value="pan_left"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan Left" /> + </rows> + <rows + name="pan_right" + value="pan_right"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan Right" /> + </rows> + <rows + name="pan_in" + value="pan_in"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan In" /> + </rows> + <rows + name="pan_out" + value="pan_out"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Pan Out" /> + </rows> + <rows + name="spin_around_ccw" + value="spin_around_ccw"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around counterclockwise" + value="Counterclockwise" /> + </rows> + <rows + name="spin_around_cw" + value="spin_around_cw"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around clockwise" + value="Clockwise" /> + </rows> + <rows + name="spin_around_ccw_sitting" + value="spin_around_ccw_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around counterclockwise sitting" + value="Counterclockwise Sitting" /> + </rows> + <rows + name="spin_around_cw_sitting" + value="spin_around_cw_sitting"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around clockwise sitting" + value="Clockwise Sitting" /> + </rows> + <rows + enabled="false"> + <columns + type="icon" + color="0 0 0 0.7" + halign="center" + value="menu_separator" /> + </rows> + <rows + enabled="false" + name="editing_actions" + value=""> + <columns + type="icontext" + column="lst_action" + font="SansSerif" + halign="left" + label="Editing" + name="lst_action" + value="Tool_Dozer" /> + </rows> + <rows + name="edit_avatar_spin_ccw" + value="edit_avatar_spin_ccw"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around avatar counterclockwise" + value="Counterclockwise" /> + </rows> + <rows + name="edit_avatar_spin_cw" + value="edit_avatar_spin_cw"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin around avatar clockwise" + value="Clockwise" /> + </rows> + <rows + name="edit_avatar_spin_over" + value="edit_avatar_spin_over"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin over avatar" + value="Camera Spin Over" /> + </rows> + <rows + name="edit_avatar_spin_under" + value="edit_avatar_spin_under"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + tool_tip="Camera spin under avatar" + value="Camera Spin Under" /> + </rows> + <rows + name="edit_avatar_move_forward" + value="edit_avatar_move_forward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Forward" /> + </rows> + <rows + name="edit_avatar_move_backward" + value="edit_avatar_move_backward"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Camera Backward" /> + </rows> + <rows + enabled="false"> + <columns + type="icon" + color="0 0 0 0.7" + halign="center" + value="menu_separator" /> + </rows> + <rows + enabled="false" + name="media_actions" + value=""> + <columns + type="icontext" + column="lst_action" + font="SansSerif" + halign="left" + label="Sound and Media" + name="lst_action" + value="Audio_Press" /> + </rows> + <rows + name="toggle_pause_media" + value="toggle_pause_media"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Play/Pause Media" /> + </rows> + <rows + name="toggle_enable_media" + value="toggle_enable_media"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Play/Stop All Media" /> + </rows> + <rows + name="voice_follow_key" + value="voice_follow_key"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Voice" /> + </rows> + <rows + name="toggle_voice" + value="toggle_voice"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Toggle Voice" /> + </rows> + <rows + name="start_chat" + value="start_chat"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Start Chat" /> + </rows> + <rows + name="start_gesture" + value="start_gesture"> + <columns + column="lst_action" + font="SansSerif" + halign="left" + name="lst_action" + value="Start Gesture" /> + </rows> +</contents> diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index 9f853fd960032489b51aa10169fd5cff2818da9b..a143adfa0633dacff99563e04d2ab849941fa685 100644 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -1800,7 +1800,7 @@ Only large parcels can be listed in search. Music URL: </text> <line_editor - follows="left|top" + follows="left|top|right" height="23" layout="topleft" left="100" diff --git a/indra/newview/skins/default/xui/en/floater_avatar_textures.xml b/indra/newview/skins/default/xui/en/floater_avatar_textures.xml index bac3ea86f1fa7a59f7ecb4acea6585e3903f082d..6540f5e3488726c8a77b958d081dd54e10650ebe 100644 --- a/indra/newview/skins/default/xui/en/floater_avatar_textures.xml +++ b/indra/newview/skins/default/xui/en/floater_avatar_textures.xml @@ -28,11 +28,13 @@ name="scroll_content_panel" follows="left|top" min_height="300" + min_width="300" layout="topleft" top="0" background_visible="false" left="0" - height="680"> + height="1165" + width="1015"> <text type="string" length="1" @@ -102,6 +104,14 @@ Textures name="hair_alpha" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Hair Tattoo" + layout="topleft" + left_pad="7" + name="hair_tattoo" + top_delta="0" + width="92" /> <texture_picker height="103" @@ -135,6 +145,14 @@ Textures name="head_tattoo" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Head Unv Tattoo" + layout="topleft" + left_pad="7" + name="head_universal_tattoo" + top_delta="0" + width="92" /> <texture_picker height="103" @@ -160,6 +178,14 @@ Textures name="eyes_alpha" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Eyes Tattoo" + layout="topleft" + left_pad="7" + name="eyes_tattoo" + top_delta="0" + width="92" /> <texture_picker height="103" @@ -225,6 +251,14 @@ Textures name="upper_tattoo" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Upper Unv Tattoo" + layout="topleft" + left_pad="7" + name="upper_universal_tattoo" + top_delta="0" + width="92" /> <texture_picker height="103" @@ -298,6 +332,14 @@ Textures name="lower_tattoo" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Lower Unv Tattoo" + layout="topleft" + left_pad="7" + name="lower_universal_tattoo" + top_delta="0" + width="92" /> <texture_picker height="103" @@ -315,6 +357,99 @@ Textures name="skirt" top_delta="0" width="92" /> + <texture_picker + height="103" + label="Skirt Tattoo" + layout="topleft" + left_pad="7" + name="skirt_tattoo" + top_delta="0" + width="92" /> + + <texture_picker + height="103" + label="Left Arm" + layout="topleft" + left="10" + name="leftarm-baked" + top_delta="100" + width="92" /> + <texture_picker + height="103" + label="Left Arm Tattoo" + layout="topleft" + left_pad="21" + name="leftarm_tattoo" + top_delta="0" + width="92" /> + + <texture_picker + height="103" + label="Left Leg" + layout="topleft" + left="10" + name="leftleg-baked" + top_delta="100" + width="92" /> + <texture_picker + height="103" + label="Left Leg Tattoo" + layout="topleft" + left_pad="21" + name="leftleg_tattoo" + top_delta="0" + width="92" /> + + <texture_picker + height="103" + label="AUX 1" + layout="topleft" + left="10" + name="aux1-baked" + top_delta="100" + width="92" /> + <texture_picker + height="103" + label="AUX 1 Tattoo" + layout="topleft" + left_pad="21" + name="aux1_tattoo" + top_delta="0" + width="92" /> + + <texture_picker + height="103" + label="AUX 2" + layout="topleft" + left="10" + name="aux2-baked" + top_delta="100" + width="92" /> + <texture_picker + height="103" + label="AUX 2 Tattoo" + layout="topleft" + left_pad="21" + name="aux2_tattoo" + top_delta="0" + width="92" /> + + <texture_picker + height="103" + label="AUX 3" + layout="topleft" + left="10" + name="aux3-baked" + top_delta="100" + width="92" /> + <texture_picker + height="103" + label="AUX 3 Tattoo" + layout="topleft" + left_pad="21" + name="aux3_tattoo" + top_delta="0" + width="92" /> </panel> </panel> </scroll_container> diff --git a/indra/newview/skins/default/xui/en/floater_forget_user.xml b/indra/newview/skins/default/xui/en/floater_forget_user.xml new file mode 100644 index 0000000000000000000000000000000000000000..f2e894733fced87a59d0b4a3d7ccd3b22093c666 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_forget_user.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + height="258" + layout="topleft" + name="groups" + help_topic="forget_username" + title="REMEMBERED USERNAMES" + width="280"> + <scroll_list + height="173" + layout="topleft" + left="12" + name="user_list" + top="24" + width="256"> + <scroll_list.columns + name="user" + width="248" /> + </scroll_list> + <button + height="20" + label="Forget" + label_selected="Forget" + layout="topleft" + left_delta="90" + name="forget" + top_pad="8" + width="80" /> + <check_box + height="20" + label="Also delete local data for this username" + layout="topleft" + left="15" + name="delete_data" + top_pad="5" + width="260" + initial_value="1" + tooltip="Deletes local files: chat history, last session screenshot, browser cookies, teleport history, toolbar settings, e t c"/> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/en/floater_merchant_outbox.xml deleted file mode 100644 index 7802f65902e5f4452ec1a37112ad5ef0a66ce712..0000000000000000000000000000000000000000 --- a/indra/newview/skins/default/xui/en/floater_merchant_outbox.xml +++ /dev/null @@ -1,156 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<floater - positioning="cascading" - can_close="true" - can_resize="true" - height="440" - help_topic="floater_merchant_outbox" - min_width="300" - min_height="200" - name="floater_merchant_outbox" - save_rect="true" - save_visibility="false" - reuse_instance="true" - title="MERCHANT OUTBOX" - width="333"> - <string name="OutboxFolderCount0"></string> - <string name="OutboxFolderCount1">1 folder</string> - <string name="OutboxFolderCountN">[NUM] folders</string> - <string name="OutboxImporting">Sending folders...</string> - <string name="OutboxInitializing">Initializing...</string> - <panel - name="panel_1" - follows="all" - layout="topleft" - left="0" - top="0" - label="" - height="440" - width="333"> - <panel - name="panel_2" - follows="all" - left="10" - bottom="370" - width="313" - top="0" - bg_opaque_color="InventoryBackgroundColor"> - <panel - name="outbox_inventory_placeholder_panel" - follows="all" - layout="topleft" - top="0" - left="0" - width="308" - height="370" - bg_opaque_color="InventoryBackgroundColor"> - <text - name="outbox_inventory_placeholder_title" - type="string" - follows="top|left|right" - layout="topleft" - top="10" - left="0" - width="308" - height="25" - wrap="true" - halign="center" - font="SansSerifBold"> - Loading... - </text> - <text - name="outbox_inventory_placeholder_text" - type="string" - follows="top|left|right" - layout="topleft" - top="35" - left="0" - width="308" - height="130" - wrap="true" - halign="left" /> - </panel> - </panel> - <panel - name="panel_3" - follows="bottom|left|right" - left="10" - bottom="435" - width="313" - top="370"> - <panel - name="outbox_generic_drag_target" - mouse_opaque="false" - follows="all" - top="5" - left="5" - width="303" - height="25" - background_visible="false" - bg_alpha_color="EmphasisColor_35" - border="true" - bevel_style="in" - visible="true"> - <text - name="text_1" - type="string" - follows="all" - layout="topleft" - top="6" - height="20" - left="5" - width="293" - halign="center" - font="SansSerifMedium" - font_shadow="hard" - valign="top"> - Drag items here to create folders - </text> - </panel> - <text - name="outbox_folder_count" - type="string" - follows="all" - layout="topleft" - top="40" - left="5" - width="150" - height="20" - wrap="true" - halign="left" - valign="center" - font="SansSerif"/> - <button - label="Send to Marketplace" - tool_tip="Push to my Marketplace Storefront" - is_toggle="false" - name="outbox_import_btn" - follows="bottom|right" - tab_stop="false" - halign="center" - top="37" - left="160" - height="25" - width="150" - enabled="false" /> - </panel> - <layout_stack name="import_progress_indicator" orientation="vertical" left="0" height="440" top="0" width="333" follows="all" visible="false"> - <layout_panel /> - <layout_panel height="24" auto_resize="false"> - <layout_stack orientation="horizontal" left="0" height="24" top="0" width="333" follows="all"> - <layout_panel width="0" /> - <layout_panel width="24" auto_resize="false"> - <loading_indicator - height="24" - layout="topleft" - left="0" - top="0" - width="24" /> - </layout_panel> - <layout_panel width="0" /> - </layout_stack> - </layout_panel> - <layout_panel /> - </layout_stack> - </panel> -</floater> diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml index 0e62d50072eb1940726e1c00a3fa296340d97419..ee730dcb013e1339b6cb5637a9e56d8356c7b3c1 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences.xml @@ -169,6 +169,13 @@ https://accounts.secondlife.com/change_email/ layout="topleft" help_topic="preferences_uploads_tab" name="uploads" /> + <panel + class="panel_preference_controls" + filename="panel_preferences_controls.xml" + label="Controls" + layout="topleft" + help_topic="preferences_controls_tab" + name="controls" /> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_preview_trash.xml b/indra/newview/skins/default/xui/en/floater_preview_trash.xml index 9e50e89ac953b556d4c18aaca44e52247be10dea..3fa71e7bfe024c7f44358481d1c42f48ba48d405 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_trash.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_trash.xml @@ -14,7 +14,7 @@ reuse_instance="true" can_minimize="false"> <inventory_panel - name="inventory_outbox" + name="inventory_trash" start_folder.name="Trash" show_empty_message="false" start_folder.type="trash" diff --git a/indra/newview/skins/default/xui/en/floater_select_key.xml b/indra/newview/skins/default/xui/en/floater_select_key.xml index 4e89df5a7352f7770c5058f564e03aa922a0061d..48d9eee4cd456039c4dc1e304f30bc2d2ff7a4d2 100644 --- a/indra/newview/skins/default/xui/en/floater_select_key.xml +++ b/indra/newview/skins/default/xui/en/floater_select_key.xml @@ -4,10 +4,27 @@ border="false" can_close="false" can_minimize="false" - height="90" + height="116" layout="topleft" name="modal container" - width="240"> + width="272"> + <floater.string + name="keyboard"> + Keyboard + </floater.string> + <floater.string + name="mouse"> + Mouse Buttons + </floater.string> + <floater.string + name="basic_description"> +Press a key to set your trigger. +Allowed input: [INPUT]. + </floater.string> + <floater.string + name="reserved_by_menu"> +Combination [KEYSTR] is reserved by menu. + </floater.string> <text type="string" halign="center" @@ -16,19 +33,47 @@ height="30" layout="topleft" left="30" - name="Save item as:" + name="descritption" top="25" word_wrap="true" - width="180"> - Press a key to set your Speak button trigger. + width="212"> +Press a key to set your trigger. +Allowed input: [INPUT]. </text> + <check_box + follows="top|left" + height="20" + initial_value="false" + label="Apply to all" + layout="topleft" + left="90" + name="apply_all" + tool_tip="Viewer uses different control combinations depending on what you are doing in world, setting this will apply your change to all combinations" + top_pad="8" + width="160" /> + + <button + height="23" + label="Set Empty" + layout="topleft" + left="8" + name="SetEmpty" + top_pad="6" + width="80" /> + <button + height="23" + label="Default" + layout="topleft" + left_pad="8" + name="Default" + top_delta="0" + width="80" /> <button height="23" label="Cancel" - label_selected="Cancel" layout="topleft" - right="-10" + left_pad="8" name="Cancel" - top_pad="8" - width="100" /> + top_delta="0" + width="80" /> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml index d122d7491cfaa83e4d725743afff349054c78623..c2af4f54d0e58e2f03c0531a2238efb302f01904 100644 --- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml @@ -93,11 +93,22 @@ height="14" layout="topleft" left_delta="12" + name="size_lbl" + top_pad="4"> + Size: + </text> + + <text + type="string" + length="1" + follows="left|top" + height="14" + layout="topleft" + left_delta="0" name="unknown" top_pad="4"> - Size: [DIMENSIONS] + [DIMENSIONS] </text> - <!-- middle: inventory mode --> <button @@ -139,19 +150,20 @@ image_unselected="eye_button_inactive.tga" layout="topleft" left_delta="-80" - top_delta="-25" + top_delta="-10" name="Pipette" width="28" /> <text follows="left|bottom" - height="20" + height="40" layout="topleft" left="8" name="preview_disabled" - top="266" + top="285" value="Preview Disabled" + word_wrap="true" visible="false" - width="120" /> + width="87" /> <filter_editor follows="left|top|right" height="23" diff --git a/indra/newview/skins/default/xui/en/menu_gesture_gear.xml b/indra/newview/skins/default/xui/en/menu_gesture_gear.xml index c1458977ca15713a98265f44ca65e8ee015003a0..5cae643e44f5dc9475c354705d7cc08a7c47d0f5 100644 --- a/indra/newview/skins/default/xui/en/menu_gesture_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_gesture_gear.xml @@ -11,6 +11,16 @@ <on_click function="Gesture.Action.ToogleActiveState" /> </menu_item_call> + <menu_item_call + label="Rename" + layout="topleft" + name="rename"> + <on_click + function="Gesture.Action.Rename" /> + <on_enable + function="Gesture.EnableAction" + parameter="rename_gesture" /> + </menu_item_call> <menu_item_call label="Copy" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 7bb7b5d62cf2f0b2aa13be6aac1934435420cb65..af185d43b0edca0d0b3c75941851de378d7fa331 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -17,9 +17,11 @@ </menu_item_call> <menu_item_call label="Appearance..." - name="ChangeOutfit"> + name="ChangeOutfit" + shortcut="control|O"> <menu_item_call.on_click - function="CustomizeAvatar" /> + function="Floater.ToggleOrBringToFront" + parameter="appearance" /> <menu_item_call.on_enable function="Edit.EnableCustomizeAvatar" /> </menu_item_call> @@ -152,13 +154,16 @@ <menu_item_call.on_click function="Tools.StopAllAnimations" /> </menu_item_call> - <menu_item_call + <menu_item_check label="Walk / run / fly..." name="WalkRunFly"> - <menu_item_call.on_click + <menu_item_check.on_check + function="Floater.Visible" + parameter="moveview" /> + <menu_item_check.on_click function="Floater.ToggleOrBringToFront" parameter="moveview" /> - </menu_item_call> + </menu_item_check> </menu> <menu diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index f72767ccebe513740db1c1f8d5ea9e75acf472d8..92711d4397055d0988d062f72157f49c230aee3b 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2180,7 +2180,7 @@ Wrong chunk size in WAV file: icon="alertmodal.tga" name="SoundFileInvalidTooLong" type="alertmodal"> -Audio file is too long (10 second maximum): +Audio file is too long (30 second maximum): [FILE] <tag>fail</tag> </notification> @@ -2259,6 +2259,7 @@ Unable to create output file: [FILE] icon="alertmodal.tga" name="DoNotSupportBulkAnimationUpload" type="alertmodal"> + <unique/> [APP_NAME] does not currently support bulk upload of BVH format animation files. <tag>fail</tag> </notification> @@ -2477,6 +2478,13 @@ Sorry, but the system was unable to complete your teleport request in a timely f type="alertmodal"> <tag>fail</tag> Sorry, but the system was unable to complete your region crossing in a timely fashion. Please try again in a few minutes. + </notification> + <notification + icon="alertmodal.tga" + name="preexisting_tport" + type="alertmodal"> + <tag>fail</tag> +Sorry, but the system was unable to start your teleport. Please try again in a few minutes. </notification> <notification icon="alertmodal.tga" @@ -3091,6 +3099,29 @@ See https://wiki.secondlife.com/wiki/Adding_Spelling_Dictionaries </form> </notification> + <notification + icon="alertmodal.tga" + label="Rename Gesture" + name="RenameGesture" + type="alertmodal"> + New gesture name: + <tag>confirm</tag> + <form name="form"> + <input name="new_name" type="text" width="300"> + [NAME] + </input> + <button + default="true" + index="0" + name="OK" + text="OK"/> + <button + index="1" + name="Cancel" + text="Cancel"/> + </form> + </notification> + <notification icon="alertmodal.tga" name="RemoveFromFriends" @@ -3410,6 +3441,9 @@ Display settings have been set to recommended levels because of a change to the icon="alertmodal.tga" name="ErrorMessage" type="alertmodal"> + <unique> + <context>ERROR_MESSAGE</context> + </unique> [ERROR_MESSAGE] <tag>fail</tag> <usetemplate @@ -3545,6 +3579,30 @@ You can either check your Internet connection and try again in a few minutes, cl </form> </notification> + <notification + icon="alertmodal.tga" + name="LoginPacketNeverReceivedNoTP" + type="alertmodal"> + <tag>fail</tag> +We're having trouble connecting. There may be a problem with your Internet connection or the [SECOND_LIFE_GRID]. + +You can either check your Internet connection and try again in a few minutes or click Help to view the [SUPPORT_SITE]. + <url option="1" name="url"> + http://secondlife.com/support/ + </url> + <form name="form"> + <button + default="true" + index="0" + name="OK" + text="OK"/> + <button + index="1" + name="Help" + text="Help"/> + </form> + </notification> + <notification icon="alertmodal.tga" name="WelcomeChooseSex" @@ -5998,6 +6056,34 @@ Would you like to turn off Do Not Disturb before completing this transaction? </form> </notification> + <notification + icon="notify.tga" + label="Parcel is Playing Media" + name="ParcelPlayingMedia" + persist="false" + type="notify"> +This land has media: +[URL] +Would you like to play it? + <tag>confirm</tag> + <form name="form"> + <ignore name="ignore" + checkbox_only="true" + text="Always choose this option for this land."/> + <button + ignore="Play Media" + index="1" + name="Yes" + text="Play"/> + <button + default="true" + ignore="Ignore Media" + index="0" + name="No" + text="Ignore"/> + </form> + </notification> + <notification icon="alertmodal.tga" name="ConfirmDeleteProtectedCategory" @@ -6108,6 +6194,20 @@ Are you sure you want to permanently delete the contents of your Lost And Found? yestext="Yes"/> </notification> + <notification + icon="alertmodal.tga" + name="ConfirmReplaceLink" + type="alertmodal"> +You're about to replace '[TYPE]' body part link with the item which doesn't match the type. +Are you sure you want to proceed? + <tag>confirm</tag> + <usetemplate + ignoretext="Confirm before I replace link" + name="okcancelignore" + notext="No" + yestext="Yes"/> + </notification> + <notification icon="alertmodal.tga" name="CopySLURL" @@ -7026,12 +7126,14 @@ You can only claim public land in the Region you're in. </notification> <notification - icon="notify.tga" + icon="alertmodal.tga" name="RegionTPAccessBlocked" - persist="false" - type="notify"> + type="alertmodal"> <tag>fail</tag> The region you're trying to visit contains content exceeding your current preferences. You can change your preferences using Me > Preferences > General. + <usetemplate + name="okbutton" + yestext="OK"/> </notification> <notification @@ -11175,6 +11277,19 @@ Cannot create large prims that intersect other residents. Please re-try when ot notext="Cancel" yestext="OK"/> </notification> + + <notification + icon="alertmodal.tga" + name="PreferenceControlsDefaults" + type="alertmodal"> + Do you want to restore default values for controls? + <tag>confirm</tag> + <usetemplate + canceltext="Cancel" + name="yesnocancelbuttons" + notext="Current mode" + yestext="All modes"/> + </notification> <notification icon="alertmodal.tga" diff --git a/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml b/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml index 27c653bc354ae3b8ef83f3ab34e83e88051fa716..d1175a9fe18926a444a102af31cbaa8440efead3 100644 --- a/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_classifieds_list_item.xml @@ -32,7 +32,6 @@ width="308"/> <texture_picker allow_no_texture="true" - border_enabled="true" fallback_image="default_land_picture.j2c" enabled="false" follows="left|top" diff --git a/indra/newview/skins/default/xui/en/panel_edit_classified.xml b/indra/newview/skins/default/xui/en/panel_edit_classified.xml index 3509eaa2851f63c77565e724a185bab1e1a9f31a..e846edf1d4b9f7beaa958c135816d3dc75277f3a 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_classified.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_classified.xml @@ -144,7 +144,6 @@ follows="left|top|right" height="100" width="273" - hide_scrollbar="false" layout="topleft" left="10" top_pad="2" diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 7759d4fdb2975cadfc31b9bf6d426da8a54526a9..d601b36ce55b6ce1f4fc58b17e7f4a7d85ae89f9 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -57,19 +57,15 @@ combo_editor.prevalidate_callback="ascii" tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine" name="username_combo" - width="232"> + width="206"> <combo_box.combo_editor text_pad_left="8" bg_image_always_focused="true"/> - <combo_box.combo_button - visible="false" /> - <combo_box.drop_down_button - visible="false" /> </combo_box> <line_editor follows="left|top" height="32" - left_pad="-11" + left_pad="15" max_length_chars="16" text_pad_left="8" name="password_edit" @@ -119,36 +115,49 @@ width="120" height="32" left_pad="15" - bottom_delta="0" /> + bottom_delta="0" /> + <text + follows="left|top" + font="SansSerifLarge" + font.style="BOLD" + text_color="EmphasisColor" + height="34" + name="sign_up_text" + left_pad="10" + width="200" + valign="center"> + Sign up + </text> <check_box - control_name="RememberPassword" follows="left|top" font="SansSerifMedium" left="185" - bottom_delta="21" + bottom_delta="21" height="24" label="Remember me" check_button.bottom="3" - name="remember_check" + name="remember_name" + tooltip="Already recorded user can be forgotten from preferences." width="145" /> - <text + <check_box + control_name="RememberPassword" follows="left|top" font="SansSerifMedium" text_color="EmphasisColor" height="16" - name="forgot_password_text" - left="408" + left="408" bottom_delta="0" - width="200"> - Forgotten password - </text> + label="Remember password" + check_button.bottom="3" + name="remember_check" + width="145" /> <combo_box allow_text_entry="false" font="SansSerifTiny" follows="left|top" height="26" left="588" - bottom_delta="10" + bottom_delta="8" max_chars="128" label="Select grid" layout="topleft" @@ -159,12 +168,13 @@ font="SansSerifMedium" text_color="EmphasisColor" height="16" - name="sign_up_text" + name="forgot_password_text" left="778" - bottom_delta="-10" - width="200"> - Sign up - </text> + bottom_delta="-8" + width="120" + halign="center"> + Password help + </text> </layout_panel> <layout_panel height="172" diff --git a/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml deleted file mode 100644 index b2d8bb874b642b845130c0d444aab27ee63f1589..0000000000000000000000000000000000000000 --- a/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<inventory_panel - name="inventory_outbox" - start_folder.name="Outbox" - show_empty_message="false" - start_folder.type="outbox" - follows="all" layout="topleft" - top="0" left="0" height="165" width="308" - top_pad="0" - bg_opaque_color="DkGray2" - bg_alpha_color="DkGray2" - background_visible="true" - border="false" - bevel_style="none" - show_item_link_overlays="true" - tool_tip="Drag and drop items here to prepare them for sale on your storefront" - scroll.reserve_scroll_corner="false"> - <folder folder_arrow_image="Folder_Arrow" - folder_indentation="8" - item_height="20" - item_top_pad="4" - selection_image="Rounded_Square" - left_pad="5" - icon_pad="2" - icon_width="16" - text_pad="1" - text_pad_right="4" - arrow_size="12" - max_folder_item_overlap="2"/> - <item allow_wear="false"/> -</inventory_panel> diff --git a/indra/newview/skins/default/xui/en/panel_pick_info.xml b/indra/newview/skins/default/xui/en/panel_pick_info.xml index 79d190e1e09a0e6dea7ae3d190080c2dc6cc333e..99c47eb8257efaf0d6f189b4d17a15c0ff01aa11 100644 --- a/indra/newview/skins/default/xui/en/panel_pick_info.xml +++ b/indra/newview/skins/default/xui/en/panel_pick_info.xml @@ -103,7 +103,6 @@ height="100" width="280" parse_urls="true" - hide_scrollbar="false" layout="topleft" left="10" top_pad="2" diff --git a/indra/newview/skins/default/xui/en/panel_pick_list_item.xml b/indra/newview/skins/default/xui/en/panel_pick_list_item.xml index 43d580844fb9f61d49abd5403c1c31bf47d6e597..4c0cdd321e16f2879d8d90c2ad3919b288813e77 100644 --- a/indra/newview/skins/default/xui/en/panel_pick_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_pick_list_item.xml @@ -32,7 +32,6 @@ width="308" /> <texture_picker allow_no_texture="true" - border_enabled="true" fallback_image="default_land_picture.j2c" enabled="false" follows="left|top" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index 4f0bb9d3b775cfa3af90215367d6ab7635e803f2..d0518aa2450ebf9ae95267ca7193a090cf0897f6 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -142,6 +142,32 @@ min_val="0.75" name="ui_scale_slider" top_pad="-14" + width="250" /> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left="33" + name="HUD Size:" + top_pad="20" + width="100"> + HUD Scale: + </text> + <slider + control_name="HUDScaleFactor" + decimal_digits="2" + follows="left|top" + height="17" + increment="0.1" + initial_value="1" + layout="topleft" + left_pad="0" + max_val="2.0" + min_val="1.0" + name="ui_scale_slider" + top_pad="-14" width="250" /> <check_box control_name="ShowScriptErrors" @@ -222,14 +248,27 @@ top_pad="5" width="237"/> <button + follows="top|left" + layout="topleft" + label="Remembered Usernames" + name="remembered_usernames" height="20" - label="Default Creation Permissions" + left="30" + top_pad="16" + width="200"> + <button.commit_callback + function="Pref.RememberedUsernames" /> + </button> + <button + follows="top|left" layout="topleft" + label="Default Creation Permissions" name="default_creation_permissions" + height="20" left="30" - top_pad = "20" - width="250"> - <button.commit_callback - function="Pref.PermsDefault" /> + top_pad="16" + width="200"> + <button.commit_callback + function="Pref.PermsDefault" /> </button> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml index 9e7023d2f2507b123af9137dace39e8516dbaf24..ece6c95080e22da18c5c46f97fb2d33648341f61 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml @@ -99,6 +99,7 @@ label="Bubble Chat" layout="topleft" top_pad="4" + left_delta="0" name="bubble_text_chat" width="330"> </check_box> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml new file mode 100644 index 0000000000000000000000000000000000000000..904387909eef5fb5d599a085b63eef256209cdc0 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<panel + border="true" + follows="all" + height="408" + label="Controls" + layout="topleft" + left="102" + name="controls" + top="1" + width="517"> + <combo_box + follows="top|left" + layout="topleft" + top="6" + left="10" + height="23" + width="140" + name="key_mode"> + <combo_box.item + label="Third Person " + name="third_person" + value="1"/> + <combo_box.item + label="First Person (Mouselook)" + name="first_person" + value="0"/> + <combo_box.item + label="Edit Avatar" + name="edit_avatar" + value="2"/> + <combo_box.item + label="Sitting" + name="sitting" + value="3"/> + </combo_box> + + <button + follows="top|left" + layout="topleft" + top="6" + right="-10" + height="23" + width="140" + label="Restore Defaults" + tool_tip="Restores default values for all control modes." + name="restore_defaults"/> + + <scroll_list + draw_heading="true" + follows="all" + layout="topleft" + column_padding="0" + selection_type="header" + top="31" + left="3" + bottom="-3" + right="-3" + can_sort="false" + multi_select="false" + name="controls_list" + fg_disable_color="ScrollUnselectedColor"/> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_move.xml b/indra/newview/skins/default/xui/en/panel_preferences_move.xml index 8794e3bf95ac9d54e4084203b16433e6b5a72208..d106456b31731e972afaa8f7063ba851c8601baf 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_move.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_move.xml @@ -195,70 +195,6 @@ name="invert_mouse" top_delta="0" width="128" /> - <text - follows="left|top" - type="string" - length="1" - height="10" - layout="topleft" - left="86" - name="single_click_action_lbl" - width="150" - top_pad="20"> - Single click on land: - </text> - <combo_box - height="23" - layout="topleft" - left_pad="10" - top_delta="-6" - name="single_click_action_combo" - width="200"> - <combo_box.item - label="No action" - name="0" - value="0"/> - <combo_box.item - label="Move to clicked point" - name="1" - value="1"/> - <combo_box.commit_callback - function="Pref.ClickActionChange"/> - </combo_box> - <text - follows="left|top" - type="string" - length="1" - height="10" - layout="topleft" - left="86" - name="double_click_action_lbl" - width="150" - top_pad="12"> - Double click on land: - </text> - <combo_box - height="23" - layout="topleft" - left_pad="10" - top_delta="-6" - name="double_click_action_combo" - width="200"> - <combo_box.item - label="No action" - name="0" - value="0"/> - <combo_box.item - label="Move to clicked point" - name="1" - value="1"/> - <combo_box.item - label="Teleport to clicked point" - name="2" - value="2"/> - <combo_box.commit_callback - function="Pref.ClickActionChange"/> - </combo_box> <button height="23" label="Other Devices" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml index 8f2e81b9f7481538d2a1f607925ec85ad2971eea..c2995393fd78dc00b397936729a00ba9655c1440 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml @@ -13,6 +13,14 @@ name="middle_mouse"> Middle Mouse </panel.string> + <panel.string + name="button4_mouse"> + Mouse Button 4 + </panel.string> + <panel.string + name="button5_mouse"> + Mouse Button 5 + </panel.string> <slider control_name="AudioLevelMaster" follows="left|top" @@ -314,17 +322,40 @@ name="enable_voice_check" width="110"/> <!-- --> - <check_box - name="media_auto_play_btn" - control_name="ParcelMediaAutoPlayEnable" - enabled_control="AudioStreamingMedia" - value="true" - follows="left|bottom|right" - height="15" - tool_tip="Check this to let media auto-play if it wants" - label="Allow Media to auto-play" - top_pad="1" - left="25"/> + <text + follows="left|top" + layout="topleft" + height="15" + left="0" + top_pad="3" + width="120" + halign="right" + name="media_autoplay_label"> + Media auto-play + </text> + <combo_box + control_name="ParcelMediaAutoPlayEnable" + enabled_control="AudioStreamingMedia" + follows="left|top" + layout="topleft" + height="23" + left_pad="7" + top_delta="-4" + name="media_auto_play_combo" + width="100"> + <item + label="Disabled" + name="autoplay_disabled" + value="0"/> + <item + label="Enabled" + name="autoplay_enabled" + value="1"/> + <item + label="Ask" + name="autoplay_ask" + value="2"/> + </combo_box> <check_box name="media_show_on_others_btn" control_name="MediaShowOnOthers" @@ -432,52 +463,13 @@ enabled_control="EnableVoiceChat" control_name="PushToTalkToggle" height="15" - label="Toggle speak on/off when I press:" + label="Toggle speak on/off when I press button in toolbar" layout="topleft" left="44" name="push_to_talk_toggle_check" width="237" tool_tip="When in toggle mode, press and release the trigger key ONCE to switch your microphone on or off. When not in toggle mode, the microphone broadcasts your voice only while the trigger is being held down." top_pad="3"/> - <line_editor - follows="top|left" - control_name="PushToTalkButton" - enabled="false" - enabled_control="EnableVoiceChat" - height="23" - left="80" - max_length_bytes="200" - name="modifier_combo" - label="Push-to-Speak trigger" - top_pad="3" - width="200" /> - <button - layout="topleft" - follows="top|left" - enabled_control="EnableVoiceChat" - height="23" - label="Set Key" - left_pad="5" - name="set_voice_hotkey_button" - width="100"> - <button.commit_callback - function="Pref.VoiceSetKey" /> - </button> - <button - enabled_control="EnableVoiceChat" - follows="top|left" - halign="center" - height="23" - image_overlay="Refresh_Off" - layout="topleft" - tool_tip="Reset to Middle Mouse Button" - mouse_opaque="true" - name="set_voice_middlemouse_button" - left_pad="5" - width="25"> - <button.commit_callback - function="Pref.VoiceSetMiddleMouse" /> - </button> <button control_name="ShowDeviceSettings" follows="left|top" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 9eedc45aa9d4533c153c790493661bc396c83577..0594e18c96728de023743c48aa6a57c5fbf23bd9 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2637,6 +2637,7 @@ If you continue to receive this message, please contact Second Life support for <string name="Debits">Debits</string> <string name="Total">Total</string> <string name="NoGroupDataFound">No group data found for group </string> + <string name="AlreadyInGroup">You are already in this group </string> <!-- floater IM bonus_info: When a Linden with Admin/god status receives a new IM this displays the estate (Mainland vs. teen grid) of the source avatar. This is to help Lindens when answering questions. --> @@ -2820,7 +2821,7 @@ If you continue to receive this message, please contact Second Life support for <string name="BuyingCosts">Buying this costs L$ [AMOUNT]</string> <string name="UnknownFileExtension"> Unknown file extension .%s -Expected .wav, .tga, .bmp, .jpg, .jpeg, or .bvh +Expected .wav, .tga, .bmp, .jpg, .jpeg, or .anim </string> <string name="MuteObject2">Block</string> <string name="MuteAvatar">Block</string> @@ -4068,6 +4069,15 @@ Try enclosing path to the editor with double quotes. <string name="Z">Z</string> <!-- Key names end --> + <!-- Mouse button names (short) begin --> + <string name="LMB">LMB</string> + <string name="MMB">MMB</string> + <string name="RMB">RMB</string> + <string name="MB4">MB4</string> + <string name="MB5">MB5</string> + <string name="Double LMB">Double LMB</string> + <!-- Mouse button names end --> + <!-- llviewerwindow --> <string name="BeaconParticle">Viewing particle beacons (blue)</string> <string name="BeaconPhysical">Viewing physical object beacons (green)</string> @@ -4097,7 +4107,6 @@ Try enclosing path to the editor with double quotes. <string name="Command_MarketplaceListings_Label">Marketplace</string> <string name="Command_MiniMap_Label">Mini-map</string> <string name="Command_Move_Label">Walk / run / fly</string> - <string name="Command_Outbox_Label">Merchant outbox</string> <string name="Command_People_Label">People</string> <string name="Command_Picks_Label">Picks</string> <string name="Command_Places_Label">Places</string> @@ -4129,7 +4138,6 @@ Try enclosing path to the editor with double quotes. <string name="Command_MarketplaceListings_Tooltip">Sell your creation</string> <string name="Command_MiniMap_Tooltip">Show nearby people</string> <string name="Command_Move_Tooltip">Moving your avatar</string> - <string name="Command_Outbox_Tooltip">Transfer items to your marketplace for sale</string> <string name="Command_People_Tooltip">Friends, groups, and nearby people</string> <string name="Command_Picks_Tooltip">Places to show as favorites in your profile</string> <string name="Command_Places_Tooltip">Places you've saved</string> diff --git a/indra/newview/skins/default/xui/en/teleport_strings.xml b/indra/newview/skins/default/xui/en/teleport_strings.xml index 5a9a16d3448d91d8102e3bf421242a6d5d21a095..57f8bb542de1fbde1d87885bc8471be964b50020 100644 --- a/indra/newview/skins/default/xui/en/teleport_strings.xml +++ b/indra/newview/skins/default/xui/en/teleport_strings.xml @@ -39,6 +39,9 @@ Go to 'Welcome Island Public' to repeat the tutorial. <message name="expired_region_handoff"> Sorry, but the system was unable to complete your region crossing in a timely fashion. Please try again in a few minutes. </message> + <message name="preexisting_tport"> + Sorry, but the system was unable to start your teleport. Please try again in a few minutes. + </message> <message name="no_host"> Unable to find teleport destination. The destination may be temporarily unavailable or no longer exists. Please try again in a few minutes. </message> diff --git a/indra/newview/skins/default/xui/es/floater_about_land.xml b/indra/newview/skins/default/xui/es/floater_about_land.xml index 998d2a8863939958c867e549c0ee778ef52a84a1..57a1b2ec1e466291001489bfa6e70a8f223b04ac 100644 --- a/indra/newview/skins/default/xui/es/floater_about_land.xml +++ b/indra/newview/skins/default/xui/es/floater_about_land.xml @@ -362,7 +362,7 @@ Sólo las parcelas más grandes pueden listarse en la búsqueda. Foto: </text> <texture_picker label="" name="snapshot_ctrl" tool_tip="Pulse para elegir una imagen"/> - <text name="allow_see_label"> + <text name="allow_see_label" top="170"> Los avatares de otras parcelas pueden ver a los avatares de esta parcela y chatear con ellos </text> <check_box label="Ver los avatares" name="SeeAvatarsCheck" tool_tip="Permite que los avatares de otras parcelas vean a los avatares de ésta y chateen con ellos, y también que tú puedas verles y chatear con ellos." top="170"/> @@ -444,7 +444,7 @@ los media: <panel.string name="estate_override"> Una o más de esta opciones está configurada a nivel del estado </panel.string> - <check_box label="Cualquiera puede visitar (Si no seleccionas esta opción, se crearán lÃneas de prohibición)" name="public_access"/> + <check_box label="Cualquiera puede visitar" name="public_access" tool_tip="Si no seleccionas esta opción, se crearán lÃneas de prohibición"/> <check_box label="Debe ser mayor de 18 [ESTATE_AGE_LIMIT]" name="limit_age_verified" tool_tip="Para poder acceder a esta parcela los Residentes deben ser mayores de 18 años. Para más información, consulta [SUPPORT_SITE]."/> <check_box label="Debe haber información archivada sobre el pago [ESTATE_PAYMENT_LIMIT]" name="limit_payment" tool_tip="Para poder acceder a esta parcela los Residentes deben haber aportado información de pago en su cuenta. Para más información, ver [SUPPORT_SITE]."/> <check_box label="Permitir grupo [GROUP] sin restricciones" name="GroupCheck" tool_tip="Elija el grupo en la pestaña General."/> diff --git a/indra/newview/skins/default/xui/es/floater_buy_currency.xml b/indra/newview/skins/default/xui/es/floater_buy_currency.xml index 2c8848265f481a62e66c56a6e3a34b29c4b5ddc8..dbff3fcf0e6a5935d8a34ff8b4386048268ab102 100644 --- a/indra/newview/skins/default/xui/es/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/es/floater_buy_currency.xml @@ -60,7 +60,7 @@ no el objeto. </text> <button label="Comprar ahora" name="buy_btn"/> <button label="Cancelar" name="cancel_btn"/> - <text left="5" name="info_cannot_buy" right="-5"> + <text name="info_cannot_buy" left="150" font="SansSerifBig"> No se pudo hacer la compra </text> <button label="Ir a la web" name="error_web"/> diff --git a/indra/newview/skins/default/xui/es/panel_preferences_chat.xml b/indra/newview/skins/default/xui/es/panel_preferences_chat.xml index f7e036efd7471e9685a18085a80bdafe5b933b06..388a5d84d28b9eea7fef894a914f19c401e5697c 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_chat.xml @@ -13,7 +13,7 @@ <item label="Medio" name="Medium" value="1"/> <item label="Grande" name="Large" value="2"/> </combo_box> - <check_box label="Bocadillos del chat" name="bubble_text_chat"/> + <check_box label="Bocadillos del chat" name="bubble_text_chat" left_delta="30"/> </panel> <panel name="im_notification_settings"> <text name="friend_ims"> diff --git a/indra/newview/skins/default/xui/es/panel_preferences_setup.xml b/indra/newview/skins/default/xui/es/panel_preferences_setup.xml index 1b191d3e46b84f1fd6ae8fce7e0b2a093b270cf1..36888850c4e8ec5c475ff1d6eb0de97501bcddd5 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_setup.xml @@ -30,7 +30,7 @@ <combo_box.item label="Preguntarme cuando una actualización opcional está disponible para instalar" name="Install_ask"/> <combo_box.item label="Instalar sólo actualizaciones obligatorias" name="Install_manual"/> </combo_box> - <check_box label="Admitir candidatos a la versión comercial a la hora de realizar actualizaciones" name="update_willing_to_test"/> + <check_box label="Admitir candidatos a la versión comercial a la hora de realizar actualizaciones" name="update_willing_to_test" left_delta="-20"/> <check_box label="Mostrar las notas de la versión después de la actualización" name="update_show_release_notes"/> <text name="Proxy Settings:"> Configuración de proxy: diff --git a/indra/newview/skins/default/xui/fr/floater_about_land.xml b/indra/newview/skins/default/xui/fr/floater_about_land.xml index 219857eb992633ce94d0be0132733c3a417ae5ff..fb65e71ee1bbf2e6886f0791b21513002c177b7e 100644 --- a/indra/newview/skins/default/xui/fr/floater_about_land.xml +++ b/indra/newview/skins/default/xui/fr/floater_about_land.xml @@ -366,10 +366,10 @@ Seules les parcelles de grande taille peuvent apparaître dans la recherche. Photo : </text> <texture_picker label="" name="snapshot_ctrl" tool_tip="Cliquez pour sélectionner une image"/> - <text name="allow_see_label"> + <text name="allow_see_label" top="170"> Les avatars sur d'autres parcelles peuvent voir et chatter avec les avatars sur cette parcelle. </text> - <check_box label="Voir les avatars" name="SeeAvatarsCheck" tool_tip="Permettre aux avatars présents sur d'autres parcelles de voir et chatter avec les avatars présents sur cette parcelle et à vous de les voir et de chatter avec eux."/> + <check_box label="Voir les avatars" name="SeeAvatarsCheck" top="170" tool_tip="Permettre aux avatars présents sur d'autres parcelles de voir et chatter avec les avatars présents sur cette parcelle et à vous de les voir et de chatter avec eux."/> <text name="landing_point"> Lieu d'arrivée : [LANDING] </text> @@ -449,7 +449,7 @@ musique : <panel.string name="estate_override"> Au moins une de ces options est définie au niveau du domaine. </panel.string> - <check_box label="Tout le monde peut rendre visite (Des lignes d'interdiction seront créées si cette case n'est pas cochée)" name="public_access"/> + <check_box label="Tout le monde peut rendre visite" tool_tip="Des lignes d'interdiction seront créées si cette case n'est pas cochée" name="public_access"/> <check_box label="Doit avoir plus de 18 ans [ESTATE_AGE_LIMIT]" name="limit_age_verified" tool_tip="Pour accéder à cette parcelle, les résidents doivent avoir au moins 18 ans. Consultez le [SUPPORT_SITE] pour plus d'informations."/> <check_box label="Les infos de paiement doivent être enregistrées dans le dossier [ESTATE_PAYMENT_LIMIT]" name="limit_payment" tool_tip="Pour pouvoir accéder à cette parcelle, les résidents doivent avoir enregistré des informations de paiement. Consultez le [SUPPORT_SITE] pour plus d'informations."/> <check_box label="Autoriser le groupe [GROUP] sans restrictions" name="GroupCheck" tool_tip="Définir le groupe à l'onglet Général."/> diff --git a/indra/newview/skins/default/xui/fr/floater_buy_currency.xml b/indra/newview/skins/default/xui/fr/floater_buy_currency.xml index 148a5a35d23b5bd33ca08bf0bf52e651e2f65167..c295172abf03620a3479c30c5a44d37fb821f406 100644 --- a/indra/newview/skins/default/xui/fr/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/fr/floater_buy_currency.xml @@ -60,7 +60,7 @@ le Lindex... </text> <button label="Acheter" name="buy_btn"/> <button label="Annuler" name="cancel_btn"/> - <text left="5" name="info_cannot_buy" right="-5" width="200"> + <text name="info_cannot_buy" left="160" width="200"> Achat impossible </text> <button label="Accéder au Web" name="error_web"/> diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml b/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml index 422243445be9d466a12d64b00a1bdd4f1fb74a72..a0f2e0eba7ae70496d6b9d38de1ed4463cc99111 100644 --- a/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml @@ -13,7 +13,7 @@ <item label="Moyenne" name="Medium" value="1"/> <item label="Grande" name="Large" value="2"/> </combo_box> - <check_box label="Bulles de chat" name="bubble_text_chat"/> + <check_box label="Bulles de chat" name="bubble_text_chat" left_delta="45"/> </panel> <panel name="im_notification_settings"> <text name="friend_ims"> diff --git a/indra/newview/skins/default/xui/it/floater_about_land.xml b/indra/newview/skins/default/xui/it/floater_about_land.xml index 0a7837e12212c56c06b326ed19c0e1b9a0222df2..50e2d1a8de539ec5c3dd57a71ed4dfad6667880d 100644 --- a/indra/newview/skins/default/xui/it/floater_about_land.xml +++ b/indra/newview/skins/default/xui/it/floater_about_land.xml @@ -367,10 +367,10 @@ Solamente terreni più grandi possono essere abilitati nella ricerca. Fotografia: </text> <texture_picker label="" name="snapshot_ctrl" tool_tip="Clicca per scegliere una immagine"/> - <text name="allow_see_label"> + <text name="allow_see_label" top="170"> Gli avatar di altri lotti possono vedere gli avatar che si trovano in questo lotto e chattare con loro </text> - <check_box label="Vedi avatar" name="SeeAvatarsCheck" tool_tip="Consente ad avatar in altri lotti di vedere e chattare con avatar in questo lotto e viceversa."/> + <check_box label="Vedi avatar" top="170" name="SeeAvatarsCheck" tool_tip="Consente ad avatar in altri lotti di vedere e chattare con avatar in questo lotto e viceversa."/> <text name="landing_point"> Punto di atterraggio: [LANDING] </text> @@ -449,7 +449,7 @@ Media: <panel.string name="estate_override"> Una o più di queste impostazioni sono già impostate a livello regionale </panel.string> - <check_box label="Chiunque può visitare (Se si rimuove la selezione vengono create linee di espulsione)" name="public_access"/> + <check_box label="Chiunque può visitare" tool_tip="Se si rimuove la selezione vengono create linee di espulsione" name="public_access"/> <check_box label="È necessario avere più di 18 anni [ESTATE_AGE_LIMIT]" name="limit_age_verified" tool_tip="Per poter visitare questo lotto i Residenti devono avere almeno 18 anni. Vedi [SUPPORT_SITE] per maggiori informazioni."/> <check_box label="È necessario aver registrato le informazioni di pagamento [ESTATE_PAYMENT_LIMIT]" name="limit_payment" tool_tip="Per poter visitare questo lotto i Residenti devono aver fornito informazioni di pagamento a Linden Lab. Vedi [SUPPORT_SITE] per maggiori informazioni."/> <check_box label="Consenti gruppo [GRUPPO] senza restrizioni" name="GroupCheck" tool_tip="Imposta il gruppo nel pannello generale."/> diff --git a/indra/newview/skins/default/xui/it/floater_buy_currency.xml b/indra/newview/skins/default/xui/it/floater_buy_currency.xml index 743969f557147272de279dfea872257c402f775e..53a2057455e1c31618cb13c78ab65467133b306a 100644 --- a/indra/newview/skins/default/xui/it/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/it/floater_buy_currency.xml @@ -60,7 +60,7 @@ l'oggetto. </text> <button label="Acquista" name="buy_btn"/> <button label="Annulla" name="cancel_btn"/> - <text left="5" name="info_cannot_buy" right="-5"> + <text name="info_cannot_buy" left="160" font="SansSerifBig"> Non in grado di acquistare </text> <button label="Continua sul Web" name="error_web"/> diff --git a/indra/newview/skins/default/xui/pt/floater_about_land.xml b/indra/newview/skins/default/xui/pt/floater_about_land.xml index ef71baa0b6287fd1c7d52405df5bc701e300ad59..96e54bb9bcbb6a55ba5deec74652e42f9ababe96 100644 --- a/indra/newview/skins/default/xui/pt/floater_about_land.xml +++ b/indra/newview/skins/default/xui/pt/floater_about_land.xml @@ -362,10 +362,10 @@ Apenas lotes maiores podem ser listados na busca. Foto: </text> <texture_picker label="" name="snapshot_ctrl" tool_tip="Clique para escolher uma imagem"/> - <text name="allow_see_label"> + <text name="allow_see_label" top="170"> Avatares em outros lotes podem ver e conversar com avatares neste lote </text> - <check_box label="Ver avatares" name="SeeAvatarsCheck" tool_tip="Permite que os avatares em outros lotes vejam e batam papo com avatares neste lote. Você poderá vê-los e conversar com eles."/> + <check_box label="Ver avatares" name="SeeAvatarsCheck" top="170" tool_tip="Permite que os avatares em outros lotes vejam e batam papo com avatares neste lote. Você poderá vê-los e conversar com eles."/> <text name="landing_point"> Ponto de Aterrissagem: [LANDING] </text> diff --git a/indra/newview/skins/default/xui/ru/floater_about_land.xml b/indra/newview/skins/default/xui/ru/floater_about_land.xml index 1ae6df76d920663583f23952d2f353236c49d1e4..222572b4bf68e359b86b90045978e19043bc2fe0 100644 --- a/indra/newview/skins/default/xui/ru/floater_about_land.xml +++ b/indra/newview/skins/default/xui/ru/floater_about_land.xml @@ -338,7 +338,7 @@ <check_box label="Ð’Ñе" name="check other scripts" tool_tip="ЕÑли уÑтановлен флажок, то жители могут выполнÑÑ‚ÑŒ Ñкрипты на вашем учаÑтке, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ."/> <check_box label="Группа" name="check group scripts" tool_tip="ЕÑли уÑтановлен флажок, то члены группы могут выполнÑÑ‚ÑŒ Ñкрипты на вашем учаÑтке, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ."/> <check_box label="БезопаÑно (нет повреждений)" name="check safe" tool_tip="ЕÑли отмечено, то Ð·ÐµÐ¼Ð»Ñ ÑчитаетÑÑ Ð±ÐµÐ·Ð¾Ð¿Ð°Ñной, отключены боевые повреждениÑ. ЕÑли не отмечено, то боевые Ð¿Ð¾Ð²Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ñ‹."/> - <check_box label="Ðе толкать" name="PushRestrictCheck" tool_tip="Запрещает Ñкриптам функцию толканиÑ. Ðтот параметр может оказатьÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñ‹Ð¼ Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð½ÐµÐ¶ÐµÐ»Ð°Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð³Ð¾ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð½Ð° вашей земле."/> + <check_box label="Ðе толкать" name="PushRestrictCheck" left_pad="44" tool_tip="Запрещает Ñкриптам функцию толканиÑ. Ðтот параметр может оказатьÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñ‹Ð¼ Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð½ÐµÐ¶ÐµÐ»Ð°Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð³Ð¾ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð½Ð° вашей земле."/> <check_box label="Показать меÑто в поиÑке (L$30/неделÑ)" name="ShowDirectoryCheck" tool_tip="Позволить людÑм видеть учаÑток в результатах поиÑка"/> <combo_box name="land category"> <combo_box.item label="Ð›ÑŽÐ±Ð°Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ñ" name="item0"/> @@ -360,10 +360,10 @@ Снимок: </text> <texture_picker name="snapshot_ctrl" tool_tip="Щелкните Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° изображениÑ"/> - <text name="allow_see_label"> + <text name="allow_see_label" left="283"> Ðватары Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… учаÑтков могут видеть аватары на Ñтом учаÑтке и общатьÑÑ Ñ Ð½Ð¸Ð¼Ð¸ </text> - <check_box label="Видны аватары" name="SeeAvatarsCheck" tool_tip="Ðватары Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… учаÑтков Ñмогут видеть аватары на Ñтом учаÑтке и общатьÑÑ Ñ Ð½Ð¸Ð¼Ð¸ в чате, а вы также Ñможете видеть их и общатьÑÑ Ñ Ð½Ð¸Ð¼Ð¸."/> + <check_box label="Видны аватары" left="262" name="SeeAvatarsCheck" tool_tip="Ðватары Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… учаÑтков Ñмогут видеть аватары на Ñтом учаÑтке и общатьÑÑ Ñ Ð½Ð¸Ð¼Ð¸ в чате, а вы также Ñможете видеть их и общатьÑÑ Ñ Ð½Ð¸Ð¼Ð¸."/> <text name="landing_point"> Ð’ точку телепортации: [LANDING] </text> @@ -372,7 +372,7 @@ <text name="Teleport Routing: "> Вариант телепортации: </text> - <combo_box name="landing type" tool_tip="Вариант телепортации – выберите, каким образом будет производитьÑÑ Ñ‚ÐµÐ»ÐµÐ¿Ð¾Ñ€Ñ‚Ð°Ñ†Ð¸Ñ Ð½Ð° вашу землю"> + <combo_box name="landing type" width="150" tool_tip="Вариант телепортации – выберите, каким образом будет производитьÑÑ Ñ‚ÐµÐ»ÐµÐ¿Ð¾Ñ€Ñ‚Ð°Ñ†Ð¸Ñ Ð½Ð° вашу землю"> <combo_box.item label="Ð’ черном ÑпиÑке" name="Blocked"/> <combo_box.item label="Ð’ точку телепортации" name="LandingPoint"/> <combo_box.item label="Ð’ любое меÑто" name="Anywhere"/> @@ -439,7 +439,7 @@ <panel.string name="estate_override"> ЧаÑÑ‚ÑŒ Ñтих параметров уÑтановлена на уровне Ð·ÐµÐ¼Ð»ÐµÐ²Ð»Ð°Ð´ÐµÐ½Ð¸Ñ </panel.string> - <check_box label="ДоÑтуп открыт Ð´Ð»Ñ Ð²Ñех (При ÑнÑÑ‚Ð¸Ñ Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÐµÑ‚ Ñоздана запиÑÑŒ в Ñтроке запрета)" name="public_access"/> + <check_box label="ДоÑтуп открыт Ð´Ð»Ñ Ð²Ñех" tool_tip="При ÑнÑÑ‚Ð¸Ñ Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÐµÑ‚ Ñоздана запиÑÑŒ в Ñтроке запрета" name="public_access"/> <check_box label="Должен быть 18 и Ñтарше [ESTATE_AGE_LIMIT]" name="limit_age_verified" tool_tip="ДоÑтуп к Ñтому учаÑтку имеют только жители 18 лет и Ñтарше. Более Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð½Ð°Ñ…Ð¾Ð´Ð¸Ñ‚ÑÑ Ð·Ð´ÐµÑÑŒ: [SUPPORT_SITE]."/> <check_box label="Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ платежах должна быть в файле [ESTATE_PAYMENT_LIMIT]" name="limit_payment" tool_tip="Ð”Ð»Ñ Ð´Ð¾Ñтупа к Ñтому учаÑтку у Ð¶Ð¸Ñ‚ÐµÐ»Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° быть зарегиÑтрирована Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ð± оплате. Более Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð½Ð°Ñ…Ð¾Ð´Ð¸Ñ‚ÑÑ Ð·Ð´ÐµÑÑŒ: [SUPPORT_SITE]."/> <check_box label="Разрешить группе [GROUP] без вÑÑких ограничений" name="GroupCheck" tool_tip="Группа уÑтанавливаетÑÑ Ð½Ð° оÑновной вкладке."/> diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml index 08accc39fe949d6663fddd941776a76e1656176e..1e4f9e9abbb35c997a359ac813dfaa809e03dc81 100644 --- a/indra/newview/skins/default/xui/ru/notifications.xml +++ b/indra/newview/skins/default/xui/ru/notifications.xml @@ -1436,9 +1436,9 @@ <usetemplate name="okcancelbuttons" notext="Продолжить" yestext="Создать аккаунт..."/> </notification> <notification name="LoginPacketNeverReceived"> - Возникли неполадки при подключении. Возможно, проблема Ñ Ð²Ð°ÑˆÐ¸Ð¼ подключением к интернету или [SECOND_LIFE_GRID]. + Возникли неполадки при подключении. Возможно, проблема Ñ Ð²Ð°ÑˆÐ¸Ð¼ подключением к интернету или [SECOND_LIFE_GRID] временно недоÑтупна. -Варианты ваших дейÑтвий: проверьте подключение к интернету и повторите попытку через неÑколько минут, нажмите кнопку «Справка» Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° к [SUPPORT_SITE] или кнопку «ТелепортациÑ», чтобы телепортироватьÑÑ Ð´Ð¾Ð¼Ð¾Ð¹. +Ð’Ñ‹ можете проверить подключение к интернету, повторить попытку через неÑколько минут, нажать кнопку «Справка» Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð° на [SUPPORT_SITE] или нажать кнопку «ТелепортациÑ», чтобы телепортироватьÑÑ Ð´Ð¾Ð¼Ð¾Ð¹. <url name="url"> http://secondlife.com/support/ </url> diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_chat.xml b/indra/newview/skins/default/xui/ru/panel_preferences_chat.xml index c2fcac8840420d44f94f7600e84a3d12c0723bab..03a714f266e3c35e8445df6afc53e186c70f44da 100644 --- a/indra/newview/skins/default/xui/ru/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/ru/panel_preferences_chat.xml @@ -5,15 +5,15 @@ <check_box initial_value="true" label="ВоÑпроизводить анимацию ввода текÑта при общении" name="play_typing_animation"/> <check_box label="ОтправлÑÑ‚ÑŒ мне ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾ почте, когда Ð¼ÐµÐ½Ñ Ð½ÐµÑ‚ в Ñети" name="send_im_to_email"/> <check_box label="Только Ð´Ñ€ÑƒÐ·ÑŒÑ Ð¸ группы могут звонить мне и отправлÑÑ‚ÑŒ IM" name="voice_call_friends_only_check"/> - <text name="font_size"> + <text name="font_size" left="361"> Размер шрифта: </text> - <combo_box name="chat_font_size"> + <combo_box name="chat_font_size" left="361"> <item label="Мелкий" name="Small" value="0"/> <item label="Средний" name="Medium" value="1"/> <item label="Крупный" name="Large" value="2"/> </combo_box> - <check_box label="Чат в пузырьках" name="bubble_text_chat"/> + <check_box label="Чат в пузырьках" name="bubble_text_chat" left_delta="19"/> </panel> <panel name="im_notification_settings"> <text name="friend_ims"> diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_setup.xml b/indra/newview/skins/default/xui/ru/panel_preferences_setup.xml index d4d0ef9e7ca84bbac88ea1f422caf3d576fa4b17..137e047d977a7753656a459cefaa2a1c3977c925 100644 --- a/indra/newview/skins/default/xui/ru/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/ru/panel_preferences_setup.xml @@ -14,7 +14,7 @@ <text name="Web:"> Браузер: </text> - <radio_group name="preferred_browser_behavior"> + <radio_group name="preferred_browser_behavior" left_delta="30"> <radio_item label="ИÑпользуйте вÑтроенный браузер Ð´Ð»Ñ Ð²Ñех ÑÑылок" name="internal" tool_tip="Будет иÑпользоватьÑÑ Ð±Ñ€Ð°ÑƒÐ·ÐµÑ€, заданный в ÑиÑтеме по умолчанию. Ðе рекомендуетÑÑ, еÑли [APP_NAME] работает в полноÑкранном режиме." value="0"/> <radio_item label="Ð”Ð»Ñ ÑÑылок Second Life Ñледует иÑпользовать только вÑтроенный браузер" name="external" tool_tip="ИÑпользуйте вÑтроенный браузер Ð´Ð»Ñ Ñправки, веб-ÑÑылок и Ñ‚.д. Ð”Ð»Ñ ÑÑылок LindenLab/Second Life Ñледует иÑпользовать только вÑтроенный браузер." value="1"/> <radio_item label="Ð”Ð»Ñ Ð²Ñех ÑÑылок Ñледует иÑпользовать вÑтроенный браузер" name="external_all" tool_tip="Ð”Ð»Ñ Ð¿Ñ€Ð¾Ñмотра Ñправки, ÑÑылок на веб-Ñтраницы и Ñ‚. д. будет иÑпользоватьÑÑ Ð²Ñтроенный браузер. Ðтот браузер открываетÑÑ ÐºÐ°Ðº новое окно в [APP_NAME]." value="2"/> diff --git a/indra/newview/skins/default/xui/tr/floater_about_land.xml b/indra/newview/skins/default/xui/tr/floater_about_land.xml index 48b16e2fdea5d08ee2fb766bfd18e823a0adb689..1101e5055a95101328a65de736007ee51f879aa1 100644 --- a/indra/newview/skins/default/xui/tr/floater_about_land.xml +++ b/indra/newview/skins/default/xui/tr/floater_about_land.xml @@ -360,10 +360,10 @@ Sadece büyük parseller aramada görünür. Anlık Görüntü: </text> <texture_picker name="snapshot_ctrl" tool_tip="Bir resim seçmek için tıklayın"/> - <text name="allow_see_label"> + <text name="allow_see_label" top="170"> DiÄŸer parsellerdeki avatarlar bu parseldeki avatarları görebilir ve onlarla sohbet edebilir </text> - <check_box label="Avatarları Gör" name="SeeAvatarsCheck" tool_tip="DiÄŸer parsellerdeki avatarların bu parseldeki avatarları görmesine ve onlarla sohbet etmesine, sizin de onları görüp, onlarla sohbet etmenize imkan tanır."/> + <check_box label="Avatarları Gör" name="SeeAvatarsCheck" top="170" tool_tip="DiÄŸer parsellerdeki avatarların bu parseldeki avatarları görmesine ve onlarla sohbet etmesine, sizin de onları görüp, onlarla sohbet etmenize imkan tanır."/> <text name="landing_point"> Ä°niÅŸ Noktası: [LANDING] </text> diff --git a/indra/newview/tests/llsecapi_test.cpp b/indra/newview/tests/llsecapi_test.cpp index d7e87ed52ea5dc0c1a8d9c9853a358774c1fd180..a1005c654cde01744661dba4f99285c805be73f2 100644 --- a/indra/newview/tests/llsecapi_test.cpp +++ b/indra/newview/tests/llsecapi_test.cpp @@ -60,12 +60,21 @@ LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(X509* openssl_cert LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(const X509_STORE_CTX* chain) { return NULL; } LLPointer<LLCertificateStore> LLSecAPIBasicHandler::getCertificateStore(const std::string& store_id) { return NULL; } void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type, const std::string& data_id, const LLSD& data) {} +void LLSecAPIBasicHandler::addToProtectedMap(const std::string& data_type, const std::string& data_id, const std::string& map_elem, const LLSD& data) {} +void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type, const std::string& data_id, const std::string& map_elem) {} LLSD LLSecAPIBasicHandler::getProtectedData(const std::string& data_type, const std::string& data_id) { return LLSD(); } void LLSecAPIBasicHandler::deleteProtectedData(const std::string& data_type, const std::string& data_id) {} LLPointer<LLCredential> LLSecAPIBasicHandler::createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator) { return NULL; } LLPointer<LLCredential> LLSecAPIBasicHandler::loadCredential(const std::string& grid) { return NULL; } void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool save_authenticator) {} void LLSecAPIBasicHandler::deleteCredential(LLPointer<LLCredential> cred) {} +bool LLSecAPIBasicHandler::hasCredentialMap(const std::string& storage, const std::string& grid) { return false; } +void LLSecAPIBasicHandler::loadCredentialMap(const std::string& storage, const std::string& grid, credential_map_t& credential_map) {} +LLPointer<LLCredential> LLSecAPIBasicHandler::loadFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) { return NULL; } +void LLSecAPIBasicHandler::addToCredentialMap(const std::string& storage, LLPointer<LLCredential> cred, bool save_authenticator) {} +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, LLPointer<LLCredential> cred) {} +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) {} +void LLSecAPIBasicHandler::removeCredentialMap(const std::string& storage, const std::string& grid) {} // ------------------------------------------------------------------------------------------- // TUT diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index a4cda0ba78cfe196acbc22fe004ec3fa6bd48453..a403760670eeff299cf61d3b389e8fc5a054955e 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1332,7 +1332,6 @@ def package_finish(self): print "Converting temp disk image to final disk image" self.run_command(['hdiutil', 'convert', sparsename, '-format', 'UDZO', '-imagekey', 'zlib-level=9', '-o', finalname]) - self.run_command(['hdiutil', 'internet-enable', '-yes', finalname]) # get rid of the temp file self.package_file = finalname self.remove(sparsename)