diff options
author | AndreyL ProductEngine <alihatskiy@productengine.com> | 2019-11-27 23:20:03 +0200 |
---|---|---|
committer | AndreyL ProductEngine <alihatskiy@productengine.com> | 2019-11-27 23:20:03 +0200 |
commit | 56056aa198fc31a14cb4320762033958e96558cc (patch) | |
tree | d274000fb53dc1234cff8cddd8b3d3b756bf3681 /indra | |
parent | 78bdf57ad6610b34389226bf941ba736ca0c2225 (diff) | |
parent | 191c1791f4f83fee1be6e71aa9e3f246206b2e80 (diff) |
Upstream merge from viewer-neko
Diffstat (limited to 'indra')
274 files changed, 10242 insertions, 3779 deletions
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 2b54cd4155..a5770c5528 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 6ab61689fd..e7db84f6ab 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 1549c41e62..37904936d8 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 af41b9e460..7e52a620db 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 0fbf4b966b..ef29e7e5cd 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 29f0c7da9a..984e90f376 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -242,6 +242,64 @@ void _ll_apr_assert_status(apr_status_t status, const char* file, int 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 // LLAPRFile::LLAPRFile() @@ -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 da50dda103..0d6637f999 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -180,9 +180,6 @@ public: 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 @@ public: 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 67e9fad1ab..cc775775bf 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 0000000000..ecfc289cb3 --- /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 0000000000..ad0ebec67c --- /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 1aaff5628f..0bae59ef4c 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 0b72b53186..34268d94f6 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 be534b3ce4..e0b2876a00 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 9dea876114..7a0c8cd8f5 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 3b1b060c02..ead9a37fb8 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 f298764cc0..f7dc6272cf 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 e7a8ca2f9d..ac02364a67 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 24387fbffd..0eae6d9826 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 3510f93805..6cf6af6437 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 04b34a296c..6fd17c9154 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 134154aa6c..fcda2a85f6 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 c4c7e66703..e70e259436 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 8d7c4c0282..5ac5f6c580 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 4e0c53c37e..6d5ad0ba08 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 c8b9d5d19f..32e0e2cc3b 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 f6c5d9e228..0af5a1b96d 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 78b1483810..85197d1272 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 4f52afb317..9d11ee0421 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -118,7 +118,7 @@ public: 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 e24d222cb6..8fb3054eac 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 a0987b35d8..bc5dd62f45 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 031a315d62..7c48e57a1a 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 c0f0cec80b..bcc702d31f 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 4c4302d05b..6db1fe9c90 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -78,6 +78,7 @@ public: // 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 722dd9050b..36fbb381bb 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 42802cd339..e3bb36192c 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 165f67499b..f8c04e8a2f 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -395,6 +395,15 @@ protected: 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 @@ private: 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 200dd2fdca..1e18396184 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -213,6 +213,12 @@ LLSD LLMenuItemGL::getValue() const } //virtual +bool LLMenuItemGL::hasAccelerator(const KEY &key, const MASK &mask) const +{ + return (mAcceleratorKey == key) && (mAcceleratorMask == mask); +} + +//virtual BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask) { if( getEnabled() && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) ) @@ -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 78f688642e..f3844af507 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 @@ public: /*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 @@ public: 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 @@ public: /*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 @@ public: 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 @@ private: 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 9fc6c05ead..6a7075301b 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 1509446920..62cf41256b 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -180,6 +180,7 @@ public: Optional<std::string> control; Optional<bool> invert_control; Optional<bool> session_only; + Optional<bool> checkbox_only; FormIgnore(); }; @@ -232,7 +233,8 @@ public: 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 b3a79bc1eb..fde6de4921 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 e2bf52c14b..5f2f490d81 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -88,6 +88,7 @@ public: 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 6135cc56ad..3db38bbfac 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 e6c7891397..c14099dbd5 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -107,6 +107,7 @@ public: 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 8000efad0e..13839da400 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 d625ebddcc..19576fb247 100644 --- a/indra/llui/llscrolllistcell.h +++ b/indra/llui/llscrolllistcell.h @@ -59,7 +59,8 @@ public: 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 @@ public: 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 @@ public: 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 @@ private: }; /* - * Cell displaying an image. + * Cell displaying an image. AT the moment, this is specifically UI image */ class LLScrollListIcon : public LLScrollListCell { @@ -223,4 +226,26 @@ private: 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 f4028057e8..94b130e28d 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 b35a8608e7..bf1055c8dc 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 @@ public: commit_on_keyboard_movement, mouse_wheel_opaque; + Optional<ESelectionType, SelectionTypeNames> selection_type; + // display flags Optional<bool> has_border, draw_heading, @@ -114,7 +128,8 @@ public: // 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 @@ public: /*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 @@ private: 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 @@ private: 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 df22c88afb..51c615dd00 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 13655b5873..d2c3dd7721 100644 --- a/indra/llui/llscrolllistitem.h +++ b/indra/llui/llscrolllistitem.h @@ -77,15 +77,21 @@ public: 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 @@ public: 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 22635f734e..e64078828b 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 9831c35858..4239cdf43c 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -103,6 +103,7 @@ public: /*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 df74e113e9..c98da0d410 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 03d946f1b7..f740f14e4d 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -160,8 +160,8 @@ public: 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 63ed427ab5..333d03f208 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 2a190365b3..771d32d2fc 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 e36ca7c8c6..db81900aaf 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -426,6 +426,7 @@ public: /*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 @@ protected: 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 119cbebc81..3c34fd269e 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 d4790f9f29..12a6baa3e6 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 cf33db8b37..1cb687e3b6 100644 --- a/indra/llwindow/lldxhardware.h +++ b/indra/llwindow/lldxhardware.h @@ -94,6 +94,10 @@ public: 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 f6f6c3931c..5404ac50e5 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 6f2dc87317..36bd8bcbed 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 @@ public: 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 bea66e763c..e41ebd42f3 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 d825a3424c..d221dd117c 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 @@ public: 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 @@ public: 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 1990499459..5b9dce02c4 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 94c725fc7e..be61e1e16c 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 4d753024fe..3b18648138 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -49,11 +49,14 @@ public: 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 99af161102..44fd4127ce 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 3554f90be8..2604a23c85 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 e05f507506..0b3936f8a5 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 17400a203e..013a422d35 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 de0d366492..9312bbc91a 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 6a27a65499..0000000000 --- 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 eead92fd8e..cff21b13c4 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 c296a0413d..650685fb94 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 80702a1079..f7d35b33c2 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 694e89ab99..5a872f2aac 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 cab0c523b2..dae397a3b6 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 index a8037fec05..dd74293644 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 49601ae98f..bbac65ef61 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 31b8b90518..0e43af91df 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 5ba1083d8e..a5d37ef496 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -343,6 +343,7 @@ public: 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 0b4b848014..c55c12e670 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 d087de1e2f..a4bc8434b0 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -266,6 +266,7 @@ public: 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 7325ec598a..fb864f18c1 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 ff897ef962..3e33815b20 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 b37aba6c15..4b6c855bde 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 f1d8ef4528..672a07f7d3 100644 --- a/indra/newview/llaudiosourcevo.h +++ b/indra/newview/llaudiosourcevo.h @@ -41,7 +41,11 @@ public: /*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 1099d4bc09..722523830b 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 92eeebd705..f0682dc1ba 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 f7c61efce0..5539fa75dd 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 0075b62100..60a5204547 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 1587903a15..85ee33edb1 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 5b4b7789b4..347997a69a 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1493,19 +1493,25 @@ 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() { LLFavoritesOrderStorage::instance().cleanup(); @@ -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 cac32c7f2a..571208aa31 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -208,9 +208,15 @@ public: * @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 @@ private: 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 @@ private: slurls_map_t mSLURLs; std::set<LLUUID> mMissingSLURLs; bool mIsDirty; + bool mRecreateFavoriteStorage; struct IsNotInFavorites { @@ -275,7 +279,9 @@ private: 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 56619e818a..957b2e1e8e 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 33099db1b9..ab95bc06b8 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 ec2c9740af..1a784223c2 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 55561fa128..44725cab70 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 a8dbbc9ffe..7ca4ee6945 100644 --- a/indra/newview/llfloaterconversationpreview.h +++ b/indra/newview/llfloaterconversationpreview.h @@ -66,6 +66,7 @@ private: bool mShowHistory; bool mHistoryThreadsBusy; bool mOpened; + bool mIsGroup; }; #endif /* LLFLOATERCONVERSATIONPREVIEW_H_ */ diff --git a/indra/newview/llfloaterexperiencepicker.cpp b/indra/newview/llfloaterexperiencepicker.cpp index bb54c57baf..c642da7b83 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 fdc1b47334..184e39402a 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 0000000000..5659cb2f79 --- /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 0000000000..119aece2d1 --- /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 b840d37c4d..e778e8eb9e 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 8efb3e6461..1d702c6704 100644 --- a/indra/newview/llfloatergesture.h +++ b/indra/newview/llfloatergesture.h @@ -95,6 +95,9 @@ private: 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 c47ff1c1d9..faa7e9f3db 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 7fdba8734a..30c90ac184 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 f6a3ca5550..657e5711f0 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 3098c6d118..d8f4360142 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 10cce3bd22..595d584799 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 dd5c301206..060773f93e 100644 --- a/indra/newview/llfloaterlinkreplace.h +++ b/indra/newview/llfloaterlinkreplace.h @@ -94,6 +94,7 @@ public: 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 b6efc1590e..e12ad262f8 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 edc90d1695..1c66570650 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -125,7 +125,7 @@ public: /*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 @@ private: 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 0d4c834122..721fce059e 100644 --- a/indra/newview/llfloatermodeluploadbase.h +++ b/indra/newview/llfloatermodeluploadbase.h @@ -45,7 +45,7 @@ public: 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 fe347a91a3..c9c563a054 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 1b8229ada6..9ede7d5bcf 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 @@ protected: // 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 @@ public: 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 @@ public: void refreshUI(); - void onCommitParcelMediaAutoPlayEnable(); void onCommitMediaEnabled(); void onCommitMusicEnabled(); void applyResolution(); @@ -180,6 +173,7 @@ public: void onClickProxySettings(); void onClickTranslationSettings(); void onClickPermsDefault(); + void onClickRememberedUsernames(); void onClickAutoReplace(); void onClickSpellChecker(); void onClickRenderExceptions(); @@ -202,7 +196,6 @@ private: 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 @@ private: 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 fbb7432f71..64ad40f419 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -85,7 +85,7 @@ public: } 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 960fd9620d..60cb22c4de 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 54e683e048..d1d83e6e03 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 f46152dcec..6898dce7b1 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 cc772c8f5c..ecf6d42d69 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 fc6efdb840..2ba8aa422b 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 3606a439a6..48101bf0d9 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 e331a51bda..d5142a4496 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 2a9e4679a8..79c831ebb6 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -91,6 +91,7 @@ public: 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 349ba6183b..d460aa1452 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 @@ public: // 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 16385928b4..e8bc915f22 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 4a1fec8454..3f24211f41 100644 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -327,6 +327,9 @@ private: 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 d4993a1091..6f461673ee 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 0000000000..a94836c59d --- /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 0000000000..84730e4d4f --- /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 42b5ff3890..802e4941e6 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 453bf17b11..0c64531783 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 b71a34ae0a..8b7fe14e16 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -106,7 +106,7 @@ public: 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 @@ protected: 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 eca34c0d4d..22cedf450e 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 805c25508f..aa0c7fb73b 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 ec312baca3..fee9225f77 100644 --- a/indra/newview/llmarketplacefunctions.h +++ b/indra/newview/llmarketplacefunctions.h @@ -204,7 +204,9 @@ public: 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 b399ab9bc4..0affe8efb4 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -202,12 +202,29 @@ 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 11400c8274..958c76f261 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -92,6 +92,7 @@ public: 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 31e3d408d7..ce41e2bd35 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 8fc356c928..54409a6994 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 fc1039b372..112da55682 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 b405d3dca2..6a79a0c68c 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 b2b6de94b3..12b46e9bb2 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 7f6c065bb9..e9fe493d7e 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 6d0c30fbf3..c0342eef4e 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 0efb234015..e3d75d5604 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 e253557797..fd76a36044 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() @@ -443,24 +525,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), void* callback_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; @@ -953,6 +1081,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) { LLPanelLogin *self = (LLPanelLogin *)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 c633582d89..3eb7b68949 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -55,9 +55,9 @@ public: 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 @@ public: void setSiteIsAlive( bool alive ); - void showLoginWidgets(); - static void loadLoginPage(); static void giveFocus(); static void setAlwaysRefresh(bool refresh); @@ -88,6 +86,9 @@ public: // 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 @@ private: 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 @@ private: 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 2dca55514d..b654e928e2 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 961e259947..2ef82d0cf9 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 9b4dc5474a..0ca4a83779 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 8105beae1b..3c74aed734 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 735eaa423d..58bc049338 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 6792137350..f063d84272 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 1533a27469..2f534ac245 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 1b4295ddad..18b669ff4f 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 72d7cf1e45..10e510b842 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 d207f3b5b7..c0f0a367c7 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -464,7 +464,19 @@ public: // 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 @@ public: 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 9ab9e4a1a2..a8bb54a90e 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 c35617f564..426b5d392a 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 @@ public: // 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 @@ public: // 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 90f8f84ea4..f849fecaf6 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 3e8bfdb00e..3bed484b58 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 @@ public: // 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 @@ private: 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 0000000000..4eb76c9d89 --- /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 0000000000..70190230e4 --- /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 2503e2a5e2..d508621b41 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 @@ public: } 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 @@ public: 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 74cf7afe35..5f29254182 100644 --- a/indra/newview/llsidepaneliteminfo.h +++ b/indra/newview/llsidepaneliteminfo.h @@ -57,6 +57,9 @@ public: 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 @@ private: 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 @@ protected: 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 f03c7abc4d..7fa06f51e3 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 cbfb07874b..dc259cb22d 100644 --- a/indra/newview/llsidepaneltaskinfo.h +++ b/indra/newview/llsidepaneltaskinfo.h @@ -95,6 +95,7 @@ protected: 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 f5fea9dece..43dc676a63 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 1dc1e65fe5..7e6f3ef7bc 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 c8c39ae00f..008dfe2a45 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 9eda33d3d2..b8c227334d 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 403d590aca..cad877f799 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -114,7 +114,8 @@ private: 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 e5af47ab6c..f3bb574191 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 81ea7aeee2..da59290930 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -155,6 +155,7 @@ private: 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 @@ private: 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 e2bb904eff..fd1c5373ae 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 941cb410fc..f882fd31ee 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 15bf11d42c..9b4e054bf1 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 @@ public: 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 @@ private: 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 a2116817a2..bccf88128d 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 e4a75acfda..a5a637c6fa 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 7c624d5b50..100d5ee713 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 6a9b72a5ae..f4c758ade9 100644 --- a/indra/newview/lltoastpanel.h +++ b/indra/newview/lltoastpanel.h @@ -64,4 +64,23 @@ protected: 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 b5d78f3654..5235914c34 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 c5bad9d532..41a38804ce 100644 --- a/indra/newview/lltool.h +++ b/indra/newview/lltool.h @@ -49,7 +49,7 @@ public: 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 @@ public: 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 f66211ef34..7d77a8983f 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 3831f7d67d..a4806ceaf6 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 f6eb290bc3..3fcf193dec 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 54df5198c8..dd429d4ccf 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 95d155a474..ac6751aac0 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 @@ public: 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 @@ public: 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 @@ private: 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 15c3dad38e..77e950a1c9 100644 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -53,7 +53,7 @@ public: 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 d8526e63ca..6df849674f 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 f475ab7d66..846a8e62a1 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 0000000000..0718a27696 --- /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 0000000000..1fe55bd585 --- /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 9d7da115ac..6ff02ffe66 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 e930eb20d3..0000000000 --- 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 110dc89d28..0000000000 --- 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 6cfc22a4e5..700462ad75 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 014f9048f0..2b604d3a7a 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 @@ public: 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 @@ public: /*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 f4a64a8e55..69ab0a71af 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 dc82719109..a49218858b 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 @@ private: 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 a9a91b158b..687a48e7c1 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 b0ad81614a..12a9757f71 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 2d6636f30d..78829a6a56 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -254,7 +254,7 @@ public: /*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 @@ private: 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 c7a77d4d2a..05230c17e0 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 873b300489..03c5403a1e 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -403,6 +403,7 @@ public: // 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 @@ public: 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 @@ private: 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 @@ protected: 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 @@ protected: 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 0000000000..d4aa783f12 --- /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 0000000000..dc711917d2 --- /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 b5a76ccba2..54d9804b9c 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 33565307f2..cf8e9a97e7 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -39,6 +39,9 @@ public: 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; BOOL mPlayed; diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 6cc88d0c0b..d91d0abb99 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 29219843c9..288077fafc 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -268,7 +268,8 @@ public: // *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 15b2ac8acf..85d87a43af 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 06524847d1..561319ca5d 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 61f4ee463d..7f87836644 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 071a3632dd..1f49c0756c 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -175,8 +175,9 @@ public: 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 @@ public: /*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 @@ public: /*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 @@ public: 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 @@ public: // 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 97b405c1d0..acf25b9792 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 ca1216b89d..3c4c785a42 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 00dccc5d12..e352a6c1fa 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -348,7 +348,7 @@ public: 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 63ace4fe52..16b27fd144 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 d8c8cb0461..fca8de7410 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 f95b853c31..cecaac7f85 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -408,17 +408,11 @@ public: 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 @@ protected: 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 739f7bd47c..530adb8975 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 9e4297baaf..aa8c79b0d2 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 9bc3a2a33b..a6df079223 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 bd73c234a6..eb2d3bf873 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 5aba0546f3..9b18dbc2e2 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 4dd64cba2a..8f55b3297f 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 550a99fe0a..51c82c97f8 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 ff0a6614bd..e0aa9fe4a9 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 0000000000..7b777befee --- /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 9f853fd960..a143adfa06 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 bac3ea86f1..6540f5e348 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 0000000000..f2e894733f --- /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 7802f65902..0000000000 --- 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 0e62d50072..ee730dcb01 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 9e50e89ac9..3fa71e7bfe 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 4e89df5a73..48d9eee4cd 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 d122d7491c..c2af4f54d0 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 c1458977ca..5cae643e44 100644 --- a/indra/newview/skins/default/xui/en/menu_gesture_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_gesture_gear.xml @@ -12,6 +12,16 @@ 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" name="copy_gesture"> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 7bb7b5d62c..af185d43b0 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 f72767cceb..92711d4397 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> @@ -2480,6 +2481,13 @@ Sorry, but the system was unable to complete your region crossing in a timely fa </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" name="no_host" type="alertmodal"> <tag>fail</tag> @@ -3093,6 +3101,29 @@ See https://wiki.secondlife.com/wiki/Adding_Spelling_Dictionaries <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" type="alertmodal"> <tag>friendship</tag> @@ -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 @@ -3547,6 +3581,30 @@ You can either check your Internet connection and try again in a few minutes, cl <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" type="alertmodal"> Your character will appear in a moment. @@ -5999,6 +6057,34 @@ Would you like to turn off Do Not Disturb before completing this transaction? </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" type="alertmodal"> @@ -6110,6 +6196,20 @@ Are you sure you want to permanently delete the contents of your Lost And Found? <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" type="alertmodal"> The following SLurl has been copied to your clipboard: @@ -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 27c653bc35..d1175a9fe1 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 3509eaa285..e846edf1d4 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 7759d4fdb2..d601b36ce5 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 b2d8bb874b..0000000000 --- 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 79d190e1e0..99c47eb825 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 43d580844f..4c0cdd321e 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 4f0bb9d3b7..d0518aa245 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -143,6 +143,32 @@ 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" follows="left|top" @@ -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 9e7023d2f2..ece6c95080 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 0000000000..904387909e --- /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 8794e3bf95..d106456b31 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 8f2e81b9f7..c2995393fd 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 9eedc45aa9..0594e18c96 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 5a9a16d344..57f8bb542d 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 998d2a8863..57a1b2ec1e 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 2c8848265f..dbff3fcf0e 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 f7e036efd7..388a5d84d2 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 1b191d3e46..36888850c4 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 219857eb99..fb65e71ee1 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 148a5a35d2..c295172abf 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 422243445b..a0f2e0eba7 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 0a7837e122..50e2d1a8de 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 743969f557..53a2057455 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 ef71baa0b6..96e54bb9bc 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 1ae6df76d9..222572b4bf 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 08accc39fe..1e4f9e9abb 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 c2fcac8840..03a714f266 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 d4d0ef9e7c..137e047d97 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 48b16e2fde..1101e5055a 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 d7e87ed52e..a1005c654c 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 a4cda0ba78..a403760670 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1332,7 +1332,6 @@ class DarwinManifest(ViewerManifest): 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) |