diff options
Diffstat (limited to 'indra')
52 files changed, 771 insertions, 172 deletions
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 4d98e73092..cd7da5d6c1 100755 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -37,6 +37,7 @@ set(cmake_SOURCE_FILES FindNDOF.cmake FindOpenJPEG.cmake FindSCP.cmake + FindURIPARSER.cmake FindXmlRpcEpi.cmake FindZLIB.cmake FMODEX.cmake @@ -97,6 +98,7 @@ set(cmake_SOURCE_FILES Tut.cmake UI.cmake UnixInstall.cmake + URIPARSER.cmake Variables.cmake ViewerMiscLibs.cmake VisualLeakDetector.cmake diff --git a/indra/cmake/FindURIPARSER.cmake b/indra/cmake/FindURIPARSER.cmake new file mode 100644 index 0000000000..8ab9f0f4ed --- /dev/null +++ b/indra/cmake/FindURIPARSER.cmake @@ -0,0 +1,46 @@ +# -*- cmake -*- + +# - Find uriparser +# Find the URIPARSER includes and library +# This module defines +# URIPARSER_INCLUDE_DIRS, where to find uriparser.h, etc. +# URIPARSER_LIBRARIES, the libraries needed to use uriparser. +# URIPARSER_FOUND, If false, do not try to use uriparser. +# +# This FindURIPARSER is about 43 times as fast the one provided with cmake (2.8.x), +# because it doesn't look up the version of uriparser, resulting in a dramatic +# speed up for configure (from 4 minutes 22 seconds to 6 seconds). +# +# Note: Since this file is only used for standalone, the windows +# specific parts were left out. + +FIND_PATH(URIPARSER_INCLUDE_DIR uriparser/uri.h + NO_SYSTEM_ENVIRONMENT_PATH + ) + +FIND_LIBRARY(URIPARSER_LIBRARY uriparser) + +if (URIPARSER_LIBRARY AND URIPARSER_INCLUDE_DIR) + SET(URIPARSER_INCLUDE_DIRS ${URIPARSER_INCLUDE_DIR}) + SET(URIPARSER_LIBRARIES ${URIPARSER_LIBRARY}) + SET(URIPARSER_FOUND "YES") +else (URIPARSER_LIBRARY AND URIPARSER_INCLUDE_DIR) + SET(URIPARSER_FOUND "NO") +endif (URIPARSER_LIBRARY AND URIPARSER_INCLUDE_DIR) + +if (URIPARSER_FOUND) + if (NOT URIPARSER_FIND_QUIETLY) + message(STATUS "Found URIPARSER: ${URIPARSER_LIBRARIES}") + SET(URIPARSER_FIND_QUIETLY TRUE) + endif (NOT URIPARSER_FIND_QUIETLY) +else (URIPARSER_FOUND) + if (URIPARSER_FIND_REQUIRED) + message(FATAL_ERROR "Could not find URIPARSER library") + endif (URIPARSER_FIND_REQUIRED) +endif (URIPARSER_FOUND) + +mark_as_advanced( + URIPARSER_LIBRARY + URIPARSER_INCLUDE_DIR + ) + diff --git a/indra/cmake/URIPARSER.cmake b/indra/cmake/URIPARSER.cmake new file mode 100644 index 0000000000..de146885a0 --- /dev/null +++ b/indra/cmake/URIPARSER.cmake @@ -0,0 +1,35 @@ +# -*- cmake -*- + +set(URIPARSER_FIND_QUIETLY ON) +set(URIPARSER_FIND_REQUIRED ON) + +include(Prebuilt) + +if (USESYSTEMLIBS) + include(FindURIPARSER) +else (USESYSTEMLIBS) + use_prebuilt_binary(uriparser) + if (WINDOWS) + set(URIPARSER_LIBRARIES + debug uriparserd + optimized uriparser) + elseif (LINUX) + # + # When we have updated static libraries in competition with older + # shared libraries and we want the former to win, we need to do some + # extra work. The *_PRELOAD_ARCHIVES settings are invoked early + # and will pull in the entire archive to the binary giving it. + # priority in symbol resolution. Beware of cmake moving the + # achive load itself to another place on the link command line. If + # that happens, you can try something like -Wl,-luriparser here to hide + # the archive. Also be aware that the linker will not tolerate a + # second whole-archive load of the archive. See viewer's + # CMakeLists.txt for more information. + # + set(URIPARSER_PRELOAD_ARCHIVES -Wl,--whole-archive uriparser -Wl,--no-whole-archive) + set(URIPARSER_LIBRARIES uriparser) + elseif (DARWIN) + set(URIPARSER_LIBRARIES uriparser) + endif (WINDOWS) + set(URIPARSER_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/uriparser) +endif (USESYSTEMLIBS) diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 63d25225c9..1459b9ada2 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -12,12 +12,14 @@ include(GoogleBreakpad) include(GooglePerfTools) include(Copy3rdPartyLibs) include(ZLIB) +include(URIPARSER) include_directories( ${EXPAT_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ${BREAKPAD_INCLUDE_DIRECTORIES} + ${URIPARSER_INCLUDE_DIRS} ) # add_executable(lltreeiterators lltreeiterators.cpp) @@ -103,6 +105,7 @@ set(llcommon_SOURCE_FILES lltracerecording.cpp lltracethreadrecorder.cpp lluri.cpp + lluriparser.cpp lluuid.cpp llworkerthread.cpp timing.cpp @@ -217,6 +220,7 @@ set(llcommon_HEADER_FILES llunits.h llunittype.h lluri.h + lluriparser.h lluuid.h llwin32headers.h llwin32headerslean.h @@ -261,6 +265,7 @@ target_link_libraries( ${BOOST_PROGRAM_OPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} ${GOOGLE_PERFTOOLS_LIBRARIES} + ${URIPARSER_LIBRARIES} ) if (DARWIN) diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp new file mode 100644 index 0000000000..ef4481d32f --- /dev/null +++ b/indra/llcommon/lluriparser.cpp @@ -0,0 +1,228 @@ +/** + * @file lluriparser.cpp + * @author Protey + * @date 2014-10-07 + * @brief Implementation of the LLUriParser class. + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, 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 "lluriparser.h" + +LLUriParser::LLUriParser(const std::string& u) : mTmpScheme(false), mRes(0) +{ + mState.uri = &mUri; + + if (u.find("://") == std::string::npos) + { + mNormalizedUri = "http://"; + mTmpScheme = true; + } + + mNormalizedUri += u.c_str(); + + mRes = parse(); +} + +LLUriParser::~LLUriParser() +{ + uriFreeUriMembersA(&mUri); +} + +S32 LLUriParser::parse() +{ + mRes = uriParseUriA(&mState, mNormalizedUri.c_str()); + return mRes; +} + +const char * LLUriParser::scheme() const +{ + return mScheme.c_str(); +} + +void LLUriParser::sheme(const std::string& s) +{ + mTmpScheme = !s.size(); + mScheme = s; +} + +const char * LLUriParser::port() const +{ + return mPort.c_str(); +} + +void LLUriParser::port(const std::string& s) +{ + mPort = s; +} + +const char * LLUriParser::host() const +{ + return mHost.c_str(); +} + +void LLUriParser::host(const std::string& s) +{ + mHost = s; +} + +const char * LLUriParser::path() const +{ + return mPath.c_str(); +} + +void LLUriParser::path(const std::string& s) +{ + mPath = s; +} + +const char * LLUriParser::query() const +{ + return mQuery.c_str(); +} + +void LLUriParser::query(const std::string& s) +{ + mQuery = s; +} + +const char * LLUriParser::fragment() const +{ + return mFragment.c_str(); +} + +void LLUriParser::fragment(const std::string& s) +{ + mFragment = s; +} + +void LLUriParser::textRangeToString(UriTextRangeA& textRange, std::string& str) +{ + S32 len = textRange.afterLast - textRange.first; + if (len) + { + str = textRange.first; + str = str.substr(0, len); + } +} + +void LLUriParser::extractParts() +{ + if (mTmpScheme) + { + mScheme.clear(); + } + else + { + textRangeToString(mUri.scheme, mScheme); + } + + textRangeToString(mUri.hostText, mHost); + textRangeToString(mUri.portText, mPort); + textRangeToString(mUri.query, mQuery); + textRangeToString(mUri.fragment, mFragment); + + UriPathSegmentA * pathHead = mUri.pathHead; + while (pathHead) + { + std::string partOfPath; + textRangeToString(pathHead->text, partOfPath); + + mPath += '/'; + mPath += partOfPath; + + pathHead = pathHead->next; + } +} + +S32 LLUriParser::normalize() +{ + if (!mRes) + { + mRes = uriNormalizeSyntaxExA(&mUri, URI_NORMALIZE_SCHEME | URI_NORMALIZE_HOST); + + if (!mRes) + { + S32 chars_required; + mRes = uriToStringCharsRequiredA(&mUri, &chars_required); + + if (!mRes) + { + chars_required++; + std::vector<char> label_buf(chars_required); + mRes = uriToStringA(&label_buf[0], &mUri, chars_required, NULL); + + if (!mRes) + { + mNormalizedUri = &label_buf[mTmpScheme ? 7 : 0]; + } + } + } + } + + return mRes; +} + +void LLUriParser::glue(std::string& uri) const +{ + if (mScheme.size()) + { + uri = mScheme; + uri += "://"; + } + + uri += mHost; + + if (mPort.size()) + { + uri += ':'; + uri += mPort; + } + + uri += mPath; + + if (mQuery.size()) + { + uri += '?'; + uri += mQuery; + + if (mFragment.size()) + { + uri += '#'; + uri += mFragment; + } + } +} + +bool LLUriParser::test() const +{ + std::string uri; + glue(uri); + + return uri == mNormalizedUri; +} + +const char * LLUriParser::normalizedUri() const +{ + return mNormalizedUri.c_str(); +} diff --git a/indra/llcommon/lluriparser.h b/indra/llcommon/lluriparser.h new file mode 100644 index 0000000000..719f916837 --- /dev/null +++ b/indra/llcommon/lluriparser.h @@ -0,0 +1,84 @@ +/** + * @file lluriparser.h + * @author Protey + * @date 20146-10-07 + * @brief Declaration of the UriParser class. + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, 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_LLURIPARSER_H +#define LL_LLURIPARSER_H + +#include <string> +#include "uriparser/Uri.h" + +class LL_COMMON_API LLUriParser +{ +public: + LLUriParser(const std::string& u); + virtual ~LLUriParser(); + + const char * scheme() const; + void sheme (const std::string& s); + + const char * port() const; + void port (const std::string& s); + + const char * host() const; + void host (const std::string& s); + + const char * path() const; + void path (const std::string& s); + + const char * query() const; + void query (const std::string& s); + + const char * fragment() const; + void fragment (const std::string& s); + + const char * normalizedUri() const; + + void extractParts(); + void glue(std::string& uri) const; + bool test() const; + S32 normalize(); + +private: + S32 parse(); + void textRangeToString(UriTextRangeA& textRange, std::string& str); + std::string mScheme; + std::string mHost; + std::string mPort; + std::string mPath; + std::string mQuery; + std::string mFragment; + std::string mNormalizedUri; + + UriParserStateA mState; + UriUriA mUri; + + S32 mRes; + bool mTmpScheme; +}; + +#endif // LL_LLURIPARSER_H diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp index 294f68b122..7735dc1379 100755 --- a/indra/llimage/llimagepng.cpp +++ b/indra/llimage/llimagepng.cpp @@ -67,7 +67,7 @@ BOOL LLImagePNG::updateData() } LLPngWrapper::ImageInfo infop; - if (! pngWrapper.readPng(getData(), NULL, &infop)) + if (! pngWrapper.readPng(getData(), getDataSize(), NULL, &infop)) { setLastError(pngWrapper.getErrorMessage()); return FALSE; @@ -102,7 +102,7 @@ BOOL LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time) return FALSE; } - if (! pngWrapper.readPng(getData(), raw_image)) + if (! pngWrapper.readPng(getData(), getDataSize(), raw_image)) { setLastError(pngWrapper.getErrorMessage()); return FALSE; diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index 2cc7d3c460..aad139f570 100755 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -87,6 +87,12 @@ void LLPngWrapper::errorHandler(png_structp png_ptr, png_const_charp msg) void LLPngWrapper::readDataCallback(png_structp png_ptr, png_bytep dest, png_size_t length) { PngDataInfo *dataInfo = (PngDataInfo *) png_get_io_ptr(png_ptr); + if(dataInfo->mOffset + length > dataInfo->mDataSize) + { + png_error(png_ptr, "Data read error. Requested data size exceeds available data size."); + return; + } + U8 *src = &dataInfo->mData[dataInfo->mOffset]; memcpy(dest, src, length); dataInfo->mOffset += static_cast<U32>(length); @@ -114,7 +120,7 @@ void LLPngWrapper::writeFlush(png_structp png_ptr) // The scanline also begins at the bottom of // the image (per SecondLife conventions) instead of at the top, so we // must assign row-pointers in "reverse" order. -BOOL LLPngWrapper::readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop) +BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInfo *infop) { try { @@ -133,6 +139,7 @@ BOOL LLPngWrapper::readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop) PngDataInfo dataPtr; dataPtr.mData = src; dataPtr.mOffset = 0; + dataPtr.mDataSize = dataSize; png_set_read_fn(mReadPngPtr, &dataPtr, &readDataCallback); png_set_sig_bytes(mReadPngPtr, 0); diff --git a/indra/llimage/llpngwrapper.h b/indra/llimage/llpngwrapper.h index 739f435996..27d7df3bef 100755 --- a/indra/llimage/llpngwrapper.h +++ b/indra/llimage/llpngwrapper.h @@ -44,7 +44,7 @@ public: }; BOOL isValidPng(U8* src); - BOOL readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop = NULL); + BOOL readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInfo *infop = NULL); BOOL writePng(const LLImageRaw* rawImage, U8* dst); U32 getFinalSize(); const std::string& getErrorMessage(); @@ -61,6 +61,7 @@ private: { U8 *mData; U32 mOffset; + S32 mDataSize; }; static void writeFlush(png_structp png_ptr); diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index e5081ee1d5..f290edb5ff 100755 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -60,6 +60,7 @@ #include "v2math.h" #include <set> #include <boost/tokenizer.hpp> +#include <boost/foreach.hpp> // static LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL; @@ -2031,15 +2032,7 @@ void LLMenuGL::arrange( void ) // torn off menus are not constrained to the size of the screen U32 max_width = getTornOff() ? U32_MAX : menu_region_rect.getWidth(); - U32 max_height = U32_MAX; - if (!getTornOff()) - { - max_height = getRect().mTop - menu_region_rect.mBottom; - if (menu_region_rect.mTop - getRect().mTop > (S32)max_height) - { - max_height = menu_region_rect.mTop - getRect().mTop; - } - } + U32 max_height = getTornOff() ? U32_MAX: menu_region_rect.getHeight(); // *FIX: create the item first and then ask for its dimensions? S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") ); // *TODO: Translate @@ -2097,13 +2090,15 @@ void LLMenuGL::arrange( void ) } else { + BOOST_FOREACH(LLMenuItemGL* itemp, mItems) + { + // do first so LLMenuGLItemCall can call on_visible to determine if visible + itemp->buildDrawLabel(); + } item_list_t::iterator item_iter; for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { - // do first so LLMenuGLItemCall can call on_visible to determine if visible - (*item_iter)->buildDrawLabel(); - if ((*item_iter)->getVisible()) { if (!getTornOff() @@ -2111,34 +2106,43 @@ void LLMenuGL::arrange( void ) && *item_iter != mSpilloverBranch && height + (*item_iter)->getNominalHeight() > max_height - spillover_item_height) { - // no room for any more items - createSpilloverBranch(); - - std::vector<LLMenuItemGL*> items_to_remove; - std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove)); - std::vector<LLMenuItemGL*>::iterator spillover_iter; - for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter) + // don't show only one item + int visible_items = 0; + item_list_t::iterator count_iter; + for (count_iter = item_iter; count_iter != mItems.end(); ++count_iter) { - LLMenuItemGL* itemp = (*spillover_iter); - removeChild(itemp); - mSpilloverMenu->addChild(itemp); + if((*count_iter)->getVisible()) + visible_items++; } + if (visible_items>1) + { + // no room for any more items + createSpilloverBranch(); + std::vector<LLMenuItemGL*> items_to_remove; + std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove)); + std::vector<LLMenuItemGL*>::iterator spillover_iter; + for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter) + { + LLMenuItemGL* itemp = (*spillover_iter); + removeChild(itemp); + mSpilloverMenu->addChild(itemp); + } - addChild(mSpilloverBranch); - height += mSpilloverBranch->getNominalHeight(); - width = llmax( width, mSpilloverBranch->getNominalWidth() ); + addChild(mSpilloverBranch); - break; - } - else - { - // track our rect - height += (*item_iter)->getNominalHeight(); - width = llmax( width, (*item_iter)->getNominalWidth() ); + height += mSpilloverBranch->getNominalHeight(); + width = llmax( width, mSpilloverBranch->getNominalWidth() ); + + break; + } } + // track our rect + height += (*item_iter)->getNominalHeight(); + width = llmax( width, (*item_iter)->getNominalWidth() ); + if (mScrollable) { // Determining visible items boundaries @@ -2362,7 +2366,9 @@ void LLMenuGL::createSpilloverBranch() branch_params.label = label; branch_params.branch = mSpilloverMenu; branch_params.font.style = "italic"; - + branch_params.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); + branch_params.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); + branch_params.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor"); mSpilloverBranch = LLUICtrlFactory::create<LLMenuItemBranchGL>(branch_params); } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 367bc9a084..43e048d216 100755 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -38,6 +38,7 @@ #include "lltextutil.h" #include "lltooltip.h" #include "lluictrl.h" +#include "lluriparser.h" #include "llurlaction.h" #include "llurlregistry.h" #include "llview.h" @@ -2019,6 +2020,8 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name) static LLTrace::BlockTimerStatHandle FTM_PARSE_HTML("Parse HTML"); + + void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params) { LLStyle::Params style_params(input_params); @@ -2055,7 +2058,12 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para std::string subtext=text.substr(0,start); appendAndHighlightText(subtext, part, style_params); } + + // add icon before url if need + LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted()); + // output the styled Url + //appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly()); appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly()); // set the tooltip for the Url label @@ -2063,14 +2071,12 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para { segment_set_t::iterator it = getSegIterContaining(getLength()-1); if (it != mSegments.end()) - { - LLTextSegmentPtr segment = *it; - segment->setToolTip(match.getTooltip()); - } + { + LLTextSegmentPtr segment = *it; + segment->setToolTip(match.getTooltip()); + } } - LLTextUtil::processUrlMatch(&match,this,isContentTrusted()); - // move on to the rest of the text after the Url if (end < (S32)text.length()) { diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 738b4d5b8e..dfc10923f3 100755 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -590,6 +590,7 @@ protected: void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params()); void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false); + S32 normalizeUri(std::string& uri); protected: diff --git a/indra/llui/lltextutil.h b/indra/llui/lltextutil.h index 798f14d086..1be81ffd62 100755 --- a/indra/llui/lltextutil.h +++ b/indra/llui/lltextutil.h @@ -64,7 +64,15 @@ namespace LLTextUtil */ const std::string& formatPhoneNumber(const std::string& phone_str); - bool processUrlMatch(LLUrlMatch* match,LLTextBase* text_base, bool is_content_trusted); + /** + * Adds icon before url if need. + * + * @param[in] match an object with results of matching + * @param[in] text_base pointer to UI text object + * @param[in] is_content_trusted true if context is trusted + * @return reference to string with formatted phone number + */ + bool processUrlMatch(LLUrlMatch* match, LLTextBase* text_base, bool is_content_trusted); class TextHelpers { diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index c058ad6f7d..7e4104c49b 100755 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -31,6 +31,7 @@ #include "lluri.h" #include "llurlmatch.h" #include "llurlregistry.h" +#include "lluriparser.h" #include "llavatarnamecache.h" #include "llcachename.h" @@ -38,6 +39,8 @@ #include "lluicolortable.h" #include "message.h" +#include "uriparser/Uri.h" + #define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" // Utility functions @@ -342,6 +345,30 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const } // +// LLUrlEntrySeconlifeURLs Describes *secondlife.com and *lindenlab.com urls to substitute icon 'hand.png' before link +// +LLUrlEntrySeconlifeURL::LLUrlEntrySeconlifeURL() +{ + mPattern = boost::regex("\\b(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?(/\\S*)?\\b", + boost::regex::perl|boost::regex::icase); + + mIcon = "Hand"; + mMenuName = "menu_url_http.xml"; +} + +std::string LLUrlEntrySeconlifeURL::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + LLUriParser up(url); + up.extractParts(); + return up.host(); +} + +std::string LLUrlEntrySeconlifeURL::getTooltip(const std::string &url) const +{ + return url; +} + +// // LLUrlEntryAgent Describes a Second Life agent Url, e.g., // secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about // x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index ffcd45dfde..1cb11cdb1c 100755 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -96,6 +96,8 @@ public: /// Should this link text be underlined only when mouse is hovered over it? virtual bool underlineOnHoverOnly(const std::string &string) const { return false; } + virtual bool isTrusted() const { return false; } + virtual LLUUID getID(const std::string &string) const { return LLUUID::null; } bool isLinkDisabled() const; @@ -168,6 +170,21 @@ public: }; /// +/// LLUrlEntrySeconlifeURLs Describes *secondlife.com and *lindenlab.com Urls +/// +class LLUrlEntrySeconlifeURL : public LLUrlEntryBase +{ +public: + LLUrlEntrySeconlifeURL(); + bool isTrusted() const { return true; } + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getTooltip(const std::string &url) const; + +private: + std::string mLabel; +}; + +/// /// LLUrlEntryAgent Describes a Second Life agent Url, e.g., /// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about class LLUrlEntryAgent : public LLUrlEntryBase diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp index c1f1382a9f..016d1ca92d 100755 --- a/indra/llui/llurlmatch.cpp +++ b/indra/llui/llurlmatch.cpp @@ -37,7 +37,8 @@ LLUrlMatch::LLUrlMatch() : mIcon(""), mMenuName(""), mLocation(""), - mUnderlineOnHoverOnly(false) + mUnderlineOnHoverOnly(false), + mTrusted(false) { } @@ -45,7 +46,7 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, const std::string &label, const std::string &tooltip, const std::string &icon, const LLStyle::Params& style, const std::string &menu, const std::string &location, - const LLUUID& id, bool underline_on_hover_only) + const LLUUID& id, bool underline_on_hover_only, bool trusted) { mStart = start; mEnd = end; @@ -59,4 +60,5 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, mLocation = location; mID = id; mUnderlineOnHoverOnly = underline_on_hover_only; + mTrusted = trusted; } diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h index 2818f45207..9f8960b32f 100755 --- a/indra/llui/llurlmatch.h +++ b/indra/llui/llurlmatch.h @@ -80,12 +80,15 @@ public: /// Should this link text be underlined only when mouse is hovered over it? bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; } + /// Return true if Url is trusted. + bool isTrusted() const { return mTrusted; } + /// Change the contents of this match object (used by LLUrlRegistry) void setValues(U32 start, U32 end, const std::string &url, const std::string &label, const std::string &tooltip, const std::string &icon, const LLStyle::Params& style, const std::string &menu, const std::string &location, const LLUUID& id, - bool underline_on_hover_only = false ); + bool underline_on_hover_only = false, bool trusted = false ); const LLUUID& getID() const { return mID; } private: @@ -100,6 +103,7 @@ private: LLUUID mID; LLStyle::Params mStyle; bool mUnderlineOnHoverOnly; + bool mTrusted; }; #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index ef0789e0e4..9e8d8d01f1 100755 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -27,6 +27,7 @@ #include "linden_common.h" #include "llurlregistry.h" +#include "lluriparser.h" #include <boost/regex.hpp> @@ -44,6 +45,10 @@ LLUrlRegistry::LLUrlRegistry() mUrlEntryIcon = new LLUrlEntryIcon(); registerUrl(mUrlEntryIcon); registerUrl(new LLUrlEntrySLURL()); + + // decorated links for host names like: secondlife.com and lindenlab.com + registerUrl(new LLUrlEntrySeconlifeURL()); + registerUrl(new LLUrlEntryHTTP()); mUrlEntryHTTPLabel = new LLUrlEntryHTTPLabel(); registerUrl(mUrlEntryHTTPLabel); @@ -203,6 +208,11 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL { // fill in the LLUrlMatch object and return it std::string url = text.substr(match_start, match_end - match_start + 1); + + LLUriParser up(url); + up.normalize(); + url = up.normalizedUri(); + match.setValues(match_start, match_end, match_entry->getUrl(url), match_entry->getLabel(url, cb), @@ -212,7 +222,8 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL match_entry->getMenuName(), match_entry->getLocation(url), match_entry->getID(url), - match_entry->underlineOnHoverOnly(url)); + match_entry->underlineOnHoverOnly(url), + match_entry->isTrusted()); return true; } diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 959dbc1040..1c9160a42d 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -133,6 +133,10 @@ attributedStringInfo getSegments(NSAttributedString *str) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:[self window]]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification + object:[self window]]; } - (void)setOldResize:(bool)oldresize @@ -159,6 +163,11 @@ attributedStringInfo getSegments(NSAttributedString *str) callWindowUnhide(); } +- (void)windowDidBecomeKey:(NSNotification *)notification; +{ + mModifiers = [NSEvent modifierFlags]; +} + - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index d3ac1612ad..8c5bc9777c 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -51,6 +51,7 @@ include(UnixInstall) include(ViewerMiscLibs) include(VisualLeakDetector) include(ZLIB) +include(URIPARSER) if (NOT HAVOK_TPV) # When using HAVOK_TPV, the library is precompiled, so no need for this @@ -1934,6 +1935,7 @@ endif (WINDOWS) target_link_libraries(${VIEWER_BINARY_NAME} ${PNG_PRELOAD_ARCHIVES} ${ZLIB_PRELOAD_ARCHIVES} + ${URIPARSER_PRELOAD_ARCHIVES} ${UPDATER_LIBRARIES} ${GOOGLE_PERFTOOLS_LIBRARIES} ${LLAUDIO_LIBRARIES} diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index c282746153..e5403775b2 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -3.7.25 +3.7.26 diff --git a/indra/newview/app_settings/keywords_lsl_default.xml b/indra/newview/app_settings/keywords_lsl_default.xml index 37dd2db93f..cea7a58949 100755 --- a/indra/newview/app_settings/keywords_lsl_default.xml +++ b/indra/newview/app_settings/keywords_lsl_default.xml @@ -10980,7 +10980,7 @@ </map> </array> <key>tooltip</key> - <string>Rez directly off of a UUID if owner has dog-bit set.</string> + <string>Rez directly off of a UUID if owner has god-bit set.</string> </map> <key>llGround</key> <map> diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 2047171e25..4ccb8f23cd 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -697,13 +697,13 @@ void LLFloaterPreference::onOpen(const LLSD& key) maturity_list->deleteItems(LLSD(SIM_ACCESS_ADULT)); } } - getChildView("maturity_desired_combobox")->setVisible( true); + getChildView("maturity_desired_combobox")->setEnabled( true); getChildView("maturity_desired_textbox")->setVisible( false); } else { getChild<LLUICtrl>("maturity_desired_textbox")->setValue(maturity_combo->getSelectedItemLabel()); - getChildView("maturity_desired_combobox")->setVisible( false); + getChildView("maturity_desired_combobox")->setEnabled( false); } // Forget previous language changes. @@ -2007,6 +2007,12 @@ void LLPanelPreference::cancel() { LLControlVariable* control = iter->first; LLSD ctrl_value = iter->second; + + if((control->getName() == "InstantMessageLogPath") && (ctrl_value.asString() == "")) + { + continue; + } + control->set(ctrl_value); } diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 971da74158..dbc643881e 100755 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -383,12 +383,20 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater) S32 w = gViewerWindow->getWindowWidthRaw(); LL_DEBUGS() << "Initializing width spinner (" << width_ctrl->getName() << "): " << w << LL_ENDL; width_ctrl->setValue(w); + if(getActiveSnapshotType(floater) == LLSnapshotLivePreview::SNAPSHOT_TEXTURE) + { + width_ctrl->setIncrement(w >> 1); + } } if (height_ctrl->getValue().asInteger() == 0) { S32 h = gViewerWindow->getWindowHeightRaw(); LL_DEBUGS() << "Initializing height spinner (" << height_ctrl->getName() << "): " << h << LL_ENDL; height_ctrl->setValue(h); + if(getActiveSnapshotType(floater) == LLSnapshotLivePreview::SNAPSHOT_TEXTURE) + { + height_ctrl->setIncrement(h >> 1); + } } // Clamp snapshot resolution to window size when showing UI or HUD in snapshot. @@ -823,6 +831,11 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, BOOL { getWidthSpinner(view)->setValue(width); getHeightSpinner(view)->setValue(height); + if (getActiveSnapshotType(view) == LLSnapshotLivePreview::SNAPSHOT_TEXTURE) + { + getWidthSpinner(view)->setIncrement(width >> 1); + getHeightSpinner(view)->setIncrement(height >> 1); + } } if(original_width != width || original_height != height) @@ -942,6 +955,11 @@ void LLFloaterSnapshot::Impl::setImageSizeSpinnersValues(LLFloaterSnapshot *view { getWidthSpinner(view)->forceSetValue(width); getHeightSpinner(view)->forceSetValue(height); + if (getActiveSnapshotType(view) == LLSnapshotLivePreview::SNAPSHOT_TEXTURE) + { + getWidthSpinner(view)->setIncrement(width >> 1); + getHeightSpinner(view)->setIncrement(height >> 1); + } } // static diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp index f3a48625a4..73120a0242 100755 --- a/indra/newview/llhudeffectlookat.cpp +++ b/indra/newview/llhudeffectlookat.cpp @@ -39,8 +39,6 @@ #include "llrendersphere.h" #include "llselectmgr.h" #include "llglheaders.h" - - #include "llxmltree.h" diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index ed833cba53..407613d32c 100755 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -85,7 +85,6 @@ const LLManip::EManipPart MANIPULATOR_IDS[LLManipScale::NUM_MANIPULATORS] = LLManip::LL_FACE_NEGZ }; - F32 get_default_max_prim_scale(bool is_flora) { // a bit of a hack, but if it's foilage, we don't want to use the @@ -290,10 +289,6 @@ void LLManipScale::render() LLGLEnable poly_offset(GL_POLYGON_OFFSET_FILL); glPolygonOffset( -2.f, -2.f); - // JC - Band-aid until edge stretch working similar to side stretch - // in non-uniform. - // renderEdges( bbox ); - renderCorners( bbox ); renderFaces( bbox ); @@ -350,6 +345,10 @@ BOOL LLManipScale::handleMouseDownOnPart( S32 x, S32 y, MASK mask ) updateSnapGuides(bbox); + mFirstClickX = x; + mFirstClickY = y; + mIsFirstClick = true; + mDragStartPointGlobal = gAgent.getPosGlobalFromAgent(box_corner_agent); mDragStartCenterGlobal = gAgent.getPosGlobalFromAgent(box_center_agent); LLVector3 far_corner_agent = bbox.localToAgent( unitVectorToLocalBBoxExtent( -1.f * partToUnitVector( mManipPart ), bbox ) ); @@ -413,7 +412,15 @@ BOOL LLManipScale::handleHover(S32 x, S32 y, MASK mask) } else { - drag( x, y ); + if((mFirstClickX != x) || (mFirstClickY != y)) + { + mIsFirstClick = false; + } + + if(!mIsFirstClick) + { + drag( x, y ); + } } LL_DEBUGS("UserInput") << "hover handled by LLManipScale (active)" << LL_ENDL; } @@ -679,63 +686,38 @@ void LLManipScale::renderFaces( const LLBBox& bbox ) { case 0: conditionalHighlight( LL_FACE_POSZ, &z_highlight_color, &z_normal_color ); - renderAxisHandle( LL_FACE_POSZ, ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], max.mV[VZ] ) ); + renderAxisHandle( 8, ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], max.mV[VZ] ) ); break; case 1: conditionalHighlight( LL_FACE_POSX, &x_highlight_color, &x_normal_color ); - renderAxisHandle( LL_FACE_POSX, ctr, LLVector3( max.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) ); + renderAxisHandle( 9, ctr, LLVector3( max.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) ); break; case 2: conditionalHighlight( LL_FACE_POSY, &y_highlight_color, &y_normal_color ); - renderAxisHandle( LL_FACE_POSY, ctr, LLVector3( ctr.mV[VX], max.mV[VY], ctr.mV[VZ] ) ); + renderAxisHandle( 10, ctr, LLVector3( ctr.mV[VX], max.mV[VY], ctr.mV[VZ] ) ); break; case 3: conditionalHighlight( LL_FACE_NEGX, &x_highlight_color, &x_normal_color ); - renderAxisHandle( LL_FACE_NEGX, ctr, LLVector3( min.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) ); + renderAxisHandle( 11, ctr, LLVector3( min.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) ); break; case 4: conditionalHighlight( LL_FACE_NEGY, &y_highlight_color, &y_normal_color ); - renderAxisHandle( LL_FACE_NEGY, ctr, LLVector3( ctr.mV[VX], min.mV[VY], ctr.mV[VZ] ) ); + renderAxisHandle( 12, ctr, LLVector3( ctr.mV[VX], min.mV[VY], ctr.mV[VZ] ) ); break; case 5: conditionalHighlight( LL_FACE_NEGZ, &z_highlight_color, &z_normal_color ); - renderAxisHandle( LL_FACE_NEGZ, ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], min.mV[VZ] ) ); + renderAxisHandle( 13, ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], min.mV[VZ] ) ); break; } } } } -void LLManipScale::renderEdges( const LLBBox& bbox ) -{ - LLVector3 extent = bbox.getExtentLocal(); - - for( U32 part = LL_EDGE_MIN; part <= LL_EDGE_MAX; part++ ) - { - F32 edge_width = mBoxHandleSize[part] * .6f; - LLVector3 direction = edgeToUnitVector( part ); - LLVector3 center_to_edge = unitVectorToLocalBBoxExtent( direction, bbox ); - - gGL.pushMatrix(); - { - gGL.translatef( center_to_edge.mV[0], center_to_edge.mV[1], center_to_edge.mV[2] ); - conditionalHighlight( part ); - gGL.scalef( - direction.mV[0] ? edge_width : extent.mV[VX], - direction.mV[1] ? edge_width : extent.mV[VY], - direction.mV[2] ? edge_width : extent.mV[VZ] ); - gBox.render(); - } - gGL.popMatrix(); - } -} - - void LLManipScale::renderCorners( const LLBBox& bbox ) { U32 part = LL_CORNER_NNN; @@ -778,14 +760,14 @@ void LLManipScale::renderBoxHandle( F32 x, F32 y, F32 z ) } -void LLManipScale::renderAxisHandle( U32 part, const LLVector3& start, const LLVector3& end ) +void LLManipScale::renderAxisHandle( U32 handle_index, const LLVector3& start, const LLVector3& end ) { if( getShowAxes() ) { // Draws a single "jacks" style handle: a long, retangular box from start to end. LLVector3 offset_start = end - start; offset_start.normalize(); - offset_start = start + mBoxHandleSize[part] * offset_start; + offset_start = start + mBoxHandleSize[handle_index] * offset_start; LLVector3 delta = end - offset_start; LLVector3 pos = offset_start + 0.5f * delta; @@ -794,9 +776,9 @@ void LLManipScale::renderAxisHandle( U32 part, const LLVector3& start, const LLV { gGL.translatef( pos.mV[VX], pos.mV[VY], pos.mV[VZ] ); gGL.scalef( - mBoxHandleSize[part] + llabs(delta.mV[VX]), - mBoxHandleSize[part] + llabs(delta.mV[VY]), - mBoxHandleSize[part] + llabs(delta.mV[VZ])); + mBoxHandleSize[handle_index] + llabs(delta.mV[VX]), + mBoxHandleSize[handle_index] + llabs(delta.mV[VY]), + mBoxHandleSize[handle_index] + llabs(delta.mV[VZ])); gBox.render(); } gGL.popMatrix(); diff --git a/indra/newview/llmanipscale.h b/indra/newview/llmanipscale.h index 7cc3c99810..11ade9b7d0 100755 --- a/indra/newview/llmanipscale.h +++ b/indra/newview/llmanipscale.h @@ -96,7 +96,6 @@ public: private: void renderCorners( const LLBBox& local_bbox ); void renderFaces( const LLBBox& local_bbox ); - void renderEdges( const LLBBox& local_bbox ); void renderBoxHandle( F32 x, F32 y, F32 z ); void renderAxisHandle( U32 part, const LLVector3& start, const LLVector3& end ); void renderGuidelinesPart( const LLBBox& local_bbox ); @@ -172,6 +171,9 @@ private: ESnapRegimes mSnapRegime; //<! Which, if any, snap regime the cursor is currently residing in. F32 mManipulatorScales[NUM_MANIPULATORS]; F32 mBoxHandleSize[NUM_MANIPULATORS]; // The size of the handles at the corners of the bounding box + S32 mFirstClickX; + S32 mFirstClickY; + bool mIsFirstClick; }; #endif // LL_MANIPSCALE_H diff --git a/indra/newview/llpanelgrouplandmoney.cpp b/indra/newview/llpanelgrouplandmoney.cpp index 7f82eecdb0..a2e136bd5a 100755 --- a/indra/newview/llpanelgrouplandmoney.cpp +++ b/indra/newview/llpanelgrouplandmoney.cpp @@ -421,20 +421,51 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) msg->getUUID("QueryData", "OwnerID", owner_id, 0); msg->getUUID("TransactionData", "TransactionID", trans_id); - S32 total_contribution = 0; if(owner_id.isNull()) { // special block which has total contribution ++first_block; + S32 committed = 0; + S32 billable_area = 0; + + if(count == 1) + { + msg->getS32("QueryData", "BillableArea", committed, 0); + } + else + { + for(S32 i = first_block; i < count; ++i) + { + msg->getS32("QueryData", "BillableArea", billable_area, i); + committed+=billable_area; + } + } + + S32 total_contribution; msg->getS32("QueryData", "ActualArea", total_contribution, 0); mPanel.getChild<LLUICtrl>("total_contributed_land_value")->setTextArg("[AREA]", llformat("%d", total_contribution)); + + mPanel.getChild<LLUICtrl>("total_land_in_use_value")->setTextArg("[AREA]", llformat("%d", committed)); + S32 available = total_contribution - committed; + mPanel.getChild<LLUICtrl>("land_available_value")->setTextArg("[AREA]", llformat("%d", available)); + + + if ( mGroupOverLimitTextp && mGroupOverLimitIconp ) + + { + mGroupOverLimitIconp->setVisible(available < 0); + mGroupOverLimitTextp->setVisible(available < 0); + } + } if ( trans_id != mTransID ) return; + // This power was removed to make group roles simpler //if ( !gAgent.hasPowerInGroup(mGroupID, GP_LAND_VIEW_OWNED) ) return; if (!gAgent.isInGroup(mPanel.mGroupID)) return; + mGroupParcelsp->setCommentText(mEmptyParcelsText); std::string name; @@ -447,7 +478,6 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) std::string sim_name; std::string land_sku; std::string land_type; - S32 committed = 0; for(S32 i = first_block; i < count; ++i) { @@ -477,7 +507,6 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) S32 region_y = ll_round(global_y) % REGION_WIDTH_UNITS; std::string location = sim_name + llformat(" (%d, %d)", region_x, region_y); std::string area; - committed+=billable_area; if(billable_area == actual_area) @@ -516,16 +545,6 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) mGroupParcelsp->addElement(row); } - - mPanel.getChild<LLUICtrl>("total_land_in_use_value")->setTextArg("[AREA]", llformat("%d", committed)); - - S32 available = total_contribution - committed; - mPanel.getChild<LLUICtrl>("land_available_value")->setTextArg("[AREA]", llformat("%d", available)); - if ( mGroupOverLimitTextp && mGroupOverLimitIconp ) - { - mGroupOverLimitIconp->setVisible(available < 0); - mGroupOverLimitTextp->setVisible(available < 0); - } } } diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 1495d720c7..89c898001f 100755 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -281,38 +281,12 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, loadLoginPage(); - // Show last logged in user favorites in "Start at" combo. - addUsersWithFavoritesToUsername(); LLComboBox* username_combo(getChild<LLComboBox>("username_combo")); username_combo->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this)); // STEAM-14: When user presses Enter with this field in focus, initiate login username_combo->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); } -void LLPanelLogin::addUsersWithFavoritesToUsername() -{ - LLComboBox* combo = getChild<LLComboBox>("username_combo"); - if (!combo) return; - 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"); - LLSD fav_llsd; - llifstream file; - file.open(filename); - if (!file.is_open()) - { - file.open(old_filename); - if (!file.is_open()) return; - } - LLSDSerialize::fromXML(fav_llsd, file); - for (LLSD::map_const_iterator iter = fav_llsd.beginMap(); - iter != fav_llsd.endMap(); ++iter) - { - combo->add(iter->first); - mUsernameLength = iter->first.length(); - updateLoginButtons(); - } -} - void LLPanelLogin::addFavoritesToStartLocation() { // Clear the combo. diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index ba23e7013d..dcd0aab3ab 100755 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -285,7 +285,8 @@ LLPanelObject::LLPanelObject() mIsPhantom(FALSE), mSelectedType(MI_BOX), mSculptTextureRevert(LLUUID::null), - mSculptTypeRevert(0) + mSculptTypeRevert(0), + mSizeChanged(FALSE) { } @@ -1620,9 +1621,10 @@ void LLPanelObject::sendScale(BOOL btn_down) LLVector3 newscale(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get()); LLVector3 delta = newscale - mObject->getScale(); - if (delta.magVec() >= 0.0005f) + if (delta.magVec() >= 0.0005f || (mSizeChanged && !btn_down)) { // scale changed by more than 1/2 millimeter + mSizeChanged = btn_down; // check to see if we aren't scaling the textures // (in which case the tex coord's need to be recomputed) diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index c4cf27ab1a..8829f493fa 100755 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -140,6 +140,7 @@ protected: LLSpinCtrl* mCtrlScaleX; LLSpinCtrl* mCtrlScaleY; LLSpinCtrl* mCtrlScaleZ; + BOOL mSizeChanged; LLTextBox* mLabelRotation; LLSpinCtrl* mCtrlRotX; diff --git a/indra/newview/llpanelsnapshot.cpp b/indra/newview/llpanelsnapshot.cpp index 56569e3207..106fb4997e 100755 --- a/indra/newview/llpanelsnapshot.cpp +++ b/indra/newview/llpanelsnapshot.cpp @@ -37,6 +37,19 @@ #include "llsidetraypanelcontainer.h" #include "llviewercontrol.h" // gSavedSettings +const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512 + +S32 power_of_two(S32 sz, S32 upper) +{ + S32 res = upper; + while( upper >= sz) + { + res = upper; + upper >>= 1; + } + return res; +} + // virtual BOOL LLPanelSnapshot::postBuild() { @@ -164,8 +177,26 @@ void LLPanelSnapshot::cancel() void LLPanelSnapshot::onCustomResolutionCommit() { LLSD info; - info["w"] = getChild<LLUICtrl>(getWidthSpinnerName())->getValue().asInteger(); - info["h"] = getChild<LLUICtrl>(getHeightSpinnerName())->getValue().asInteger(); + LLSpinCtrl *widthSpinner = getChild<LLSpinCtrl>(getWidthSpinnerName()); + LLSpinCtrl *heightSpinner = getChild<LLSpinCtrl>(getHeightSpinnerName()); + if (getName() == "panel_snapshot_inventory") + { + S32 width = widthSpinner->getValue().asInteger(); + width = power_of_two(width, MAX_TEXTURE_SIZE); + info["w"] = width; + widthSpinner->setIncrement(width >> 1); + widthSpinner->forceSetValue(width); + S32 height = heightSpinner->getValue().asInteger(); + height = power_of_two(height, MAX_TEXTURE_SIZE); + heightSpinner->setIncrement(height >> 1); + heightSpinner->forceSetValue(height); + info["h"] = height; + } + else + { + info["w"] = widthSpinner->getValue().asInteger(); + info["h"] = heightSpinner->getValue().asInteger(); + } LLFloaterSnapshot::getInstance()->notify(LLSD().with("custom-res-change", info)); } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index a1451d770a..c758bbcc9e 100755 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2703,7 +2703,7 @@ bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) { // FIXME: THIS IS SO WRONG. // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... - if( MASK_CONTROL & mask ) + if( MASK_CONTROL & mask && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END) { result = true; } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 3abeba4b43..be9b4439a8 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -3590,7 +3590,7 @@ class LLSelfSitDown : public view_listener_t bool enable_sitdown_self() { - return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying(); + return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); } class LLCheckPanelPeopleTab : public view_listener_t @@ -7021,10 +7021,6 @@ void handle_selected_texture_info(void*) std::string msg; msg.assign("Texture info for: "); msg.append(node->mName); - - LLSD args; - args["MESSAGE"] = msg; - LLNotificationsUtil::add("SystemMessage", args); U8 te_count = node->getObject()->getNumTEs(); // map from texture ID to list of faces using it @@ -7048,10 +7044,10 @@ void handle_selected_texture_info(void*) S32 height = img->getHeight(); S32 width = img->getWidth(); S32 components = img->getComponents(); - msg = llformat("%dx%d %s on face ", + msg.append(llformat("\n%dx%d %s on face ", width, height, - (components == 4 ? "alpha" : "opaque")); + (components == 4 ? "alpha" : "opaque"))); for (U8 i = 0; i < it->second.size(); ++i) { msg.append( llformat("%d ", (S32)(it->second[i]))); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 820249e181..74b8e693c4 100755 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5205,7 +5205,6 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow { if (!gAudiop) { - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; return; } diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index e85d8198aa..991f1c77a5 100755 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1562,6 +1562,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use if (parcel == parcel_mgr.mAgentParcel) { + // new agent parcel S32 bitmap_size = parcel_mgr.mParcelsPerEdge * parcel_mgr.mParcelsPerEdge / 8; @@ -1591,6 +1592,11 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use } } } + else if (local_id == parcel_mgr.mAgentParcel->getLocalID()) + { + // updated agent parcel + parcel_mgr.mAgentParcel->unpackMessage(msg); + } } // Handle updating selections, if necessary. diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index c0c9855903..c46b6789f6 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -66,6 +66,7 @@ #include "llviewerstatsrecorder.h" #include "llvlmanager.h" #include "llvlcomposition.h" +#include "llvoavatarself.h" #include "llvocache.h" #include "llworld.h" #include "llspatialpartition.h" @@ -1483,16 +1484,27 @@ void LLViewerRegion::killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& if(drawablep && !drawablep->getParent()) { - LLViewerObject::const_child_list_t& child_list = drawablep->getVObj()->getChildren(); + LLViewerObject* v_obj = drawablep->getVObj(); + if (v_obj->isSelected() + || (v_obj->flagAnimSource() && isAgentAvatarValid() && gAgentAvatarp->hasMotionFromSource(v_obj->getID()))) + { + // do not remove objects user is interacting with + ((LLViewerOctreeEntryData*)drawablep)->setVisible(); + return; + } + LLViewerObject::const_child_list_t& child_list = v_obj->getChildren(); for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); iter != child_list.end(); iter++) { LLViewerObject* child = *iter; if(child->mDrawable) { - if(!child->mDrawable->getEntry() || !child->mDrawable->getEntry()->hasVOCacheEntry()) + if( !child->mDrawable->getEntry() + || !child->mDrawable->getEntry()->hasVOCacheEntry() + || child->isSelected() + || (child->flagAnimSource() && isAgentAvatarValid() && gAgentAvatarp->hasMotionFromSource(child->getID()))) { - //do not remove parent if any of its children non-cacheable + //do not remove parent if any of its children non-cacheable, animating or selected //especially for the case that an avatar sits on a cache-able object ((LLViewerOctreeEntryData*)drawablep)->setVisible(); return; diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 1e225553b8..d01e746936 100755 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -385,7 +385,7 @@ public: private: void addToVOCacheTree(LLVOCacheEntry* entry); LLViewerObject* addNewObject(LLVOCacheEntry* entry); - void killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list); + void killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list); //adds entry into list if it is safe to move into cache void removeFromVOCacheTree(LLVOCacheEntry* entry); void killCacheEntry(LLVOCacheEntry* entry, bool for_rendering = false); //physically delete the cache entry void killInvisibleObjects(F32 max_time); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 6bfa522822..3f5b194c3d 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -4977,6 +4977,15 @@ BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate) } //----------------------------------------------------------------------------- +// hasMotionFromSource() +//----------------------------------------------------------------------------- +// virtual +bool LLVOAvatar::hasMotionFromSource(const LLUUID& source_id) +{ + return false; +} + +//----------------------------------------------------------------------------- // stopMotionFromSource() //----------------------------------------------------------------------------- // virtual diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 9a2aaf8aa3..2223acc893 100755 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -191,6 +191,7 @@ public: /*virtual*/ LLUUID remapMotionID(const LLUUID& id); /*virtual*/ BOOL startMotion(const LLUUID& id, F32 time_offset = 0.f); /*virtual*/ BOOL stopMotion(const LLUUID& id, BOOL stop_immediate = FALSE); + virtual bool hasMotionFromSource(const LLUUID& source_id); virtual void stopMotionFromSource(const LLUUID& source_id); virtual void requestStopMotion(LLMotion* motion); LLMotion* findMotion(const LLUUID& id) const; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 170a8c41f4..aa440c06a6 100755 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -754,6 +754,13 @@ void LLVOAvatarSelf::requestStopMotion(LLMotion* motion) } // virtual +bool LLVOAvatarSelf::hasMotionFromSource(const LLUUID& source_id) +{ + AnimSourceIterator motion_it = mAnimationSources.find(source_id); + return motion_it != mAnimationSources.end(); +} + +// virtual void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id) { for (AnimSourceIterator motion_it = mAnimationSources.find(source_id); motion_it != mAnimationSources.end(); ) @@ -762,6 +769,7 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id) mAnimationSources.erase(motion_it++); } + LLViewerObject* object = gObjectList.findObject(source_id); if (object) { diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 7f641b6242..444524d6cc 100755 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -82,6 +82,7 @@ public: // LLCharacter interface and related //-------------------------------------------------------------------- public: + /*virtual*/ bool hasMotionFromSource(const LLUUID& source_id); /*virtual*/ void stopMotionFromSource(const LLUUID& source_id); /*virtual*/ void requestStopMotion(LLMotion* motion); /*virtual*/ LLJoint* getJoint(const std::string &name); diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index 0312972a22..0f0d9ce703 100755 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -50,6 +50,8 @@ #include "llviewerwindow.h" #include "llnotificationsutil.h" +#include "uriparser/Uri.h" + #include <boost/regex.hpp> bool on_load_url_external_response(const LLSD& notification, const LLSD& response, bool async ); @@ -238,9 +240,23 @@ bool LLWeb::useExternalBrowser(const std::string &url) } else if (gSavedSettings.getU32("PreferredBrowserBehavior") == BROWSER_INT_LL_EXT_OTHERS) { - boost::regex pattern = boost::regex("\\b(lindenlab.com|secondlife.com)\\b", boost::regex::perl|boost::regex::icase); + UriParserStateA state; + UriUriA uri; + state.uri = &uri; + + std::string uri_string = url; + uriParseUriA(&state, uri_string.c_str()); + if (uri.hostText.first) + { + S32 length = uri.hostText.afterLast - uri.hostText.first; + std::string buf = uri.hostText.first; + uri_string = buf.substr(0,length); + } + uriFreeUriMembersA(&uri); + + boost::regex pattern = boost::regex("\\b(lindenlab.com|secondlife.com)$", boost::regex::perl|boost::regex::icase); boost::match_results<std::string::const_iterator> matches; - return !(boost::regex_search(url, matches, pattern)); + return !(boost::regex_search(uri_string, matches, pattern)); } return false; } diff --git a/indra/newview/skins/default/textures/icons/hand.png b/indra/newview/skins/default/textures/icons/hand.png Binary files differnew file mode 100644 index 0000000000..41b9600da6 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/hand.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 1f10d966d5..9c2d55e7b4 100755 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -229,6 +229,8 @@ with the same filename but different name <texture name="Generic_Person" file_name="icons/Generic_Person.png" preload="false" /> <texture name="Generic_Person_Large" file_name="icons/Generic_Person_Large.png" preload="false" /> + <texture name="Hand" file_name="icons/hand.png" preload="false" /> + <texture name="Help_Press" file_name="navbar/Help_Press.png" preload="false" /> <texture name="Hierarchy_View_Disabled" file_name="icons/Hierarchy_View_Disabled.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/de/floater_stats.xml b/indra/newview/skins/default/xui/de/floater_stats.xml index 993316134a..4e6f56cd94 100755 --- a/indra/newview/skins/default/xui/de/floater_stats.xml +++ b/indra/newview/skins/default/xui/de/floater_stats.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="Statistics" title="STATISTIKEN" width="280"> - <scroll_container name="statistics_scroll" width="280"> - <container_view name="statistics_view" width="280"> +<floater name="Statistics" title="STATISTIKEN"> + <scroll_container name="statistics_scroll"> + <container_view name="statistics_view"> <stat_view label="Basic" name="basic"> <stat_bar label="FPS" name="fps"/> <stat_bar label="Empfangene UDP-Daten" name="bandwidth"/> diff --git a/indra/newview/skins/default/xui/en/floater_stats.xml b/indra/newview/skins/default/xui/en/floater_stats.xml index fbf262441f..2aa582beea 100755 --- a/indra/newview/skins/default/xui/en/floater_stats.xml +++ b/indra/newview/skins/default/xui/en/floater_stats.xml @@ -37,6 +37,7 @@ <stat_bar name="bandwidth" label="UDP Data Received" stat="activemessagedatareceived" + decimal_digits="0" show_bar="true"/> <stat_bar name="packet_loss" label="Packet Loss" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index ea1bc66236..b4d8046d18 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -34,6 +34,12 @@ </form> </template> + <template name="notifyignore"> + <form> + <ignore text="$ignoretext"/> + </form> + </template> + <template name="okcancelbuttons"> <form> <button @@ -9490,6 +9496,9 @@ You have been teleported home by the object '[OBJECT_NAME]' type="notify"> <tag>fail</tag> You have been teleported by an attachment on [ITEM_ID] + <usetemplate + ignoretext="Teleport: You have been teleported by an attachment" + name="notifyignore"/> </notification> <notification @@ -9498,6 +9507,9 @@ You have been teleported by an attachment on [ITEM_ID] type="notify"> <tag>fail</tag> You have been teleported by the object '[OBJECT_NAME]' on the parcel '[PARCEL_NAME]' + <usetemplate + ignoretext="Teleport: You have been teleported by an object on a parcel" + name="notifyignore"/> </notification> <notification diff --git a/indra/newview/skins/default/xui/en/panel_preferences_general.xml b/indra/newview/skins/default/xui/en/panel_preferences_general.xml index 9da044ab64..f6665a1d5d 100755 --- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml @@ -39,12 +39,7 @@ enabled="true" label="English" name="English" - value="en" /> - <combo_box.item - enabled="true" - label="Dansk (Danish) - Beta" - name="Danish" - value="da" /> + value="en" /> <combo_box.item enabled="true" label="Deutsch (German) - Beta" @@ -64,12 +59,7 @@ enabled="true" label="Italiano (Italian) - Beta" name="Italian" - value="it" /> - <combo_box.item - enabled="true" - label="Polski (Polish) - Beta" - name="Polish" - value="pl" /> + value="it" /> <combo_box.item enabled="true" label="Português (Portuguese) - Beta" 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 b71586aab1..615abbaa89 100755 --- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml @@ -398,7 +398,7 @@ follows="left|top" layout="topleft" left_delta="-168" - width="221" + width="360" height="20" name="ear_location"> <radio_item diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml index 064ece6e4b..dbf7bc031f 100755 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -51,7 +51,7 @@ v_pad="4" top="0" wrap="false" - value="L$20" + value="L$??" width="40" /> <button halign="center" diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml index fad1ea51e0..26e3d37918 100755 --- a/indra/newview/skins/default/xui/ru/menu_viewer.xml +++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml @@ -165,6 +165,12 @@ </menu> <menu label="Справка" name="Help"> <menu_item_call label="Инструкции..." name="How To"/> + <menu_item_call label="База знаний" name="Knowledge Base"/> + <menu_item_call label="Wiki" name="Wiki"/> + <menu_item_call label="Форумы сообщества" name="Community Forums"/> + <menu_item_call label="Портал поддержки" name="Support portal"/> + <menu_item_call label="Новости [SECOND_LIFE]" name="Second Life News"/> + <menu_item_call label="Блоги [SECOND_LIFE]" name="Second Life Blogs"/> <menu_item_call label="Жалоба" name="Report Abuse"/> <menu_item_call label="Сообщить об ошибке" name="Report Bug"/> <menu_item_call label="О [APP_NAME]" name="About Second Life"/> @@ -396,6 +402,12 @@ <menu_item_call label="Проверка женщины" name="Test Female"/> <menu_item_check label="Разрешить выбор аватара" name="Allow Select Avatar"/> </menu> + <menu label="Скорость анимации" name="Animation Speed"> + <menu_item_call label="Ускорить все анимации на 10%" name="All Animations 10 Faster"/> + <menu_item_call label="Замедлить все анимации на 10%" name="All Animations 10 Slower"/> + <menu_item_call label="Восстановить скорость анимаций" name="Reset All Animation Speed"/> + <menu_item_check label="Анимация медленных движений" name="Slow Motion Animations"/> + </menu> <menu_item_call label="Скинуть параметры" name="Force Params to Default"/> <menu_item_check label="Данные об анимации" name="Animation Info"/> <menu_item_check label="Показать взгляд" name="Show Look At"/> |