diff options
238 files changed, 10313 insertions, 3313 deletions
diff --git a/etc/message.xml b/etc/message.xml index 7ad392d0b5..da08e12aa1 100644 --- a/etc/message.xml +++ b/etc/message.xml @@ -671,7 +671,14 @@ <key>UploadBakedTexture</key> <boolean>true</boolean> - </map> + + <key>ObjectMedia</key> + <boolean>false</boolean> + + <key>ObjectMediaNavigate</key> + <boolean>false</boolean> + + </map> <key>messageBans</key> <map> diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp index 4b0bf6a2d9..d5fee2828e 100644 --- a/indra/linux_updater/linux_updater.cpp +++ b/indra/linux_updater/linux_updater.cpp @@ -78,9 +78,9 @@ static std::set<std::string> default_trans_args; void init_default_trans_args() { default_trans_args.insert("SECOND_LIFE"); // World - default_trans_args.insert("SECOND_LIFE_VIEWER"); + default_trans_args.insert("APP_NAME"); default_trans_args.insert("SECOND_LIFE_GRID"); - default_trans_args.insert("SECOND_LIFE_SUPPORT"); + default_trans_args.insert("SUPPORT_SITE"); } bool translate_init(std::string comma_delim_path_list, diff --git a/indra/llcommon/lllslconstants.h b/indra/llcommon/lllslconstants.h index a626e3f085..78f4435ed7 100644 --- a/indra/llcommon/lllslconstants.h +++ b/indra/llcommon/lllslconstants.h @@ -202,5 +202,18 @@ const U32 CHANGED_OWNER = 0x80; const U32 CHANGED_REGION = 0x100; const U32 CHANGED_TELEPORT = 0x200; const U32 CHANGED_REGION_START = 0x400; +const U32 CHANGED_MEDIA = 0x800; + +// Possible error results +const U32 LSL_STATUS_OK = 0; +const U32 LSL_STATUS_MALFORMED_PARAMS = 1000; +const U32 LSL_STATUS_TYPE_MISMATCH = 1001; +const U32 LSL_STATUS_BOUNDS_ERROR = 1002; +const U32 LSL_STATUS_NOT_FOUND = 1003; +const U32 LSL_STATUS_NOT_SUPPORTED = 1004; +const U32 LSL_STATUS_INTERNAL_ERROR = 1999; + +// Start per-function errors below, starting at 2000: +const U32 LSL_STATUS_WHITELIST_FAILED = 2001; #endif diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 54f153d182..7299ede22d 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -99,6 +99,8 @@ void LLPluginClassMedia::reset() mSetMediaHeight = -1; mRequestedMediaWidth = 0; mRequestedMediaHeight = 0; + mFullMediaWidth = 0; + mFullMediaHeight = 0; mTextureWidth = 0; mTextureHeight = 0; mMediaWidth = 0; @@ -266,8 +268,16 @@ unsigned char* LLPluginClassMedia::getBitsData() void LLPluginClassMedia::setSize(int width, int height) { - mSetMediaWidth = width; - mSetMediaHeight = height; + if((width > 0) && (height > 0)) + { + mSetMediaWidth = width; + mSetMediaHeight = height; + } + else + { + mSetMediaWidth = -1; + mSetMediaHeight = -1; + } setSizeInternal(); } @@ -279,16 +289,26 @@ void LLPluginClassMedia::setSizeInternal(void) mRequestedMediaWidth = mSetMediaWidth; mRequestedMediaHeight = mSetMediaHeight; } + else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0)) + { + mRequestedMediaWidth = mNaturalMediaWidth; + mRequestedMediaHeight = mNaturalMediaHeight; + } else { mRequestedMediaWidth = mDefaultMediaWidth; mRequestedMediaHeight = mDefaultMediaHeight; } + // Save these for size/interest calculations + mFullMediaWidth = mRequestedMediaWidth; + mFullMediaHeight = mRequestedMediaHeight; + if(mAllowDownsample) { switch(mPriority) { + case PRIORITY_SLIDESHOW: case PRIORITY_LOW: // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) @@ -309,6 +329,12 @@ void LLPluginClassMedia::setSizeInternal(void) mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); } + + if(mRequestedMediaWidth > 2048) + mRequestedMediaWidth = 2048; + + if(mRequestedMediaHeight > 2048) + mRequestedMediaHeight = 2048; } void LLPluginClassMedia::setAutoScale(bool auto_scale) @@ -519,6 +545,10 @@ void LLPluginClassMedia::setPriority(EPriority priority) std::string priority_string; switch(priority) { + case PRIORITY_UNLOADED: + priority_string = "unloaded"; + mSleepTime = 1.0f; + break; case PRIORITY_STOPPED: priority_string = "stopped"; mSleepTime = 1.0f; @@ -527,6 +557,10 @@ void LLPluginClassMedia::setPriority(EPriority priority) priority_string = "hidden"; mSleepTime = 1.0f; break; + case PRIORITY_SLIDESHOW: + priority_string = "slideshow"; + mSleepTime = 1.0f; + break; case PRIORITY_LOW: priority_string = "low"; mSleepTime = 1.0f / 50.0f; @@ -550,6 +584,8 @@ void LLPluginClassMedia::setPriority(EPriority priority) mPlugin->setSleepTime(mSleepTime); } + LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; + // This may affect the calculated size, so recalculate it here. setSizeInternal(); } @@ -557,15 +593,27 @@ void LLPluginClassMedia::setPriority(EPriority priority) void LLPluginClassMedia::setLowPrioritySizeLimit(int size) { - if(mLowPrioritySizeLimit != size) + int power = nextPowerOf2(size); + if(mLowPrioritySizeLimit != power) { - mLowPrioritySizeLimit = size; + mLowPrioritySizeLimit = power; // This may affect the calculated size, so recalculate it here. setSizeInternal(); } } +F64 LLPluginClassMedia::getCPUUsage() +{ + F64 result = 0.0f; + + if(mPlugin) + { + result = mPlugin->getCPUUsage(); + } + + return result; +} void LLPluginClassMedia::cut() { @@ -722,7 +770,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mNaturalMediaWidth = width; mNaturalMediaHeight = height; - setSize(width, height); + setSizeInternal(); } else if(message_name == "size_change_response") { diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 665a423d07..331ca5f6dc 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -66,6 +66,8 @@ public: int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; }; int getTextureWidth() const; int getTextureHeight() const; + int getFullWidth() const { return mFullMediaWidth; }; + int getFullHeight() const { return mFullMediaHeight; }; // This may return NULL. Callers need to check for and handle this case. unsigned char* getBitsData(); @@ -138,9 +140,11 @@ public: typedef enum { + PRIORITY_UNLOADED, // media plugin isn't even loaded. PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. - PRIORITY_LOW, // media is in the far distance, may be rendered at reduced size + PRIORITY_SLIDESHOW, // media is in the far distance, updates very infrequently + PRIORITY_LOW, // media is in the distance, may be rendered at reduced size PRIORITY_NORMAL, // normal (default) priority PRIORITY_HIGH // media has user focus and/or is taking up most of the screen }EPriority; @@ -148,6 +152,8 @@ public: void setPriority(EPriority priority); void setLowPrioritySizeLimit(int size); + F64 getCPUUsage(); + // Valid after a MEDIA_EVENT_CURSOR_CHANGED event std::string getCursorName() const { return mCursorName; }; @@ -230,6 +236,7 @@ public: void initializeUrlHistory(const LLSD& url_history); protected: + LLPluginClassMediaOwner *mOwner; // Notify this object's owner that an event has occurred. @@ -266,7 +273,11 @@ protected: int mSetMediaWidth; int mSetMediaHeight; - // Actual media size being set (may be affected by auto-scale) + // Full calculated media size (before auto-scale and downsample calculations) + int mFullMediaWidth; + int mFullMediaHeight; + + // Actual media size being set (after auto-scale) int mRequestedMediaWidth; int mRequestedMediaHeight; diff --git a/indra/llplugin/llpluginmessage.cpp b/indra/llplugin/llpluginmessage.cpp index bfabc5b7ca..e7412a1d8f 100644 --- a/indra/llplugin/llpluginmessage.cpp +++ b/indra/llplugin/llpluginmessage.cpp @@ -33,6 +33,7 @@ #include "llpluginmessage.h" #include "llsdserialize.h" +#include "u64.h" LLPluginMessage::LLPluginMessage() { @@ -93,6 +94,14 @@ void LLPluginMessage::setValueReal(const std::string &key, F64 value) mMessage["params"][key] = value; } +void LLPluginMessage::setValuePointer(const std::string &key, void* value) +{ + std::stringstream temp; + // iostreams should output pointer values in hex with an initial 0x by default. + temp << value; + setValue(key, temp.str()); +} + std::string LLPluginMessage::getClass(void) const { return mMessage["class"]; @@ -189,6 +198,20 @@ F64 LLPluginMessage::getValueReal(const std::string &key) const return result; } +void* LLPluginMessage::getValuePointer(const std::string &key) const +{ + void* result = NULL; + + if(mMessage["params"].has(key)) + { + std::string value = mMessage["params"][key].asString(); + + result = (void*)llstrtou64(value.c_str(), NULL, 16); + } + + return result; +} + std::string LLPluginMessage::generate(void) const { std::ostringstream result; diff --git a/indra/llplugin/llpluginmessage.h b/indra/llplugin/llpluginmessage.h index a17ec4bb98..f1a0e7c624 100644 --- a/indra/llplugin/llpluginmessage.h +++ b/indra/llplugin/llpluginmessage.h @@ -57,6 +57,7 @@ public: void setValueU32(const std::string &key, U32 value); void setValueBoolean(const std::string &key, bool value); void setValueReal(const std::string &key, F64 value); + void setValuePointer(const std::string &key, void *value); std::string getClass(void) const; std::string getName(void) const; @@ -82,6 +83,9 @@ public: // get the value of a key as a float. F64 getValueReal(const std::string &key) const; + // get the value of a key as a pointer. + void* getValuePointer(const std::string &key) const; + // Flatten the message into a string std::string generate(void) const; diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index dc51671032..450dcb3c78 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -43,6 +43,7 @@ LLPluginProcessChild::LLPluginProcessChild() mInstance = NULL; mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); mSleepTime = 1.0f / 100.0f; // default: send idle messages at 100Hz + mCPUElapsed = 0.0f; } LLPluginProcessChild::~LLPluginProcessChild() @@ -130,6 +131,7 @@ void LLPluginProcessChild::idle(void) { mHeartbeat.start(); mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); + mCPUElapsed = 0.0f; setState(STATE_PLUGIN_LOADED); } else @@ -158,10 +160,22 @@ void LLPluginProcessChild::idle(void) mInstance->idle(); - if(mHeartbeat.checkExpirationAndReset(HEARTBEAT_SECONDS)) + if(mHeartbeat.hasExpired()) { + // This just proves that we're not stuck down inside the plugin code. - sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat")); + LLPluginMessage heartbeat(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat"); + + // Calculate the approximage CPU usage fraction (floating point value between 0 and 1) used by the plugin this heartbeat cycle. + // Note that this will not take into account any threads or additional processes the plugin spawns, but it's a first approximation. + // If we could write OS-specific functions to query the actual CPU usage of this process, that would be a better approximation. + heartbeat.setValueReal("cpu_usage", mCPUElapsed / mHeartbeat.getElapsedTimeF64()); + + sendMessageToParent(heartbeat); + + mHeartbeat.reset(); + mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); + mCPUElapsed = 0.0f; } } // receivePluginMessage will transition to STATE_UNLOADING @@ -253,8 +267,11 @@ void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) std::string buffer = message.generate(); LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL; - + LLTimer elapsed; + mInstance->sendMessage(buffer); + + mCPUElapsed += elapsed.getElapsedTimeF64(); } void LLPluginProcessChild::sendMessageToParent(const LLPluginMessage &message) @@ -317,12 +334,7 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message) LLPluginMessage message("base", "shm_added"); message.setValue("name", name); message.setValueS32("size", (S32)size); - // shm address is split into 2x32bit values because LLSD doesn't serialize 64bit values and we need to support 64-bit addressing. - void * address = region->getMappedAddress(); - U32 address_lo = (U32)(U64(address) & 0xFFFFFFFF); // Extract the lower 32 bits - U32 address_hi = (U32)((U64(address)>>32) & 0xFFFFFFFF); // Extract the higher 32 bits - message.setValueU32("address", address_lo); - message.setValueU32("address_1", address_hi); + message.setValuePointer("address", region->getMappedAddress()); sendMessageToPlugin(message); // and send the response to the parent @@ -380,7 +392,11 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message) if(passMessage && mInstance != NULL) { + LLTimer elapsed; + mInstance->sendMessage(message); + + mCPUElapsed += elapsed.getElapsedTimeF64(); } } @@ -454,6 +470,7 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message) if(passMessage) { + LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL; writeMessageRaw(message); } } diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h index f92905e8bd..75860bdf0a 100644 --- a/indra/llplugin/llpluginprocesschild.h +++ b/indra/llplugin/llpluginprocesschild.h @@ -102,6 +102,7 @@ private: LLTimer mHeartbeat; F64 mSleepTime; + F64 mCPUElapsed; }; diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index f18a117dde..41784a713c 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -38,7 +38,7 @@ #include "llapr.h" // If we don't receive a heartbeat in this many seconds, we declare the plugin locked up. -static const F32 PLUGIN_LOCKED_UP_SECONDS = 10.0f; +static const F32 PLUGIN_LOCKED_UP_SECONDS = 15.0f; // Somewhat longer timeout for initial launch. static const F32 PLUGIN_LAUNCH_SECONDS = 20.0f; @@ -87,6 +87,7 @@ void LLPluginProcessParent::init(const std::string &launcher_filename, const std { mProcess.setExecutable(launcher_filename); mPluginFile = plugin_filename; + mCPUUsage = 0.0f; setState(STATE_INITIALIZED); } @@ -503,6 +504,11 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) { // this resets our timer. mHeartbeat.setTimerExpirySec(PLUGIN_LOCKED_UP_SECONDS); + + mCPUUsage = message.getValueReal("cpu_usage"); + + LL_DEBUGS("Plugin") << "cpu usage reported as " << mCPUUsage << LL_ENDL; + } else if(message_name == "shm_add_response") { diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index 545eb85c9a..0d0b047c88 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -96,6 +96,8 @@ public: bool getDisableTimeout() { return mDisableTimeout; }; void setDisableTimeout(bool disable) { mDisableTimeout = disable; }; + F64 getCPUUsage() { return mCPUUsage; }; + private: enum EState @@ -140,6 +142,7 @@ private: LLTimer mHeartbeat; F64 mSleepTime; + F64 mCPUUsage; bool mDisableTimeout; }; diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index 478dd398ff..d130513637 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -17,6 +17,7 @@ include_directories( set(llprimitive_SOURCE_FILES llmaterialtable.cpp + llmediaentry.cpp llprimitive.cpp llprimtexturelist.cpp lltextureanim.cpp @@ -31,6 +32,7 @@ set(llprimitive_HEADER_FILES legacy_object_types.h llmaterialtable.h + llmediaentry.h llprimitive.h llprimtexturelist.h lltextureanim.h @@ -49,3 +51,10 @@ set_source_files_properties(${llprimitive_HEADER_FILES} list(APPEND llprimitive_SOURCE_FILES ${llprimitive_HEADER_FILES}) add_library (llprimitive ${llprimitive_SOURCE_FILES}) + +#add unit tests +INCLUDE(LLAddBuildTest) +SET(llprimitive_TEST_SOURCE_FILES + llmediaentry.cpp + ) +LL_ADD_PROJECT_UNIT_TESTS(llprimitive "${llprimitive_TEST_SOURCE_FILES}") diff --git a/indra/llprimitive/llmediaentry.cpp b/indra/llprimitive/llmediaentry.cpp new file mode 100644 index 0000000000..fa04bf80e7 --- /dev/null +++ b/indra/llprimitive/llmediaentry.cpp @@ -0,0 +1,597 @@ +/** + * @file llmediaentry.cpp + * @brief This is a single instance of media data related to the face of a prim + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llmediaentry.h" +#include "lllslconstants.h" + +#include <boost/regex.hpp> + +// LLSD key defines +// DO NOT REORDER OR REMOVE THESE! + +// Some LLSD keys. Do not change! +#define MEDIA_ALT_IMAGE_ENABLE_KEY_STR "alt_image_enable" +#define MEDIA_CONTROLS_KEY_STR "controls" +#define MEDIA_CURRENT_URL_KEY_STR "current_url" +#define MEDIA_HOME_URL_KEY_STR "home_url" +#define MEDIA_AUTO_LOOP_KEY_STR "auto_loop" +#define MEDIA_AUTO_PLAY_KEY_STR "auto_play" +#define MEDIA_AUTO_SCALE_KEY_STR "auto_scale" +#define MEDIA_AUTO_ZOOM_KEY_STR "auto_zoom" +#define MEDIA_FIRST_CLICK_INTERACT_KEY_STR "first_click_interact" +#define MEDIA_WIDTH_PIXELS_KEY_STR "width_pixels" +#define MEDIA_HEIGHT_PIXELS_KEY_STR "height_pixels" + +// "security" fields +#define MEDIA_WHITELIST_ENABLE_KEY_STR "whitelist_enable" +#define MEDIA_WHITELIST_KEY_STR "whitelist" + +// "permissions" fields +#define MEDIA_PERMS_INTERACT_KEY_STR "perms_interact" +#define MEDIA_PERMS_CONTROL_KEY_STR "perms_control" + +// "general" fields +const char* LLMediaEntry::ALT_IMAGE_ENABLE_KEY = MEDIA_ALT_IMAGE_ENABLE_KEY_STR; +const char* LLMediaEntry::CONTROLS_KEY = MEDIA_CONTROLS_KEY_STR; +const char* LLMediaEntry::CURRENT_URL_KEY = MEDIA_CURRENT_URL_KEY_STR; +const char* LLMediaEntry::HOME_URL_KEY = MEDIA_HOME_URL_KEY_STR; +const char* LLMediaEntry::AUTO_LOOP_KEY = MEDIA_AUTO_LOOP_KEY_STR; +const char* LLMediaEntry::AUTO_PLAY_KEY = MEDIA_AUTO_PLAY_KEY_STR; +const char* LLMediaEntry::AUTO_SCALE_KEY = MEDIA_AUTO_SCALE_KEY_STR; +const char* LLMediaEntry::AUTO_ZOOM_KEY = MEDIA_AUTO_ZOOM_KEY_STR; +const char* LLMediaEntry::FIRST_CLICK_INTERACT_KEY = MEDIA_FIRST_CLICK_INTERACT_KEY_STR; +const char* LLMediaEntry::WIDTH_PIXELS_KEY = MEDIA_WIDTH_PIXELS_KEY_STR; +const char* LLMediaEntry::HEIGHT_PIXELS_KEY = MEDIA_HEIGHT_PIXELS_KEY_STR; + +// "security" fields +const char* LLMediaEntry::WHITELIST_ENABLE_KEY = MEDIA_WHITELIST_ENABLE_KEY_STR; +const char* LLMediaEntry::WHITELIST_KEY = MEDIA_WHITELIST_KEY_STR; + +// "permissions" fields +const char* LLMediaEntry::PERMS_INTERACT_KEY = MEDIA_PERMS_INTERACT_KEY_STR; +const char* LLMediaEntry::PERMS_CONTROL_KEY = MEDIA_PERMS_CONTROL_KEY_STR; + +#define DEFAULT_URL_PREFIX "http://" + +// Constructor(s) +LLMediaEntry::LLMediaEntry() : + mAltImageEnable(false), + mControls(STANDARD), + mCurrentURL(""), + mHomeURL(""), + mAutoLoop(false), + mAutoPlay(false), + mAutoScale(false), + mAutoZoom(false), + mFirstClickInteract(false), + mWidthPixels(0), + mHeightPixels(0), + mWhiteListEnable(false), + // mWhiteList + mPermsInteract(PERM_ALL), + mPermsControl(PERM_ALL), + mMediaIDp(NULL) +{ +} + +LLMediaEntry::LLMediaEntry(const LLMediaEntry &rhs) : + mMediaIDp(NULL) +{ + // "general" fields + mAltImageEnable = rhs.mAltImageEnable; + mControls = rhs.mControls; + mCurrentURL = rhs.mCurrentURL; + mHomeURL = rhs.mHomeURL; + mAutoLoop = rhs.mAutoLoop; + mAutoPlay = rhs.mAutoPlay; + mAutoScale = rhs.mAutoScale; + mAutoZoom = rhs.mAutoZoom; + mFirstClickInteract = rhs.mFirstClickInteract; + mWidthPixels = rhs.mWidthPixels; + mHeightPixels = rhs.mHeightPixels; + + // "security" fields + mWhiteListEnable = rhs.mWhiteListEnable; + mWhiteList = rhs.mWhiteList; + + // "permissions" fields + mPermsInteract = rhs.mPermsInteract; + mPermsControl = rhs.mPermsControl; +} + +LLMediaEntry::~LLMediaEntry() +{ + if (NULL != mMediaIDp) + { + delete mMediaIDp; + } +} + +LLSD LLMediaEntry::asLLSD() const +{ + LLSD sd; + asLLSD(sd); + return sd; +} + +// +// LLSD functions +// +void LLMediaEntry::asLLSD(LLSD& sd) const +{ + // "general" fields + sd[ALT_IMAGE_ENABLE_KEY] = mAltImageEnable; + sd[CONTROLS_KEY] = (LLSD::Integer)mControls; + sd[CURRENT_URL_KEY] = mCurrentURL; + sd[HOME_URL_KEY] = mHomeURL; + sd[AUTO_LOOP_KEY] = mAutoLoop; + sd[AUTO_PLAY_KEY] = mAutoPlay; + sd[AUTO_SCALE_KEY] = mAutoScale; + sd[AUTO_ZOOM_KEY] = mAutoZoom; + sd[FIRST_CLICK_INTERACT_KEY] = mFirstClickInteract; + sd[WIDTH_PIXELS_KEY] = mWidthPixels; + sd[HEIGHT_PIXELS_KEY] = mHeightPixels; + + // "security" fields + sd[WHITELIST_ENABLE_KEY] = mWhiteListEnable; + for (U32 i=0; i<mWhiteList.size(); i++) + { + sd[WHITELIST_KEY].append(mWhiteList[i]); + } + + // "permissions" fields + sd[PERMS_INTERACT_KEY] = mPermsInteract; + sd[PERMS_CONTROL_KEY] = mPermsControl; +} + +// static +bool LLMediaEntry::checkLLSD(const LLSD& sd) +{ + if (sd.isUndefined()) return true; + LLMediaEntry temp; + return temp.fromLLSDInternal(sd, true); +} + +void LLMediaEntry::fromLLSD(const LLSD& sd) +{ + (void)fromLLSDInternal(sd, true); +} + +void LLMediaEntry::mergeFromLLSD(const LLSD& sd) +{ + (void)fromLLSDInternal(sd, false); +} + +// *NOTE: returns true if NO failures to set occurred, false otherwise. +// However, be aware that if a failure to set does occur, it does +// not stop setting fields from the LLSD! +bool LLMediaEntry::fromLLSDInternal(const LLSD& sd, bool overwrite) +{ + // *HACK: we sort of cheat here and assume that status is a + // bit field. We "or" into status and instead of returning + // it, we return whether it finishes off as LSL_STATUS_OK or not. + U32 status = LSL_STATUS_OK; + + // "general" fields + if ( overwrite || sd.has(ALT_IMAGE_ENABLE_KEY) ) + { + status |= setAltImageEnable( sd[ALT_IMAGE_ENABLE_KEY] ); + } + if ( overwrite || sd.has(CONTROLS_KEY) ) + { + status |= setControls( (MediaControls)(LLSD::Integer)sd[CONTROLS_KEY] ); + } + if ( overwrite || sd.has(CURRENT_URL_KEY) ) + { + // Don't check whitelist + status |= setCurrentURLInternal( sd[CURRENT_URL_KEY], false ); + } + if ( overwrite || sd.has(HOME_URL_KEY) ) + { + status |= setHomeURL( sd[HOME_URL_KEY] ); + } + if ( overwrite || sd.has(AUTO_LOOP_KEY) ) + { + status |= setAutoLoop( sd[AUTO_LOOP_KEY] ); + } + if ( overwrite || sd.has(AUTO_PLAY_KEY) ) + { + status |= setAutoPlay( sd[AUTO_PLAY_KEY] ); + } + if ( overwrite || sd.has(AUTO_SCALE_KEY) ) + { + status |= setAutoScale( sd[AUTO_SCALE_KEY] ); + } + if ( overwrite || sd.has(AUTO_ZOOM_KEY) ) + { + status |= setAutoZoom( sd[AUTO_ZOOM_KEY] ); + } + if ( overwrite || sd.has(FIRST_CLICK_INTERACT_KEY) ) + { + status |= setFirstClickInteract( sd[FIRST_CLICK_INTERACT_KEY] ); + } + if ( overwrite || sd.has(WIDTH_PIXELS_KEY) ) + { + status |= setWidthPixels( (LLSD::Integer)sd[WIDTH_PIXELS_KEY] ); + } + if ( overwrite || sd.has(HEIGHT_PIXELS_KEY) ) + { + status |= setHeightPixels( (LLSD::Integer)sd[HEIGHT_PIXELS_KEY] ); + } + + // "security" fields + if ( overwrite || sd.has(WHITELIST_ENABLE_KEY) ) + { + status |= setWhiteListEnable( sd[WHITELIST_ENABLE_KEY] ); + } + if ( overwrite || sd.has(WHITELIST_KEY) ) + { + status |= setWhiteList( sd[WHITELIST_KEY] ); + } + + // "permissions" fields + if ( overwrite || sd.has(PERMS_INTERACT_KEY) ) + { + status |= setPermsInteract( 0xff & (LLSD::Integer)sd[PERMS_INTERACT_KEY] ); + } + if ( overwrite || sd.has(PERMS_CONTROL_KEY) ) + { + status |= setPermsControl( 0xff & (LLSD::Integer)sd[PERMS_CONTROL_KEY] ); + } + + return LSL_STATUS_OK == status; +} + +LLMediaEntry& LLMediaEntry::operator=(const LLMediaEntry &rhs) +{ + if (this != &rhs) + { + // "general" fields + mAltImageEnable = rhs.mAltImageEnable; + mControls = rhs.mControls; + mCurrentURL = rhs.mCurrentURL; + mHomeURL = rhs.mHomeURL; + mAutoLoop = rhs.mAutoLoop; + mAutoPlay = rhs.mAutoPlay; + mAutoScale = rhs.mAutoScale; + mAutoZoom = rhs.mAutoZoom; + mFirstClickInteract = rhs.mFirstClickInteract; + mWidthPixels = rhs.mWidthPixels; + mHeightPixels = rhs.mHeightPixels; + + // "security" fields + mWhiteListEnable = rhs.mWhiteListEnable; + mWhiteList = rhs.mWhiteList; + + // "permissions" fields + mPermsInteract = rhs.mPermsInteract; + mPermsControl = rhs.mPermsControl; + } + + return *this; +} + +bool LLMediaEntry::operator==(const LLMediaEntry &rhs) const +{ + return ( + // "general" fields + mAltImageEnable == rhs.mAltImageEnable && + mControls == rhs.mControls && + mCurrentURL == rhs.mCurrentURL && + mHomeURL == rhs.mHomeURL && + mAutoLoop == rhs.mAutoLoop && + mAutoPlay == rhs.mAutoPlay && + mAutoScale == rhs.mAutoScale && + mAutoZoom == rhs.mAutoZoom && + mFirstClickInteract == rhs.mFirstClickInteract && + mWidthPixels == rhs.mWidthPixels && + mHeightPixels == rhs.mHeightPixels && + + // "security" fields + mWhiteListEnable == rhs.mWhiteListEnable && + mWhiteList == rhs.mWhiteList && + + // "permissions" fields + mPermsInteract == rhs.mPermsInteract && + mPermsControl == rhs.mPermsControl + + ); +} + +bool LLMediaEntry::operator!=(const LLMediaEntry &rhs) const +{ + return ( + // "general" fields + mAltImageEnable != rhs.mAltImageEnable || + mControls != rhs.mControls || + mCurrentURL != rhs.mCurrentURL || + mHomeURL != rhs.mHomeURL || + mAutoLoop != rhs.mAutoLoop || + mAutoPlay != rhs.mAutoPlay || + mAutoScale != rhs.mAutoScale || + mAutoZoom != rhs.mAutoZoom || + mFirstClickInteract != rhs.mFirstClickInteract || + mWidthPixels != rhs.mWidthPixels || + mHeightPixels != rhs.mHeightPixels || + + // "security" fields + mWhiteListEnable != rhs.mWhiteListEnable || + mWhiteList != rhs.mWhiteList || + + // "permissions" fields + mPermsInteract != rhs.mPermsInteract || + mPermsControl != rhs.mPermsControl + + ); +} + +U32 LLMediaEntry::setWhiteList( const std::vector<std::string> &whitelist ) +{ + // *NOTE: This code is VERY similar to the setWhitelist below. + // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER! + U32 size = 0; + U32 count = 0; + // First count to make sure the size constraint is not violated + std::vector<std::string>::const_iterator iter = whitelist.begin(); + std::vector<std::string>::const_iterator end = whitelist.end(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter); + size += entry.length() + 1; // Include one for \0 + count ++; + if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT) + { + return LSL_STATUS_BOUNDS_ERROR; + } + } + // Next clear the vector + mWhiteList.clear(); + // Then re-iterate and copy entries + iter = whitelist.begin(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter); + mWhiteList.push_back(entry); + } + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setWhiteList( const LLSD &whitelist ) +{ + // If whitelist is undef, this is a no-op. + if (whitelist.isUndefined()) return LSL_STATUS_OK; + + // However, if the whitelist is an empty array, erase it. + if (whitelist.isArray()) + { + // *NOTE: This code is VERY similar to the setWhitelist above. + // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER! + U32 size = 0; + U32 count = 0; + // First check to make sure the size and count constraints are not violated + LLSD::array_const_iterator iter = whitelist.beginArray(); + LLSD::array_const_iterator end = whitelist.endArray(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter).asString(); + size += entry.length() + 1; // Include one for \0 + count ++; + if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT) + { + return LSL_STATUS_BOUNDS_ERROR; + } + } + // Next clear the vector + mWhiteList.clear(); + // Then re-iterate and copy entries + iter = whitelist.beginArray(); + for ( ; iter < end; ++iter) + { + const std::string &entry = (*iter).asString(); + mWhiteList.push_back(entry); + } + return LSL_STATUS_OK; + } + else + { + return LSL_STATUS_MALFORMED_PARAMS; + } +} + + +static void prefix_with(std::string &str, const char *chars, const char *prefix) +{ + // Given string 'str', prefix all instances of any character in 'chars' + // with 'prefix' + size_t found = str.find_first_of(chars); + size_t prefix_len = strlen(prefix); + while (found != std::string::npos) + { + str.insert(found, prefix, prefix_len); + found = str.find_first_of(chars, found+prefix_len+1); + } +} + +static bool pattern_match(const std::string &candidate_str, const std::string &pattern) +{ + // If the pattern is empty, it matches + if (pattern.empty()) return true; + + // 'pattern' is a glob pattern, we only accept '*' chars + // copy it + std::string expression = pattern; + + // Escape perl's regexp chars with a backslash, except all "*" chars + prefix_with(expression, ".[{()\\+?|^$", "\\"); + prefix_with(expression, "*", "."); + + // case-insensitive matching: + boost::regex regexp(expression, boost::regex::perl|boost::regex::icase); + return boost::regex_match(candidate_str, regexp); +} + +bool LLMediaEntry::checkCandidateUrl(const std::string& url) const +{ + if (getWhiteListEnable()) + { + return checkUrlAgainstWhitelist(url, getWhiteList()); + } + else + { + return true; + } +} + +// static +bool LLMediaEntry::checkUrlAgainstWhitelist(const std::string& url, + const std::vector<std::string> &whitelist) +{ + bool passes = true; + // *NOTE: no entries? Don't check + if (whitelist.size() > 0) + { + passes = false; + + // Case insensitive: the reason why we toUpper both this and the + // filter + std::string candidate_url = url; + // Use lluri to see if there is a path part in the candidate URL. No path? Assume "/" + LLURI candidate_uri(candidate_url); + std::vector<std::string>::const_iterator iter = whitelist.begin(); + std::vector<std::string>::const_iterator end = whitelist.end(); + for ( ; iter < end; ++iter ) + { + std::string filter = *iter; + + LLURI filter_uri(filter); + bool scheme_passes = pattern_match( candidate_uri.scheme(), filter_uri.scheme() ); + if (filter_uri.scheme().empty()) + { + filter_uri = LLURI(DEFAULT_URL_PREFIX + filter); + } + bool authority_passes = pattern_match( candidate_uri.authority(), filter_uri.authority() ); + bool path_passes = pattern_match( candidate_uri.escapedPath(), filter_uri.escapedPath() ); + + if (scheme_passes && authority_passes && path_passes) + { + passes = true; + break; + } + } + } + return passes; +} + +U32 LLMediaEntry::setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit ) +{ + if ( value.length() > limit ) + { + return LSL_STATUS_BOUNDS_ERROR; + } + else + { + field = value; + return LSL_STATUS_OK; + } +} + +U32 LLMediaEntry::setControls(LLMediaEntry::MediaControls controls) +{ + if (controls == STANDARD || + controls == MINI) + { + mControls = controls; + return LSL_STATUS_OK; + } + return LSL_STATUS_BOUNDS_ERROR; +} + +U32 LLMediaEntry::setPermsInteract( U8 val ) +{ + mPermsInteract = val & PERM_MASK; + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setPermsControl( U8 val ) +{ + mPermsControl = val & PERM_MASK; + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setCurrentURL(const std::string& current_url) +{ + return setCurrentURLInternal( current_url, true ); +} + +U32 LLMediaEntry::setCurrentURLInternal(const std::string& current_url, bool check_whitelist) +{ + if ( ! check_whitelist || checkCandidateUrl(current_url)) + { + return setStringFieldWithLimit( mCurrentURL, current_url, MAX_URL_LENGTH ); + } + else + { + return LSL_STATUS_WHITELIST_FAILED; + } +} + +U32 LLMediaEntry::setHomeURL(const std::string& home_url) +{ + return setStringFieldWithLimit( mHomeURL, home_url, MAX_URL_LENGTH ); +} + +U32 LLMediaEntry::setWidthPixels(U16 width) +{ + if (width > MAX_WIDTH_PIXELS) return LSL_STATUS_BOUNDS_ERROR; + mWidthPixels = width; + return LSL_STATUS_OK; +} + +U32 LLMediaEntry::setHeightPixels(U16 height) +{ + if (height > MAX_HEIGHT_PIXELS) return LSL_STATUS_BOUNDS_ERROR; + mHeightPixels = height; + return LSL_STATUS_OK; +} + +const LLUUID &LLMediaEntry::getMediaID() const +{ + // Lazily generate media ID + if (NULL == mMediaIDp) + { + mMediaIDp = new LLUUID(); + mMediaIDp->generate(); + } + return *mMediaIDp; +} + diff --git a/indra/llprimitive/llmediaentry.h b/indra/llprimitive/llmediaentry.h new file mode 100644 index 0000000000..2a5486666a --- /dev/null +++ b/indra/llprimitive/llmediaentry.h @@ -0,0 +1,228 @@ +/** + * @file llmediaentry.h + * @brief This is a single instance of media data related to the face of a prim + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLMEDIAENTRY_H +#define LL_LLMEDIAENTRY_H + +#include "llsd.h" +#include "llstring.h" + +// For return values of set* +#include "lllslconstants.h" + +class LLMediaEntry +{ +public: + enum MediaControls { + STANDARD = 0, + MINI + }; + + // Constructors + LLMediaEntry(); + LLMediaEntry(const LLMediaEntry &rhs); + + LLMediaEntry &operator=(const LLMediaEntry &rhs); + virtual ~LLMediaEntry(); + + bool operator==(const LLMediaEntry &rhs) const; + bool operator!=(const LLMediaEntry &rhs) const; + + // Render as LLSD + LLSD asLLSD() const; + void asLLSD(LLSD& sd) const; + operator LLSD() const { return asLLSD(); } + // Returns false iff the given LLSD contains fields that violate any bounds + // limits. + static bool checkLLSD(const LLSD& sd); + // This doesn't merge, it overwrites the data, so will use + // LLSD defaults if need be. Note: does not check limits! + // Use checkLLSD() above first to ensure the LLSD is valid. + void fromLLSD(const LLSD& sd); + // This merges data from the incoming LLSD into our fields. + // Note that it also does NOT check limits! Use checkLLSD() above first. + void mergeFromLLSD(const LLSD& sd); + + // "general" fields + bool getAltImageEnable() const { return mAltImageEnable; } + MediaControls getControls() const { return mControls; } + std::string getCurrentURL() const { return mCurrentURL; } + std::string getHomeURL() const { return mHomeURL; } + bool getAutoLoop() const { return mAutoLoop; } + bool getAutoPlay() const { return mAutoPlay; } + bool getAutoScale() const { return mAutoScale; } + bool getAutoZoom() const { return mAutoZoom; } + bool getFirstClickInteract() const { return mFirstClickInteract; } + U16 getWidthPixels() const { return mWidthPixels; } + U16 getHeightPixels() const { return mHeightPixels; } + + // "security" fields + bool getWhiteListEnable() const { return mWhiteListEnable; } + const std::vector<std::string> &getWhiteList() const { return mWhiteList; } + + // "permissions" fields + U8 getPermsInteract() const { return mPermsInteract; } + U8 getPermsControl() const { return mPermsControl; } + + // Setters. Those that return a U32 return a status error code + // See lllslconstants.h + + // "general" fields + U32 setAltImageEnable(bool alt_image_enable) { mAltImageEnable = alt_image_enable; return LSL_STATUS_OK; } + U32 setControls(MediaControls controls); + U32 setCurrentURL(const std::string& current_url); + U32 setHomeURL(const std::string& home_url); + U32 setAutoLoop(bool auto_loop) { mAutoLoop = auto_loop; return LSL_STATUS_OK; } + U32 setAutoPlay(bool auto_play) { mAutoPlay = auto_play; return LSL_STATUS_OK; } + U32 setAutoScale(bool auto_scale) { mAutoScale = auto_scale; return LSL_STATUS_OK; } + U32 setAutoZoom(bool auto_zoom) { mAutoZoom = auto_zoom; return LSL_STATUS_OK; } + U32 setFirstClickInteract(bool first_click) { mFirstClickInteract = first_click; return LSL_STATUS_OK; } + U32 setWidthPixels(U16 width); + U32 setHeightPixels(U16 height); + + // "security" fields + U32 setWhiteListEnable( bool whitelist_enable ) { mWhiteListEnable = whitelist_enable; return LSL_STATUS_OK; } + U32 setWhiteList( const std::vector<std::string> &whitelist ); + U32 setWhiteList( const LLSD &whitelist ); // takes an LLSD array + + // "permissions" fields + U32 setPermsInteract( U8 val ); + U32 setPermsControl( U8 val ); + + const LLUUID& getMediaID() const; + + // Helper function to check a candidate URL against the whitelist + // Returns true iff candidate URL passes (or if there is no whitelist), false otherwise + bool checkCandidateUrl(const std::string& url) const; + +public: + // Static function to check a URL against a whitelist + // Returns true iff url passes the given whitelist + static bool checkUrlAgainstWhitelist(const std::string &url, + const std::vector<std::string> &whitelist); + +public: + // LLSD key defines + // "general" fields + static const char* ALT_IMAGE_ENABLE_KEY; + static const char* CONTROLS_KEY; + static const char* CURRENT_URL_KEY; + static const char* HOME_URL_KEY; + static const char* AUTO_LOOP_KEY; + static const char* AUTO_PLAY_KEY; + static const char* AUTO_SCALE_KEY; + static const char* AUTO_ZOOM_KEY; + static const char* FIRST_CLICK_INTERACT_KEY; + static const char* WIDTH_PIXELS_KEY; + static const char* HEIGHT_PIXELS_KEY; + + // "security" fields + static const char* WHITELIST_ENABLE_KEY; + static const char* WHITELIST_KEY; + + // "permissions" fields + static const char* PERMS_INTERACT_KEY; + static const char* PERMS_CONTROL_KEY; + + // Field enumerations & constants + + // *NOTE: DO NOT change the order of these, and do not insert values + // in the middle! + // Add values to the end, and make sure to change PARAM_MAX_ID! + enum Fields { + ALT_IMAGE_ENABLE_ID = 0, + CONTROLS_ID = 1, + CURRENT_URL_ID = 2, + HOME_URL_ID = 3, + AUTO_LOOP_ID = 4, + AUTO_PLAY_ID = 5, + AUTO_SCALE_ID = 6, + AUTO_ZOOM_ID = 7, + FIRST_CLICK_INTERACT_ID = 8, + WIDTH_PIXELS_ID = 9, + HEIGHT_PIXELS_ID = 10, + WHITELIST_ENABLE_ID = 11, + WHITELIST_ID = 12, + PERMS_INTERACT_ID = 13, + PERMS_CONTROL_ID = 14, + PARAM_MAX_ID = PERMS_CONTROL_ID + }; + + // "permissions" values + // (e.g. (PERM_OWNER | PERM_GROUP) sets permissions on for OWNER and GROUP + static const U8 PERM_NONE = 0x0; + static const U8 PERM_OWNER = 0x1; + static const U8 PERM_GROUP = 0x2; + static const U8 PERM_ANYONE = 0x4; + static const U8 PERM_ALL = PERM_OWNER|PERM_GROUP|PERM_ANYONE; + static const U8 PERM_MASK = PERM_OWNER|PERM_GROUP|PERM_ANYONE; + + // Limits (in bytes) + static const U32 MAX_URL_LENGTH = 1024; + static const U32 MAX_WHITELIST_SIZE = 1024; + static const U32 MAX_WHITELIST_COUNT = 64; + static const U16 MAX_WIDTH_PIXELS = 2048; + static const U16 MAX_HEIGHT_PIXELS = 2048; + +private: + + U32 setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit ); + U32 setCurrentURLInternal( const std::string &url, bool check_whitelist); + bool fromLLSDInternal(const LLSD &sd, bool overwrite); + +private: + // "general" fields + bool mAltImageEnable; + MediaControls mControls; + std::string mCurrentURL; + std::string mHomeURL; + bool mAutoLoop; + bool mAutoPlay; + bool mAutoScale; + bool mAutoZoom; + bool mFirstClickInteract; + U16 mWidthPixels; + U16 mHeightPixels; + + // "security" fields + bool mWhiteListEnable; + std::vector<std::string> mWhiteList; + + // "permissions" fields + U8 mPermsInteract; + U8 mPermsControl; + + mutable LLUUID *mMediaIDp; // temporary id assigned to media on the viewer +}; + +#endif + diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 4e733ff56a..d307d4bbfb 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1319,6 +1319,7 @@ S32 LLPrimitive::unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, con color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f; retval |= setTEColor(i, color); + } return retval; diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index 3bcd831142..b534939dfc 100644 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -32,13 +32,31 @@ #include "linden_common.h" +#include "lluuid.h" +#include "llmediaentry.h" #include "lltextureentry.h" #include "llsdutil.h" +#include "v4color.h" const U8 DEFAULT_BUMP_CODE = 0; // no bump or shininess const LLTextureEntry LLTextureEntry::null; +// Some LLSD keys. Do not change these! +#define OBJECT_ID_KEY_STR "object_id" +#define TEXTURE_INDEX_KEY_STR "texture_index" +#define OBJECT_MEDIA_VERSION_KEY_STR "object_media_version" +#define OBJECT_MEDIA_DATA_KEY_STR "object_media_data" +#define TEXTURE_MEDIA_DATA_KEY_STR "media_data" + +/*static*/ const char* LLTextureEntry::OBJECT_ID_KEY = OBJECT_ID_KEY_STR; +/*static*/ const char* LLTextureEntry::OBJECT_MEDIA_DATA_KEY = OBJECT_MEDIA_DATA_KEY_STR; +/*static*/ const char* LLTextureEntry::MEDIA_VERSION_KEY = OBJECT_MEDIA_VERSION_KEY_STR; +/*static*/ const char* LLTextureEntry::TEXTURE_INDEX_KEY = TEXTURE_INDEX_KEY_STR; +/*static*/ const char* LLTextureEntry::TEXTURE_MEDIA_DATA_KEY = TEXTURE_MEDIA_DATA_KEY_STR; + +static const std::string MEDIA_VERSION_STRING_PREFIX = "x-mv:"; + // static LLTextureEntry* LLTextureEntry::newTextureEntry() { @@ -47,16 +65,19 @@ LLTextureEntry* LLTextureEntry::newTextureEntry() //=============================================================== LLTextureEntry::LLTextureEntry() + : mMediaEntry(NULL) { init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE); } LLTextureEntry::LLTextureEntry(const LLUUID& tex_id) + : mMediaEntry(NULL) { init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE); } LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs) + : mMediaEntry(NULL) { mID = rhs.mID; mScaleS = rhs.mScaleS; @@ -68,6 +89,10 @@ LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs) mBump = rhs.mBump; mMediaFlags = rhs.mMediaFlags; mGlow = rhs.mGlow; + if (rhs.mMediaEntry != NULL) { + // Make a copy + mMediaEntry = new LLMediaEntry(*rhs.mMediaEntry); + } } LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs) @@ -84,6 +109,16 @@ LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs) mBump = rhs.mBump; mMediaFlags = rhs.mMediaFlags; mGlow = rhs.mGlow; + if (mMediaEntry != NULL) { + delete mMediaEntry; + } + if (rhs.mMediaEntry != NULL) { + // Make a copy + mMediaEntry = new LLMediaEntry(*rhs.mMediaEntry); + } + else { + mMediaEntry = NULL; + } } return *this; @@ -103,10 +138,19 @@ void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 of mGlow = 0; setColor(LLColor4(1.f, 1.f, 1.f, 1.f)); + if (mMediaEntry != NULL) { + delete mMediaEntry; + } + mMediaEntry = NULL; } LLTextureEntry::~LLTextureEntry() { + if(mMediaEntry) + { + delete mMediaEntry; + mMediaEntry = NULL; + } } bool LLTextureEntry::operator!=(const LLTextureEntry &rhs) const @@ -158,10 +202,17 @@ void LLTextureEntry::asLLSD(LLSD& sd) const sd["bump"] = getBumpShiny(); sd["fullbright"] = getFullbright(); sd["media_flags"] = mMediaFlags; + if (hasMedia()) { + LLSD mediaData; + if (NULL != getMediaData()) { + getMediaData()->asLLSD(mediaData); + } + sd[TEXTURE_MEDIA_DATA_KEY] = mediaData; + } sd["glow"] = mGlow; } -bool LLTextureEntry::fromLLSD(LLSD& sd) +bool LLTextureEntry::fromLLSD(const LLSD& sd) { const char *w, *x; w = "imageid"; @@ -206,6 +257,17 @@ bool LLTextureEntry::fromLLSD(LLSD& sd) { setMediaTexGen( sd[w].asInteger() ); } else goto fail; + // If the "has media" flag doesn't match the fact that + // media data exists, updateMediaData will "fix" it + // by either clearing or setting the flag + w = TEXTURE_MEDIA_DATA_KEY; + if (hasMedia() != sd.has(w)) + { + llwarns << "LLTextureEntry::fromLLSD: media_flags (" << hasMedia() << + ") does not match presence of media_data (" << sd.has(w) << "). Fixing." << llendl; + } + updateMediaData(sd[w]); + w = "glow"; if (sd.has(w)) { @@ -370,7 +432,19 @@ S32 LLTextureEntry::setMediaTexGen(U8 media) if (mMediaFlags != media) { mMediaFlags = media; - return TEM_CHANGE_TEXTURE; + + // Special code for media handling + if( hasMedia() && mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + else if ( ! hasMedia() && mMediaEntry != NULL) + { + delete mMediaEntry; + mMediaEntry = NULL; + } + + return TEM_CHANGE_MEDIA; } return TEM_CHANGE_NONE; } @@ -430,7 +504,19 @@ S32 LLTextureEntry::setMediaFlags(U8 media_flags) { mMediaFlags &= ~TEM_MEDIA_MASK; mMediaFlags |= media_flags; - return TEM_CHANGE_TEXTURE; + + // Special code for media handling + if( hasMedia() && mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + else if ( ! hasMedia() && mMediaEntry != NULL) + { + delete mMediaEntry; + mMediaEntry = NULL; + } + + return TEM_CHANGE_MEDIA; } return TEM_CHANGE_NONE; } @@ -456,3 +542,107 @@ S32 LLTextureEntry::setGlow(F32 glow) } return TEM_CHANGE_NONE; } + +void LLTextureEntry::setMediaData(const LLMediaEntry &media_entry) +{ + mMediaFlags |= MF_HAS_MEDIA; + if (NULL != mMediaEntry) + { + delete mMediaEntry; + } + mMediaEntry = new LLMediaEntry(media_entry); +} + +bool LLTextureEntry::updateMediaData(const LLSD& media_data) +{ + if (media_data.isUndefined()) + { + // clear the media data + clearMediaData(); + return false; + } + else { + mMediaFlags |= MF_HAS_MEDIA; + if (mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + // *NOTE: this will *clobber* all of the fields in mMediaEntry + // with whatever fields are present (or not present) in media_data! + mMediaEntry->fromLLSD(media_data); + return true; + } +} + +void LLTextureEntry::clearMediaData() +{ + mMediaFlags &= ~MF_HAS_MEDIA; + if (mMediaEntry != NULL) { + delete mMediaEntry; + } + mMediaEntry = NULL; +} + +void LLTextureEntry::mergeIntoMediaData(const LLSD& media_fields) +{ + mMediaFlags |= MF_HAS_MEDIA; + if (mMediaEntry == NULL) + { + mMediaEntry = new LLMediaEntry; + } + // *NOTE: this will *merge* the data in media_fields + // with the data in our media entry + mMediaEntry->mergeFromLLSD(media_fields); +} + +//static +std::string LLTextureEntry::touchMediaVersionString(const std::string &in_version, const LLUUID &agent_id) +{ + // XXX TODO: make media version string binary (base64-encoded?) + // Media "URL" is a representation of a version and the last-touched agent + // x-mv:nnnnn/agent-id + // where "nnnnn" is version number + // *NOTE: not the most efficient code in the world... + U32 current_version = getVersionFromMediaVersionString(in_version) + 1; + const size_t MAX_VERSION_LEN = 10; // 2^32 fits in 10 decimal digits + char buf[MAX_VERSION_LEN+1]; + snprintf(buf, (int)MAX_VERSION_LEN+1, "%0*u", (int)MAX_VERSION_LEN, current_version); // added int cast to fix warning/breakage on mac. + return MEDIA_VERSION_STRING_PREFIX + buf + "/" + agent_id.asString(); +} + +//static +U32 LLTextureEntry::getVersionFromMediaVersionString(const std::string &version_string) +{ + U32 version = 0; + if (!version_string.empty()) + { + size_t found = version_string.find(MEDIA_VERSION_STRING_PREFIX); + if (found != std::string::npos) + { + found = version_string.find_first_of("/", found); + std::string v = version_string.substr(MEDIA_VERSION_STRING_PREFIX.length(), found); + version = strtoul(v.c_str(),NULL,10); + } + } + return version; +} + +//static +LLUUID LLTextureEntry::getAgentIDFromMediaVersionString(const std::string &version_string) +{ + LLUUID id; + if (!version_string.empty()) + { + size_t found = version_string.find(MEDIA_VERSION_STRING_PREFIX); + if (found != std::string::npos) + { + found = version_string.find_first_of("/", found); + if (found != std::string::npos) + { + std::string v = version_string.substr(found + 1); + id.set(v); + } + } + } + return id; +} diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h index 84870e93e6..8d2834f78c 100644 --- a/indra/llprimitive/lltextureentry.h +++ b/indra/llprimitive/lltextureentry.h @@ -37,10 +37,13 @@ #include "v4color.h" #include "llsd.h" +// These bits are used while unpacking TEM messages to tell which aspects of +// the texture entry changed. const S32 TEM_CHANGE_NONE = 0x0; const S32 TEM_CHANGE_COLOR = 0x1; const S32 TEM_CHANGE_TEXTURE = 0x2; -const S32 TEM_INVALID = 0x4; +const S32 TEM_CHANGE_MEDIA = 0x4; +const S32 TEM_INVALID = 0x8; const S32 TEM_BUMPMAP_COUNT = 32; @@ -65,6 +68,8 @@ const S32 TEM_MEDIA_MASK = 0x01; const S32 TEM_TEX_GEN_MASK = 0x06; const S32 TEM_TEX_GEN_SHIFT = 1; +// forward declarations +class LLMediaEntry; class LLTextureEntry { @@ -92,7 +97,7 @@ public: LLSD asLLSD() const; void asLLSD(LLSD& sd) const; operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); + bool fromLLSD(const LLSD& sd); virtual LLTextureEntry* newBlank() const; virtual LLTextureEntry* newCopy() const; @@ -140,9 +145,35 @@ public: U8 getTexGen() const { return mMediaFlags & TEM_TEX_GEN_MASK; } U8 getMediaTexGen() const { return mMediaFlags; } F32 getGlow() const { return mGlow; } - + + // *NOTE: it is possible for hasMedia() to return true, but getMediaData() to return NULL. + // CONVERSELY, it is also possible for hasMedia() to return false, but getMediaData() + // to NOT return NULL. + bool hasMedia() const { return (bool)(mMediaFlags & MF_HAS_MEDIA); } + LLMediaEntry* getMediaData() const { return mMediaEntry; } + + // Completely change the media data on this texture entry. + void setMediaData(const LLMediaEntry &media_entry); + // Returns true if media data was updated, false if it was cleared + bool updateMediaData(const LLSD& media_data); + // Clears media data, and sets the media flags bit to 0 + void clearMediaData(); + // Merges the given LLSD of media fields with this media entry. + // Only those fields that are set that match the keys in + // LLMediaEntry will be affected. If no fields are set or if + // the LLSD is undefined, this is a no-op. + void mergeIntoMediaData(const LLSD& media_fields); + + // Takes a media version string (an empty string or a previously-returned string) + // and returns a "touched" string, touched by agent_id + static std::string touchMediaVersionString(const std::string &in_version, const LLUUID &agent_id); + // Given a media version string, return the version + static U32 getVersionFromMediaVersionString(const std::string &version_string); + // Given a media version string, return the UUID of the agent + static LLUUID getAgentIDFromMediaVersionString(const std::string &version_string); + // Media flags - enum { MF_NONE = 0x0, MF_WEB_PAGE = 0x1 }; + enum { MF_NONE = 0x0, MF_HAS_MEDIA = 0x1 }; public: F32 mScaleS; // S, T offset @@ -152,6 +183,14 @@ public: F32 mRotation; // anti-clockwise rotation in rad about the bottom left corner static const LLTextureEntry null; + + // LLSD key defines + static const char* OBJECT_ID_KEY; + static const char* OBJECT_MEDIA_DATA_KEY; + static const char* MEDIA_VERSION_KEY; + static const char* TEXTURE_INDEX_KEY; + static const char* TEXTURE_MEDIA_DATA_KEY; + protected: LLUUID mID; // Texture GUID LLColor4 mColor; @@ -159,6 +198,9 @@ protected: U8 mMediaFlags; // replace with web page, movie, etc. F32 mGlow; + // Note the media data is not sent via the same message structure as the rest of the TE + LLMediaEntry* mMediaEntry; // The media data for the face + // NOTE: when adding new data to this class, in addition to adding it to the serializers asLLSD/fromLLSD and the // message packers (e.g. LLPrimitive::packTEMessage) you must also implement its copy in LLPrimitive::copyTEs() diff --git a/indra/llprimitive/tests/llmediaentry_test.cpp b/indra/llprimitive/tests/llmediaentry_test.cpp new file mode 100644 index 0000000000..72478d0459 --- /dev/null +++ b/indra/llprimitive/tests/llmediaentry_test.cpp @@ -0,0 +1,484 @@ +/** + * @file llmediaentry_test.cpp + * @brief llmediaentry unit tests + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * Copyright (c) 2001-2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lltut.h" +#include "boost/lexical_cast.hpp" +#include "llstring.h" +#include "llsdutil.h" +#include "llsdserialize.h" + +#include "../llmediaentry.h" +#include "lllslconstants.h" + +#define DEFAULT_MEDIA_ENTRY "<llsd>\n\ + <map>\n\ + <key>alt_image_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_loop</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_play</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_scale</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_zoom</key>\n\ + <boolean>0</boolean>\n\ + <key>controls</key>\n\ + <integer>0</integer>\n\ + <key>current_url</key>\n\ + <string />\n\ + <key>first_click_interact</key>\n\ + <boolean>0</boolean>\n\ + <key>height_pixels</key>\n\ + <integer>0</integer>\n\ + <key>home_url</key>\n\ + <string />\n\ + <key>perms_control</key>\n\ + <integer>7</integer>\n\ + <key>perms_interact</key>\n\ + <integer>7</integer>\n\ + <key>whitelist_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>width_pixels</key>\n\ + <integer>0</integer>\n\ + </map>\n\ + </llsd>" + +#define EMPTY_MEDIA_ENTRY "<llsd>\n\ + <map>\n\ + <key>alt_image_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_loop</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_play</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_scale</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_zoom</key>\n\ + <boolean>0</boolean>\n\ + <key>controls</key>\n\ + <integer>0</integer>\n\ + <key>current_url</key>\n\ + <string />\n\ + <key>first_click_interact</key>\n\ + <boolean>0</boolean>\n\ + <key>height_pixels</key>\n\ + <integer>0</integer>\n\ + <key>home_url</key>\n\ + <string />\n\ + <key>perms_control</key>\n\ + <integer>0</integer>\n\ + <key>perms_interact</key>\n\ + <integer>0</integer>\n\ + <key>whitelist_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>width_pixels</key>\n\ + <integer>0</integer>\n\ + </map>\n\ + </llsd>" + +#define PARTIAL_MEDIA_ENTRY(CURRENT_URL) "<llsd>\n\ + <map>\n\ + <key>alt_image_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_loop</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_play</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_scale</key>\n\ + <boolean>0</boolean>\n\ + <key>auto_zoom</key>\n\ + <boolean>0</boolean>\n\ + <key>controls</key>\n\ + <integer>0</integer>\n\ + <key>current_url</key>\n\ + <string>" CURRENT_URL "</string>\n\ + <key>first_click_interact</key>\n\ + <boolean>0</boolean>\n\ + <key>height_pixels</key>\n\ + <integer>0</integer>\n\ + <key>home_url</key>\n\ + <string />\n\ + <key>perms_control</key>\n\ + <integer>0</integer>\n\ + <key>perms_interact</key>\n\ + <integer>0</integer>\n\ + <key>whitelist_enable</key>\n\ + <boolean>0</boolean>\n\ + <key>width_pixels</key>\n\ + <integer>0</integer>\n\ + </map>\n\ + </llsd>" + +namespace tut +{ + // this is fixture data that gets created before each test and destroyed + // after each test. this is where we put all of the setup/takedown code + // and data needed for each test. + struct MediaEntry_test + { + MediaEntry_test() { + emptyMediaEntryStr = EMPTY_MEDIA_ENTRY; + std::istringstream e(EMPTY_MEDIA_ENTRY); + LLSDSerialize::fromXML(emptyMediaEntryLLSD, e); + defaultMediaEntryStr = DEFAULT_MEDIA_ENTRY; + std::istringstream d(DEFAULT_MEDIA_ENTRY); + LLSDSerialize::fromXML(defaultMediaEntryLLSD, d); + } + std::string emptyMediaEntryStr; + LLSD emptyMediaEntryLLSD; + std::string defaultMediaEntryStr; + LLSD defaultMediaEntryLLSD; + }; + + typedef test_group<MediaEntry_test, 55> factory; + typedef factory::object object; +} + + +namespace +{ + // this is for naming our tests to make pretty output + tut::factory tf("MediaEntry Test"); +} + +namespace tut +{ + bool llsd_equals(const LLSD& a, const LLSD& b) { + // cheesy, brute force, but it works + return std::string(ll_pretty_print_sd(a)) == std::string(ll_pretty_print_sd(b)); + } + + void ensure_llsd_equals(const std::string& msg, const LLSD& expected, const LLSD& actual) + { + if (! llsd_equals(expected, actual)) + { + std::string message = msg; + message += ": actual: "; + message += ll_pretty_print_sd(actual); + message += "\n expected: "; + message += ll_pretty_print_sd(expected); + message += "\n"; + ensure(message, false); + } + } + + void ensure_string_equals(const std::string& msg, const std::string& expected, const std::string& actual) + { + if ( expected != actual ) + { + std::string message = msg; + message += ": actual: "; + message += actual; + message += "\n expected: "; + message += expected; + message += "\n"; + ensure(message, false); + } + } + + void set_whitelist(LLMediaEntry &entry, const char *str) + { + std::vector<std::string> tokens; + LLStringUtil::getTokens(std::string(str), tokens, ","); + entry.setWhiteList(tokens); + } + + void whitelist_test(bool enable, const char *whitelist, const char *candidate_url, bool expected_pass) + { + std::string message = "Whitelist test"; + LLMediaEntry entry; + entry.setWhiteListEnable(enable); + set_whitelist(entry, whitelist); + bool passed_whitelist = entry.checkCandidateUrl(candidate_url); + if (passed_whitelist != expected_pass) + { + message += " failed: expected "; + message += (expected_pass) ? "" : "NOT "; + message += "to match\nwhitelist = "; + message += whitelist; + message += "\ncandidate_url = "; + message += candidate_url; + } + ensure(message, expected_pass == passed_whitelist); + } + + void whitelist_test(const char *whitelist, const char *candidate_url, bool expected_pass) + { + whitelist_test(true, whitelist, candidate_url, expected_pass); + } + void whitelist_test(const char *whitelist, const char *candidate_url) + { + whitelist_test(true, whitelist, candidate_url, true); + } + + template<> template<> + void object::test<1>() + { + set_test_name("Test LLMediaEntry Instantiation"); + LLMediaEntry entry; + ensure_llsd_equals(get_test_name(), defaultMediaEntryLLSD, entry.asLLSD()); + + } + + template<> template<> + void object::test<2>() + { + set_test_name("Test LLMediaEntry Instantiation from LLSD"); + LLMediaEntry entry; + LLSD sd; + entry.fromLLSD(sd); + ensure_llsd_equals(get_test_name() + " failed", emptyMediaEntryLLSD, entry.asLLSD()); + } + + template<> template<> + void object::test<3>() + { + set_test_name("Test LLMediaEntry Partial Instantiation from LLSD"); + LLMediaEntry entry; + LLSD sd; + sd[LLMediaEntry::CURRENT_URL_KEY] = "http://www.example.com"; + entry.fromLLSD(sd); + LLSD golden; + std::istringstream p(PARTIAL_MEDIA_ENTRY("http://www.example.com")); + LLSDSerialize::fromXML(golden,p); + ensure_llsd_equals(get_test_name() + " failed", golden, entry.asLLSD()); + } + + // limit tests + const char *URL_OK = "http://www.example.com"; + const char *URL_TOO_BIG = "http://www.example.com.qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; + + template<> template<> + void object::test<4>() + { + set_test_name("Test Limits on setting current URL"); + LLMediaEntry entry; + U32 status = entry.setCurrentURL(URL_OK); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_OK); + status = entry.setCurrentURL(URL_TOO_BIG); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_BOUNDS_ERROR); + } + + template<> template<> + void object::test<5>() + { + set_test_name("Test Limits on setting home URL"); + LLMediaEntry entry; + U32 status = entry.setHomeURL(URL_OK); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_OK); + status = entry.setHomeURL(URL_TOO_BIG); + ensure(get_test_name() + " ok failed", status == LSL_STATUS_BOUNDS_ERROR); + } + + template<> template<> + void object::test<6>() + { + set_test_name("Test Limits on setting whitelist"); + + // Test a valid list + LLMediaEntry entry; + std::vector<std::string> whitelist; + whitelist.push_back(std::string(URL_OK)); + S32 status = entry.setWhiteList(whitelist); + ensure(get_test_name() + " invalid result", status == LSL_STATUS_OK); + ensure(get_test_name() + " failed", whitelist == entry.getWhiteList()); + } + + template<> template<> + void object::test<7>() + { + set_test_name("Test Limits on setting whitelist too big"); + + // Test an invalid list + LLMediaEntry entry; + std::vector<std::string> whitelist, empty; + whitelist.push_back(std::string(URL_OK)); + whitelist.push_back(std::string(URL_TOO_BIG)); + S32 status = entry.setWhiteList(whitelist); + ensure(get_test_name() + " invalid result", status == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", empty == entry.getWhiteList()); + } + + template<> template<> + void object::test<8>() + { + set_test_name("Test Limits on setting whitelist too many"); + + // Test an invalid list + LLMediaEntry entry; + std::vector<std::string> whitelist, empty; + for (int i=0; i < LLMediaEntry::MAX_WHITELIST_SIZE+1; i++) { + whitelist.push_back("Q"); + } + S32 status = entry.setWhiteList(whitelist); + ensure(get_test_name() + " invalid result", status == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", empty == entry.getWhiteList()); + } + + template<> template<> + void object::test<9>() + { + set_test_name("Test to make sure both setWhiteList() functions behave the same"); + + // Test a valid list + std::vector<std::string> whitelist, empty; + LLSD whitelist_llsd; + whitelist.push_back(std::string(URL_OK)); + whitelist_llsd.append(std::string(URL_OK)); + LLMediaEntry entry1, entry2; + ensure(get_test_name() + " setWhiteList(s) don't match", + entry1.setWhiteList(whitelist) == LSL_STATUS_OK && + entry2.setWhiteList(whitelist_llsd)== LSL_STATUS_OK ); + ensure(get_test_name() + " failed", + entry1.getWhiteList() == entry2.getWhiteList()); + } + + template<> template<> + void object::test<10>() + { + set_test_name("Test to make sure both setWhiteList() functions behave the same"); + + // Test an invalid list + std::vector<std::string> whitelist, empty; + LLSD whitelist_llsd; + whitelist.push_back(std::string(URL_OK)); + whitelist.push_back(std::string(URL_TOO_BIG)); + whitelist_llsd.append(std::string(URL_OK)); + whitelist_llsd.append(std::string(URL_TOO_BIG)); + LLMediaEntry entry1, entry2; + ensure(get_test_name() + " setWhiteList(s) don't match", + entry1.setWhiteList(whitelist) == LSL_STATUS_BOUNDS_ERROR && + entry2.setWhiteList(whitelist_llsd) == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", + empty == entry1.getWhiteList() && + empty == entry2.getWhiteList()); + } + + template<> template<> + void object::test<11>() + { + set_test_name("Test to make sure both setWhiteList() functions behave the same"); + + // Test an invalid list, too many + std::vector<std::string> whitelist, empty; + LLSD whitelist_llsd; + for (int i=0; i < LLMediaEntry::MAX_WHITELIST_SIZE+1; i++) { + whitelist.push_back("Q"); + whitelist_llsd.append("Q"); + } + LLMediaEntry entry1, entry2; + ensure(get_test_name() + " invalid result", + entry1.setWhiteList(whitelist) == LSL_STATUS_BOUNDS_ERROR && + entry2.setWhiteList(whitelist_llsd) == LSL_STATUS_BOUNDS_ERROR); + ensure(get_test_name() + " failed", + empty == entry1.getWhiteList() && + empty == entry2.getWhiteList()); + } + + // Whitelist check tests + + // Check the "empty whitelist" case + template<> template<> + void object::test<12>() { whitelist_test("", "http://www.example.com", true); } + + // Check the "missing scheme" case + template<> template<> + void object::test<13>() { whitelist_test("www.example.com", "http://www.example.com", true); } + + // Check the "exactly the same" case + template<> template<> + void object::test<14>() { whitelist_test("http://example.com", "http://example.com", true); } + + // Check the enable flag + template<> template<> + void object::test<15>() { whitelist_test(false, "www.example.com", "http://www.secondlife.com", true); } + template<> template<> + void object::test<16>() { whitelist_test(true, "www.example.com", "http://www.secondlife.com", false); } + + // Check permutations of trailing slash: + template<> template<> + void object::test<17>() { whitelist_test("http://www.example.com", "http://www.example.com/", true); } + template<> template<> + void object::test<18>() { whitelist_test("http://www.example.com/", "http://www.example.com/", true); } + template<> template<> + void object::test<19>() { whitelist_test("http://www.example.com/", "http://www.example.com", false); } + template<> template<> + void object::test<20>() { whitelist_test("http://www.example.com", "http://www.example.com/foobar", true); } + template<> template<> + void object::test<21>() { whitelist_test("http://www.example.com/", "http://www.example.com/foobar", false); } + + + // More cases... + template<> template<> + void object::test<22>() { whitelist_test("http://example.com", "http://example.com/wiki", true); } + template<> template<> + void object::test<23>() { whitelist_test("www.example.com", "http://www.example.com/help", true); } + template<> template<> + void object::test<24>() { whitelist_test("http://www.example.com", "http://wwwexample.com", false); } + template<> template<> + void object::test<25>() { whitelist_test("http://www.example.com", "http://www.example.com/wiki", true); } + template<> template<> + void object::test<26>() { whitelist_test("example.com", "http://wwwexample.com", false); } + template<> template<> + void object::test<27>() { whitelist_test("http://www.example.com/", "http://www.amazon.com/wiki", false); } + template<> template<> + void object::test<28>() { whitelist_test("www.example.com", "http://www.amazon.com", false); } + + // regexp cases + template<> template<> + void object::test<29>() { whitelist_test("*.example.com", "http://www.example.com", true); } + template<> template<> + void object::test<30>() { whitelist_test("*.example.com", "http://www.amazon.com", false); } + template<> template<> + void object::test<31>() { whitelist_test("*.example.com", "http://www.example.com/foo/bar", true); } + template<> template<> + void object::test<32>() { whitelist_test("*.example.com", "http:/example.com/foo/bar", false); } + template<> template<> + void object::test<33>() { whitelist_test("*example.com", "http://example.com/foo/bar", true); } + template<> template<> + void object::test<34>() { whitelist_test("*example.com", "http://my.virus.com/foo/bar?example.com", false); } + template<> template<> + void object::test<35>() { whitelist_test("example.com", "http://my.virus.com/foo/bar?example.com", false); } + template<> template<> + void object::test<36>() { whitelist_test("*example.com", "http://my.virus.com/foo/bar?*example.com", false); } + template<> template<> + void object::test<37>() { whitelist_test("http://*example.com", "http://www.example.com", true); } + template<> template<> + void object::test<38>() { whitelist_test("http://*.example.com", "http://www.example.com", true); } + template<> template<> + void object::test<39>() { whitelist_test("http://*.e$?^.com", "http://www.e$?^.com", true); } + template<> template<> + void object::test<40>() { whitelist_test("*.example.com/foo/bar", "http://www.example.com/", false); } + template<> template<> + void object::test<41>() { whitelist_test("*.example.com/foo/bar", "http://example.com/foo/bar", false); } + template<> template<> + void object::test<42>() { whitelist_test("http://*.example.com/foo/bar", "http://www.example.com", false); } + template<> template<> + void object::test<43>() { whitelist_test("http://*.example.com", "https://www.example.com", false); } + template<> template<> + void object::test<44>() { whitelist_test("http*://*.example.com", "rtsp://www.example.com", false); } + template<> template<> + void object::test<45>() { whitelist_test("http*://*.example.com", "https://www.example.com", true); } + template<> template<> + void object::test<46>() { whitelist_test("example.com", "http://www.example.com", false); } + template<> template<> + void object::test<47>() { whitelist_test("www.example.com", "http://www.example.com:80", false); } + template<> template<> + void object::test<48>() { whitelist_test("www.example.com", "http://www.example.com", true); } + template<> template<> + void object::test<49>() { whitelist_test("www.example.com/", "http://www.example.com", false); } + template<> template<> + void object::test<50>() { whitelist_test("www.example.com/foo/bar/*", "http://www.example.com/foo/bar/baz", true); } + // Path only + template<> template<> + void object::test<51>() { whitelist_test("/foo/*/baz", "http://www.example.com/foo/bar/baz", true); } + template<> template<> + void object::test<52>() { whitelist_test("/foo/*/baz", "http://www.example.com/foo/bar/", false); } +} diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 1e6b216a61..0a284f0088 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -85,6 +85,7 @@ set(llui_SOURCE_FILES lltextbox.cpp lltexteditor.cpp lltextparser.cpp + lltransientfloatermgr.cpp lltransutil.cpp lltooltip.cpp llui.cpp @@ -129,7 +130,7 @@ set(llui_HEADER_FILES llfocusmgr.h llfunctorregistry.h llhandle.h - llhtmlhelp.h + llhelp.h lliconctrl.h llkeywords.h lllayoutstack.h @@ -171,6 +172,7 @@ set(llui_HEADER_FILES lltexteditor.h lltextparser.h lltooltip.h + lltransientfloatermgr.h lltransutil.h lluicolortable.h lluiconstants.h diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index fa13ced037..b9613b502c 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -39,7 +39,6 @@ #include "llstring.h" // Project includes -#include "llhtmlhelp.h" #include "llkeyboard.h" #include "llui.h" #include "lluiconstants.h" @@ -49,8 +48,10 @@ #include "llfloaterreg.h" #include "llfocusmgr.h" #include "llwindow.h" +#include "llnotifications.h" #include "llrender.h" #include "lluictrlfactory.h" +#include "llhelp.h" static LLDefaultChildRegistry::Register<LLButton> r("button"); @@ -92,7 +93,6 @@ LLButton::Params::Params() mouse_held_callback("mouse_held_callback"), is_toggle("is_toggle", false), scale_image("scale_image", true), - help_url("help_url"), hover_glow_amount("hover_glow_amount"), commit_on_return("commit_on_return", true), picture_style("picture_style", false) @@ -173,11 +173,6 @@ LLButton::LLButton(const LLButton::Params& p) mMouseDownTimer.stop(); - if (p.help_url.isProvided()) - { - setHelpURLCallback(p.help_url); - } - // if custom unselected button image provided... if (p.image_unselected != default_params.image_unselected) { @@ -1034,24 +1029,6 @@ void LLButton::addImageAttributeToXML(LLXMLNodePtr node, } } -void clicked_help(void* data) -{ - LLButton* self = (LLButton*)data; - if (!self) return; - - if (!LLUI::sHtmlHelp) - { - return; - } - - LLUI::sHtmlHelp->show(self->getHelpURL()); -} - -void LLButton::setHelpURLCallback(const std::string &help_url) -{ - mHelpURL = help_url; - setClickedCallback(clicked_help,this); -} // static void LLButton::toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname) @@ -1077,6 +1054,24 @@ void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname) button->setClickedCallback(boost::bind(&LLFloaterReg::toggleFloaterInstance, sdname)); } +// static +void LLButton::showHelp(LLUICtrl* ctrl, const LLSD& sdname) +{ + // search back through the button's parents for a panel + // with a help_topic string defined + std::string help_topic; + if (LLUI::sHelpImpl && + ctrl->findHelpTopic(help_topic)) + { + LLUI::sHelpImpl->showTopic(help_topic); + return; // success + } + + // display an error if we can't find a help_topic string. + // fix this by adding a help_topic attribute to the xui file + LLNotifications::instance().add("UnableToFindHelpTopic"); +} + void LLButton::resetMouseDownTimer() { mMouseDownTimer.stop(); diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 06e1dac914..04716d605b 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -118,7 +118,6 @@ public: commit_on_return, picture_style; //if true, don't display label - Optional<std::string> help_url; Optional<F32> hover_glow_amount; Optional<TimeIntervalParam> held_down_delay; @@ -230,12 +229,10 @@ public: void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; } BOOL getCommitOnReturn() const { return mCommitOnReturn; } - void setHelpURLCallback(const std::string &help_url); - const std::string& getHelpURL() const { return mHelpURL; } - static void onHeldDown(void *userdata); // to be called by gIdleCallbacks static void toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname); static void setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname); + static void showHelp(LLUICtrl* ctrl, const LLSD& sdname); protected: const LLPointer<LLUIImage>& getImageUnselected() const { return mImageUnselected; } @@ -314,8 +311,6 @@ private: BOOL mCommitOnReturn; BOOL mFadeWhenDisabled; - std::string mHelpURL; - LLFrameTimer mFlashingTimer; }; diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 58aeb61728..0170ac0c6a 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -483,7 +483,6 @@ void LLComboBox::createLineEditor(const LLComboBox::Params& p) params.max_length_bytes(mMaxChars); params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2)); params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); - params.focus_lost_callback(NULL); params.handle_edit_keys_directly(true); params.commit_on_focus_lost(false); params.follows.flags(FOLLOWS_ALL); diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index 93d62fd7c2..4525f0a45b 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -71,9 +71,9 @@ void LLDockableFloater::resetInstance() if (sInstanceHandle.get() != NULL && sInstanceHandle.get()->isDocked()) { sInstanceHandle.get()->setVisible(FALSE); - } + } sInstanceHandle = getHandle(); - } + } } void LLDockableFloater::setVisible(BOOL visible) @@ -105,11 +105,11 @@ void LLDockableFloater::setDocked(bool docked, bool pop_on_undock) mDockControl.get()->off(); } - if (!docked && pop_on_undock) - { - // visually pop up a little bit to emphasize the undocking - translate(0, UNDOCK_LEAP_HEIGHT); - } + if (!docked && pop_on_undock) + { + // visually pop up a little bit to emphasize the undocking + translate(0, UNDOCK_LEAP_HEIGHT); + } } else { @@ -126,8 +126,8 @@ void LLDockableFloater::draw() mDockControl.get()->repositionDockable(); if (isDocked()) { - mDockControl.get()->drawToungue(); - } + mDockControl.get()->drawToungue(); + } } LLFloater::draw(); } diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp index 0b16b2554c..146c7a969a 100644 --- a/indra/llui/lldockcontrol.cpp +++ b/indra/llui/lldockcontrol.cpp @@ -35,7 +35,7 @@ #include "lldockcontrol.h" LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, - const LLUIImagePtr& dockTongue, DocAt dockAt, get_rect_callback_t get_rect_callback) : + const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) : mDockWidget(dockWidget), mDockableFloater(dockableFloater), mDockTongue(dockTongue) { mDockAt = dockAt; @@ -49,13 +49,13 @@ LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, off(); } - if (!(get_rect_callback)) + if (!(get_allowed_rect_callback)) { - mGetRectCallback = boost::bind(&LLDockControl::getEnabledRect, this, _1); + mGetAllowedRectCallback = boost::bind(&LLDockControl::getAllowedRect, this, _1); } else { - mGetRectCallback = get_rect_callback; + mGetAllowedRectCallback = get_allowed_rect_callback; } if (dockWidget != NULL) @@ -77,7 +77,7 @@ void LLDockControl::setDock(LLView* dockWidget) } } -void LLDockControl::getEnabledRect(LLRect& rect) +void LLDockControl::getAllowedRect(LLRect& rect) { rect = mDockableFloater->getRootView()->getRect(); } @@ -86,7 +86,7 @@ void LLDockControl::repositionDockable() { LLRect dockRect = mDockWidget->calcScreenRect(); LLRect rootRect; - mGetRectCallback(rootRect); + mGetAllowedRectCallback(rootRect); static BOOL prev_visibility = !mDockWidget->getVisible(); // recalculate dockable position if dock position changed, dock visibility changed, @@ -100,7 +100,7 @@ void LLDockControl::repositionDockable() mDockableFloater->setDocked(false); // force off() since dockable may not have dockControll at this time off(); - } + } else { moveDockable(); @@ -123,10 +123,10 @@ bool LLDockControl::isDockVisible() res = mDockWidget->isInVisibleChain(); if (res) { - LLRect dockRect = mDockWidget->calcScreenRect(); + LLRect dockRect = mDockWidget->calcScreenRect(); switch (mDockAt) - { + { case TOP: // check is dock inside parent rect LLRect dockParentRect = @@ -149,25 +149,25 @@ void LLDockControl::moveDockable() // calculate new dockable position LLRect dockRect = mDockWidget->calcScreenRect(); LLRect rootRect; - mGetRectCallback(rootRect); + mGetAllowedRectCallback(rootRect); - LLRect dockableRect = mDockableFloater->calcScreenRect(); - S32 x = 0; - S32 y = 0; - switch (mDockAt) - { - case TOP: - x = dockRect.getCenterX() - dockableRect.getWidth() / 2; + LLRect dockableRect = mDockableFloater->calcScreenRect(); + S32 x = 0; + S32 y = 0; + switch (mDockAt) + { + case TOP: + x = dockRect.getCenterX() - dockableRect.getWidth() / 2; y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight(); // check is dockable inside root view rect - if (x < rootRect.mLeft) - { - x = rootRect.mLeft; - } - if (x + dockableRect.getWidth() > rootRect.mRight) - { - x = rootRect.mRight - dockableRect.getWidth(); - } + if (x < rootRect.mLeft) + { + x = rootRect.mLeft; + } + if (x + dockableRect.getWidth() > rootRect.mRight) + { + x = rootRect.mRight - dockableRect.getWidth(); + } // calculate dock tongue position @@ -185,21 +185,21 @@ void LLDockControl::moveDockable() { mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2; } - mDockTongueY = dockRect.mTop; + mDockTongueY = dockRect.mTop; - break; - } + break; + } // move dockable - dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), - dockableRect.getHeight()); - LLRect localDocableParentRect; - mDockableFloater->getParent()->screenRectToLocal(dockableRect, - &localDocableParentRect); - mDockableFloater->setRect(localDocableParentRect); + dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), + dockableRect.getHeight()); + LLRect localDocableParentRect; + mDockableFloater->getParent()->screenRectToLocal(dockableRect, + &localDocableParentRect); + mDockableFloater->setRect(localDocableParentRect); - mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, - &mDockTongueX, &mDockTongueY); + mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, + &mDockTongueX, &mDockTongueY); } @@ -207,9 +207,9 @@ void LLDockControl::on() { if (isDockVisible()) { - mDockableFloater->setCanDrag(false); - mEnabled = true; - mRecalculateDocablePosition = true; + mDockableFloater->setCanDrag(false); + mEnabled = true; + mRecalculateDocablePosition = true; } } diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h index 219ddfd092..e8ffcac0ac 100644 --- a/indra/llui/lldockcontrol.h +++ b/indra/llui/lldockcontrol.h @@ -52,11 +52,11 @@ public: public: // callback for a function getting a rect valid for control's position - typedef boost::function<void (LLRect& )> get_rect_callback_t; + typedef boost::function<void (LLRect& )> get_allowed_rect_callback_t; LOG_CLASS(LLDockControl); LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, - const LLUIImagePtr& dockTongue, DocAt dockAt, get_rect_callback_t get_rect_callback = NULL); + const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_rect_callback = NULL); virtual ~LLDockControl(); public: @@ -67,13 +67,13 @@ public: void drawToungue(); bool isDockVisible(); - // gets a rect that bounds possible positions for a dockable control - void getEnabledRect(LLRect& rect); + // gets a rect that bounds possible positions for a dockable control (EXT-1111) + void getAllowedRect(LLRect& rect); private: virtual void moveDockable(); private: - get_rect_callback_t mGetRectCallback; + get_allowed_rect_callback_t mGetAllowedRectCallback; bool mEnabled; bool mRecalculateDocablePosition; DocAt mDockAt; diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 9fcd386c19..e9df361472 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -39,8 +39,8 @@ static const LLDefaultChildRegistry::Register<LLFlatListView> flat_list_view("flat_list_view"); -const LLSD SELECTED_EVENT = LLSD().insert("selected", true); -const LLSD UNSELECTED_EVENT = LLSD().insert("selected", false); +const LLSD SELECTED_EVENT = LLSD().insert("selected", true); +const LLSD UNSELECTED_EVENT = LLSD().insert("selected", false); static const std::string COMMENT_TEXTBOX = "comment_text"; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 81915731c3..ff0288a32f 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -59,6 +59,7 @@ #include "lltabcontainer.h" #include "v2math.h" #include "lltrans.h" +#include "llhelp.h" #include "llmultifloater.h" // use this to control "jumping" behavior when Ctrl-Tabbing @@ -66,48 +67,35 @@ const S32 TABBED_FLOATER_OFFSET = 0; std::string LLFloater::sButtonActiveImageNames[BUTTON_COUNT] = { - "Icon_Close_Foreground", //BUTTON_CLOSE - "restore.tga", //BUTTON_RESTORE - "minimize.tga", //BUTTON_MINIMIZE - "tearoffbox.tga", //BUTTON_TEAR_OFF - "closebox.tga", //BUTTON_EDIT - "Icon_Dock_Foreground", - "Icon_Undock_Foreground" -}; - -// Empty string means programmatic glow effect, achieved by -// not setting explicit image. -std::string LLFloater::sButtonHoveredImageNames[BUTTON_COUNT] = -{ - "", //BUTTON_CLOSE - "restore_pressed.tga", //BUTTON_RESTORE - "minimize_pressed.tga", //BUTTON_MINIMIZE - "tearoff_pressed.tga", //BUTTON_TEAR_OFF - "close_in_blue.tga", //BUTTON_EDIT - "", //BUTTON_DOCK - "", //BUTTON_UNDOCK + "Icon_Close_Foreground", //BUTTON_CLOSE + "Icon_Restore_Foreground", //BUTTON_RESTORE + "Icon_Minimize_Foreground", //BUTTON_MINIMIZE + "tearoffbox.tga", //BUTTON_TEAR_OFF + "Icon_Dock_Foreground", //BUTTON_DOCK + "Icon_Undock_Foreground", //BUTTON_UNDOCK + "Icon_Help_Foreground" //BUTTON_HELP }; std::string LLFloater::sButtonPressedImageNames[BUTTON_COUNT] = { - "Icon_Close_Press", //BUTTON_CLOSE - "restore_pressed.tga", //BUTTON_RESTORE - "minimize_pressed.tga", //BUTTON_MINIMIZE - "tearoff_pressed.tga", //BUTTON_TEAR_OFF - "close_in_blue.tga", //BUTTON_EDIT - "Icon_Dock_Press", - "Icon_Undock_Press" + "Icon_Close_Press", //BUTTON_CLOSE + "Icon_Restore_Press", //BUTTON_RESTORE + "Icon_Minimize_Press", //BUTTON_MINIMIZE + "tearoff_pressed.tga", //BUTTON_TEAR_OFF + "Icon_Dock_Press", //BUTTON_DOCK + "Icon_Undock_Press", //BUTTON_UNDOCK + "Icon_Help_Press" //BUTTON_HELP }; std::string LLFloater::sButtonNames[BUTTON_COUNT] = { - "llfloater_close_btn", //BUTTON_CLOSE + "llfloater_close_btn", //BUTTON_CLOSE "llfloater_restore_btn", //BUTTON_RESTORE "llfloater_minimize_btn", //BUTTON_MINIMIZE "llfloater_tear_off_btn", //BUTTON_TEAR_OFF - "llfloater_edit_btn", //BUTTON_EDIT - "llfloater_dock_btn", - "llfloater_undock_btn" + "llfloater_dock_btn", //BUTTON_DOCK + "llfloater_undock_btn", //BUTTON_UNDOCK + "llfloater_help_btn" //BUTTON_HELP }; std::string LLFloater::sButtonToolTips[BUTTON_COUNT]; @@ -122,9 +110,9 @@ std::string LLFloater::sButtonToolTipsIndex[BUTTON_COUNT]= "BUTTON_RESTORE", //"Restore", //BUTTON_RESTORE "BUTTON_MINIMIZE", //"Minimize", //BUTTON_MINIMIZE "BUTTON_TEAR_OFF", //"Tear Off", //BUTTON_TEAR_OFF - "BUTTON_EDIT", //"Edit", //BUTTON_EDIT "BUTTON_DOCK", - "BUTTON_UNDOCK" + "BUTTON_UNDOCK", + "BUTTON_HELP" }; LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] = @@ -133,13 +121,12 @@ LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] = LLFloater::onClickMinimize, //BUTTON_RESTORE LLFloater::onClickMinimize, //BUTTON_MINIMIZE LLFloater::onClickTearOff, //BUTTON_TEAR_OFF - LLFloater::onClickEdit, //BUTTON_EDIT - LLFloater::onClickDock, - LLFloater::onClickDock + LLFloater::onClickDock, //BUTTON_DOCK + LLFloater::onClickDock, //BUTTON_UNDOCK + LLFloater::onClickHelp //BUTTON_HELP }; LLMultiFloater* LLFloater::sHostp = NULL; -BOOL LLFloater::sEditModeEnabled = FALSE; BOOL LLFloater::sQuitting = FALSE; // Flag to prevent storing visibility controls while quitting LLFloater::handle_map_t LLFloater::sFloaterMap; @@ -259,7 +246,6 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) mMinimized(FALSE), mForeground(FALSE), mFirstLook(TRUE), - mEditing(FALSE), mButtonScale(1.0f), mAutoFocus(TRUE), // automatically take focus when opened mCanDock(false), @@ -314,6 +300,12 @@ void LLFloater::initFloater() mButtonsEnabled[BUTTON_CLOSE] = TRUE; } + // Help button: '?' + if ( !mHelpTopic.empty() ) + { + mButtonsEnabled[BUTTON_HELP] = TRUE; + } + // Minimize button only for top draggers if ( !mDragOnLeft && mCanMinimize ) { @@ -804,7 +796,7 @@ void LLFloater::setTitle( const std::string& title ) applyTitle(); } -std::string LLFloater::getTitle() +std::string LLFloater::getTitle() const { if (mTitle.empty()) { @@ -822,7 +814,7 @@ void LLFloater::setShortTitle( const std::string& short_title ) applyTitle(); } -std::string LLFloater::getShortTitle() +std::string LLFloater::getShortTitle() const { if (mShortTitle.empty()) { @@ -834,8 +826,6 @@ std::string LLFloater::getShortTitle() } } - - BOOL LLFloater::canSnapTo(const LLView* other_view) { if (NULL == other_view) @@ -1051,6 +1041,10 @@ void LLFloater::setMinimized(BOOL minimize) reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), TRUE ); } + // don't show the help button while minimized - it's + // not very useful when minimized and uses up space + mButtonsEnabled[BUTTON_HELP] = !minimize; + applyTitle (); make_ui_sound("UISndWindowClose"); @@ -1387,28 +1381,6 @@ void LLFloater::setDocked(bool docked, bool pop_on_undock) } } -//static -void LLFloater::setEditModeEnabled(BOOL enable) -{ - if (enable != sEditModeEnabled) - { - S32 count = 0; - for(handle_map_iter_t iter = sFloaterMap.begin(); iter != sFloaterMap.end(); ++iter) - { - LLFloater* floater = iter->second; - if (!floater->isDead()) - { - iter->second->mButtonsEnabled[BUTTON_EDIT] = enable; - iter->second->updateButtons(); - } - count++; - } - } - - sEditModeEnabled = enable; -} - - // static void LLFloater::onClickMinimize(LLFloater* self) { @@ -1456,19 +1428,20 @@ void LLFloater::onClickTearOff(LLFloater* self) } // static -void LLFloater::onClickEdit(LLFloater* self) +void LLFloater::onClickDock(LLFloater* self) { - if (!self) - return; - self->mEditing = self->mEditing ? FALSE : TRUE; + if(self && self->mCanDock) + { + self->setDocked(!self->mDocked, true); + } } // static -void LLFloater::onClickDock(LLFloater* self) +void LLFloater::onClickHelp( LLFloater* self ) { - if(self && self->mCanDock) + if (self && LLUI::sHelpImpl) { - self->setDocked(!self->mDocked, true); + LLUI::sHelpImpl->showTopic(self->getHelpTopic()); } } @@ -1807,17 +1780,9 @@ void LLFloater::buildButtons() // Selected, no matter if hovered or not, is "pressed" p.image_selected.name(sButtonPressedImageNames[i]); p.image_hover_selected.name(sButtonPressedImageNames[i]); - // Empty string means programmatic glow effect, achieved by - // not setting explicit image. - if (sButtonHoveredImageNames[i].empty()) - { - // These icons are really small, need glow amount increased - p.hover_glow_amount( 0.22f ); - } - else - { - p.image_hover_unselected.name(sButtonHoveredImageNames[i]); - } + // Use a glow effect when the user hovers over the button + // These icons are really small, need glow amount increased + p.hover_glow_amount( 0.33f ); p.click_callback.function(boost::bind(sButtonCallbacks[i], this)); p.tab_stop(false); p.follows.flags(FOLLOWS_TOP|FOLLOWS_RIGHT); diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 513f6a6918..2a31ba4e8f 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -101,9 +101,9 @@ public: BUTTON_RESTORE, BUTTON_MINIMIZE, BUTTON_TEAR_OFF, - BUTTON_EDIT, BUTTON_DOCK, BUTTON_UNDOCK, + BUTTON_HELP, BUTTON_COUNT }; @@ -173,9 +173,9 @@ public: void applyTitle(); const std::string& getCurrentTitle() const; void setTitle( const std::string& title); - std::string getTitle(); + std::string getTitle() const; void setShortTitle( const std::string& short_title ); - std::string getShortTitle(); + std::string getShortTitle() const; void setTitleVisible(bool visible); virtual void setMinimized(BOOL b); void moveResizeHandlesToFront(); @@ -256,12 +256,10 @@ public: static void onClickClose(LLFloater* floater); static void onClickMinimize(LLFloater* floater); static void onClickTearOff(LLFloater* floater); - static void onClickEdit(LLFloater* floater); static void onClickDock(LLFloater* floater); + static void onClickHelp(LLFloater* floater); static void setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; } - static void setEditModeEnabled(BOOL enable); - static BOOL getEditModeEnabled() { return sEditModeEnabled; } static LLMultiFloater* getFloaterHost() {return sHostp; } protected: @@ -331,7 +329,6 @@ private: BOOL mFirstLook; // TRUE if the _next_ time this floater is visible will be the first time in the session that it is visible. - BOOL mEditing; typedef std::set<LLHandle<LLFloater> > handle_set_t; typedef std::set<LLHandle<LLFloater> >::iterator handle_set_iter_t; @@ -350,11 +347,8 @@ private: bool mDocked; static LLMultiFloater* sHostp; - static BOOL sEditModeEnabled; static BOOL sQuitting; static std::string sButtonActiveImageNames[BUTTON_COUNT]; - // Images to use when cursor hovered over an enabled button - static std::string sButtonHoveredImageNames[BUTTON_COUNT]; static std::string sButtonPressedImageNames[BUTTON_COUNT]; static std::string sButtonNames[BUTTON_COUNT]; static std::string sButtonToolTips[BUTTON_COUNT]; diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index ab9b59e252..279cbaa923 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -41,11 +41,6 @@ const F32 FOCUS_FADE_TIME = 0.3f; // NOTE: the LLFocusableElement implementation has been moved here from lluictrl.cpp. LLFocusableElement::LLFocusableElement() -: mFocusLostCallback(NULL), - mFocusReceivedCallback(NULL), - mFocusChangedCallback(NULL), - mTopLostCallback(NULL), - mFocusCallbackUserData(NULL) { } @@ -68,35 +63,19 @@ LLFocusableElement::~LLFocusableElement() void LLFocusableElement::onFocusReceived() { - if( mFocusReceivedCallback ) - { - mFocusReceivedCallback( this, mFocusCallbackUserData ); - } - if( mFocusChangedCallback ) - { - mFocusChangedCallback( this, mFocusCallbackUserData ); - } + mFocusReceivedCallback(this); + mFocusChangedCallback(this); } void LLFocusableElement::onFocusLost() { - if( mFocusLostCallback ) - { - mFocusLostCallback( this, mFocusCallbackUserData ); - } - - if( mFocusChangedCallback ) - { - mFocusChangedCallback( this, mFocusCallbackUserData ); - } + mFocusLostCallback(this); + mFocusChangedCallback(this); } void LLFocusableElement::onTopLost() { - if (mTopLostCallback) - { - mTopLostCallback(this, mFocusCallbackUserData); - } + mTopLostCallback(this); } BOOL LLFocusableElement::hasFocus() const @@ -188,12 +167,9 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL view_handle_list_t new_focus_list; // walk up the tree to root and add all views to the new_focus_list - for (LLView* ctrl = dynamic_cast<LLView*>(mKeyboardFocus); ctrl && ctrl != LLUI::getRootView(); ctrl = ctrl->getParent()) + for (LLView* ctrl = dynamic_cast<LLView*>(mKeyboardFocus); ctrl; ctrl = ctrl->getParent()) { - if (ctrl) - { - new_focus_list.push_back(ctrl->getHandle()); - } + new_focus_list.push_back(ctrl->getHandle()); } // remove all common ancestors since their focus is unchanged @@ -216,10 +192,6 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL { mCachedKeyboardFocusList.pop_front(); old_focus_view->onFocusLost(); - - // part of fix of EXT-996 - // this need to handle event when user click inside in-world area - mFocusChangeSignal(); } } diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index 2c2dae216a..2fa4e124fb 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -54,11 +54,12 @@ public: virtual void setFocus( BOOL b ); virtual BOOL hasFocus() const; - typedef boost::function<void(LLFocusableElement*, void*)> focus_callback_t; - void setFocusLostCallback(focus_callback_t cb, void* user_data = NULL) { mFocusLostCallback = cb; mFocusCallbackUserData = user_data; } - void setFocusReceivedCallback(focus_callback_t cb, void* user_data = NULL) { mFocusReceivedCallback = cb; mFocusCallbackUserData = user_data; } - void setFocusChangedCallback(focus_callback_t cb, void* user_data = NULL ) { mFocusChangedCallback = cb; mFocusCallbackUserData = user_data; } - void setTopLostCallback(focus_callback_t cb, void* user_data = NULL ) { mTopLostCallback = cb; mFocusCallbackUserData = user_data; } + typedef boost::signals2::signal<void(LLFocusableElement*)> focus_signal_t; + + boost::signals2::connection setFocusLostCallback( const focus_signal_t::slot_type& cb) { return mFocusLostCallback.connect(cb);} + boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb) { return mFocusReceivedCallback.connect(cb);} + boost::signals2::connection setFocusChangedCallback(const focus_signal_t::slot_type& cb) { return mFocusChangedCallback.connect(cb);} + void setTopLostCallback(const focus_signal_t::slot_type& cb) { mTopLostCallback.connect(cb);} // These were brought up the hierarchy from LLView so that we don't have to use dynamic_cast when dealing with keyboard focus. virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); @@ -68,11 +69,10 @@ protected: virtual void onFocusReceived(); virtual void onFocusLost(); virtual void onTopLost(); // called when registered as top ctrl and user clicks elsewhere - focus_callback_t mFocusLostCallback; - focus_callback_t mFocusReceivedCallback; - focus_callback_t mFocusChangedCallback; - focus_callback_t mTopLostCallback; - void* mFocusCallbackUserData; + focus_signal_t mFocusLostCallback; + focus_signal_t mFocusReceivedCallback; + focus_signal_t mFocusChangedCallback; + focus_signal_t mTopLostCallback; }; @@ -124,11 +124,6 @@ public: void unlockFocus(); BOOL focusLocked() const { return mLockedView != NULL; } - void addFocusChangeCallback(const boost::signals2::signal<void ()>::slot_type& cb) - { - mFocusChangeSignal.connect(cb); - } - private: LLUICtrl* mLockedView; @@ -155,8 +150,6 @@ private: typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t; focus_history_map_t mFocusHistory; - boost::signals2::signal<void()> mFocusChangeSignal; - #ifdef _DEBUG std::string mMouseCaptorName; std::string mKeyboardFocusName; diff --git a/indra/llui/llhelp.h b/indra/llui/llhelp.h new file mode 100644 index 0000000000..c06d29a4bd --- /dev/null +++ b/indra/llui/llhelp.h @@ -0,0 +1,45 @@ +/** + * @file llhelp.h + * @brief Abstract interface to the Help system + * @author Tofu Linden + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLHELP_H +#define LL_LLHELP_H + +class LLHelp +{ + public: + virtual void showTopic(const std::string &topic) = 0; + // return default (fallback) topic name suitable for showTopic() + virtual std::string defaultTopic() = 0; +}; + +#endif // headerguard diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index 01a3b5fdc7..0fbb7ced54 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -140,7 +140,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p) params.prevalidate_callback(&LLLineEditor::prevalidateFloat); params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); mEditor = LLUICtrlFactory::create<LLLineEditor> (params); - mEditor->setFocusReceivedCallback( &LLMultiSliderCtrl::onEditorGainFocus ); + mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) ); // don't do this, as selecting the entire text is single clicking in some cases // and double clicking in others //mEditor->setSelectAllonFocusReceived(TRUE); diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 26136e0a23..b9bbb4db22 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -80,6 +80,7 @@ LLPanel::Params::Params() strings("string"), filename("filename"), class_name("class"), + help_topic("help_topic"), visible_callback("visible_callback") { name = "panel"; @@ -98,6 +99,7 @@ LLPanel::LLPanel(const LLPanel::Params& p) mDefaultBtn(NULL), mBorder(NULL), mLabel(p.label), + mHelpTopic(p.help_topic), mCommitCallbackRegistrar(false), mEnableCallbackRegistrar(false), mXMLFilename(p.filename) @@ -416,6 +418,7 @@ void LLPanel::initFromParams(const LLPanel::Params& p) } setLabel(p.label()); + setHelpTopic(p.help_topic); setShape(p.rect); parseFollowsFlags(p); diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index 81b5b68f05..8b23ea7030 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -83,6 +83,7 @@ public: Optional<std::string> filename; Optional<std::string> class_name; + Optional<std::string> help_topic; Multiple<LocalizedString> strings; @@ -139,10 +140,11 @@ public: void updateDefaultBtn(); void setLabel(const LLStringExplicit& label) { mLabel = label; } std::string getLabel() const { return mLabel; } + void setHelpTopic(const std::string& help_topic) { mHelpTopic = help_topic; } + std::string getHelpTopic() const { return mHelpTopic; } void setCtrlsEnabled(BOOL b); - LLHandle<LLPanel> getHandle() const { return mPanelHandle; } const LLCallbackMap::map_t& getFactoryMap() const { return mFactoryMap; } @@ -243,6 +245,8 @@ protected: EnableCallbackRegistry::ScopedRegistrar mEnableCallbackRegistrar; commit_signal_t mVisibleSignal; // Called when visibility changes, passes new visibility as LLSD() + + std::string mHelpTopic; // the name of this panel's help topic to display in the Help Viewer private: LLUIColor mBgColorAlpha; @@ -259,7 +263,7 @@ private: // for setting the xml filename when building panel in context dependent cases std::string mXMLFilename; - + }; // end class LLPanel #endif diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index 7e72331a3f..7e88b16561 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -130,12 +130,6 @@ public: void onLineUpBtnPressed(const LLSD& data); void onLineDownBtnPressed(const LLSD& data); - void setBGColor(const LLUIColor& color) { mBGColor = color; } - const LLUIColor& getBGColor() const { return mBGColor; } - - void setBGVisible() { mBGVisible = true; } - bool getBGVisible() const { return mBGVisible; } - private: void updateThumbRect(); void changeLine(S32 delta, BOOL update_thumb ); diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index 15584c8dc7..fb71b60725 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -143,7 +143,7 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p) line_p.prevalidate_callback(&LLLineEditor::prevalidateFloat); mEditor = LLUICtrlFactory::create<LLLineEditor>(line_p); - mEditor->setFocusReceivedCallback( &LLSliderCtrl::onEditorGainFocus, this ); + mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this )); // don't do this, as selecting the entire text is single clicking in some cases // and double clicking in others //mEditor->setSelectAllonFocusReceived(TRUE); diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp index 3a96bc8f93..83d71006aa 100644 --- a/indra/llui/llspinctrl.cpp +++ b/indra/llui/llspinctrl.cpp @@ -142,7 +142,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p) params.prevalidate_callback(&LLLineEditor::prevalidateFloat); params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); mEditor = LLUICtrlFactory::create<LLLineEditor> (params); - mEditor->setFocusReceivedCallback( &LLSpinCtrl::onEditorGainFocus, this ); + mEditor->setFocusReceivedCallback( boost::bind(&LLSpinCtrl::onEditorGainFocus, _1, this )); //RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus // than when it doesn't. Instead, if you always have to double click to select all the text, // it's easier to understand diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 8d5f277b59..39f09b297f 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2001,6 +2001,8 @@ void LLTextEditor::cut() deleteSelection( FALSE ); needsReflow(); + + onKeyStroke(); } BOOL LLTextEditor::canCopy() const @@ -2105,6 +2107,8 @@ void LLTextEditor::pasteHelper(bool is_primary) deselect(); needsReflow(); + + onKeyStroke(); } @@ -2492,6 +2496,8 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) if(text_may_have_changed) { needsReflow(); + + onKeyStroke(); } needsScroll(); } @@ -2534,6 +2540,8 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char) deselect(); needsReflow(); + + onKeyStroke(); } return handled; @@ -2588,6 +2596,8 @@ void LLTextEditor::doDelete() setCursorPos(mCursorPos + 1); removeChar(); } + + onKeyStroke(); } needsReflow(); @@ -2634,6 +2644,8 @@ void LLTextEditor::undo() setCursorPos(pos); needsReflow(); + + onKeyStroke(); } BOOL LLTextEditor::canRedo() const @@ -2676,6 +2688,8 @@ void LLTextEditor::redo() setCursorPos(pos); needsReflow(); + + onKeyStroke(); } void LLTextEditor::onFocusReceived() @@ -4402,6 +4416,8 @@ void LLTextEditor::updatePreedit(const LLWString &preedit_string, // Update of the preedit should be caused by some key strokes. mKeystrokeTimer.reset(); + + onKeyStroke(); } BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const @@ -4648,3 +4664,30 @@ void LLInlineViewSegment::linkToDocument(LLTextBase* editor) ed->addDocumentChild(mView); } } + +BOOL LLTextEditor::isDirty() const +{ + if(mReadOnly) + { + return FALSE; + } + + if( mPristineCmd ) + { + return ( mPristineCmd == mLastCmd ); + } + else + { + return ( NULL != mLastCmd ); + } +} + +void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& callback) +{ + mKeystrokeSignal.connect(callback); +} + +void LLTextEditor::onKeyStroke() +{ + mKeystrokeSignal(this); +} diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 68b8f2c3b1..a04261c4be 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -139,6 +139,10 @@ public: virtual ~LLTextEditor(); + typedef boost::signals2::signal<void (LLTextEditor* caller)> keystroke_signal_t; + + void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); + void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} // mousehandler overrides @@ -169,7 +173,7 @@ public: virtual void clear(); virtual void setFocus( BOOL b ); virtual BOOL acceptsTextInput() const; - virtual BOOL isDirty() const { return isPristine(); } + virtual BOOL isDirty() const; virtual void setValue(const LLSD& value); // LLEditMenuHandler interface @@ -503,6 +507,8 @@ private: S32 getFirstVisibleLine() const; + void onKeyStroke(); + // // Data // @@ -568,6 +574,8 @@ private: BOOL mHandleEditKeysDirectly; LLCoordGL mLastIMEPosition; // Last position of the IME editor + + keystroke_signal_t mKeystrokeSignal; }; // end class LLTextEditor diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 000e85f78c..d5b67f53b7 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -79,10 +79,10 @@ std::list<std::string> gUntranslated; /*static*/ LLUIAudioCallback LLUI::sAudioCallback = NULL; /*static*/ LLVector2 LLUI::sGLScaleFactor(1.f, 1.f); /*static*/ LLWindow* LLUI::sWindow = NULL; -/*static*/ LLHtmlHelp* LLUI::sHtmlHelp = NULL; /*static*/ LLView* LLUI::sRootView = NULL; -/*static*/ BOOL LLUI::sDirty = FALSE; -/*static*/ LLRect LLUI::sDirtyRect; +/*static*/ BOOL LLUI::sDirty = FALSE; +/*static*/ LLRect LLUI::sDirtyRect; +/*static*/ LLHelp* LLUI::sHelpImpl = NULL; /*static*/ std::vector<std::string> LLUI::sXUIPaths; /*static*/ LLFrameTimer LLUI::sMouseIdleTimer; @@ -695,44 +695,6 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre } -void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect) -{ - if (NULL == image) - { - llwarns << "image == NULL; aborting function" << llendl; - return; - } - - LLGLSUIDefault gls_ui; - - gGL.pushMatrix(); - { - gGL.translatef((F32)x, (F32)y, 0.f); - - gGL.getTexUnit(0)->bind(image); - - gGL.color4fv(color.mV); - - gGL.begin(LLRender::QUADS); - { - gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom); - gGL.vertex2i(width, height ); - - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom); - gGL.vertex2i(0, height ); - - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop); - gGL.vertex2i(0, 0); - - gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop); - gGL.vertex2i(width, 0); - } - gGL.end(); - } - gGL.popMatrix(); -} - - void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase ) { phase = fmod(phase, 1.f); @@ -1592,6 +1554,9 @@ void LLUI::initClass(const settings_map_t& settings, // Button initialization callback for toggle buttons LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2)); + // Display the help topic for the current context + LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2)); + // Currently unused, but kept for reference: LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2)); @@ -1850,12 +1815,6 @@ LLPointer<LLUIImage> LLUI::getUIImage(const std::string& name) return NULL; } -// static -void LLUI::setHtmlHelp(LLHtmlHelp* html_help) -{ - LLUI::sHtmlHelp = html_help; -} - LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname) { for (settings_map_t::iterator itor = sSettingGroups.begin(); diff --git a/indra/llui/llui.h b/indra/llui/llui.h index fddf8192ad..86cb516500 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -57,13 +57,13 @@ #include "llfontgl.h" class LLColor4; -class LLHtmlHelp; class LLVector3; class LLVector2; class LLUIImage; class LLUUID; class LLWindow; class LLView; +class LLHelp; // UI colors extern const LLColor4 UI_VERTEX_COLOR; @@ -104,8 +104,6 @@ void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LL void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); -// Flip vertical, used for LLFloaterHTML -void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); void gl_rect_2d_xor(S32 left, S32 top, S32 right, S32 bottom); void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase = 0.f ); @@ -203,7 +201,6 @@ public: static void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y); static void screenRectToGL(const LLRect& screen, LLRect *gl); static void glRectToScreen(const LLRect& gl, LLRect *screen); - static void setHtmlHelp(LLHtmlHelp* html_help); // Returns the control group containing the control name, or the default group static LLControlGroup& getControlControlGroup (const std::string& controlname); static F32 getMouseIdleTime() { return sMouseIdleTimer.getElapsedTimeF32(); } @@ -223,8 +220,8 @@ public: static LLUIAudioCallback sAudioCallback; static LLVector2 sGLScaleFactor; static LLWindow* sWindow; - static LLHtmlHelp* sHtmlHelp; static LLView* sRootView; + static LLHelp* sHelpImpl; private: static LLImageProviderInterface* sImageProvider; static std::vector<std::string> sXUIPaths; diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 8807e26f6b..fe99d9c267 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -114,7 +114,6 @@ void LLUICtrl::initFromParams(const Params& p) } setTabStop(p.tab_stop); - setFocusLostCallback(p.focus_lost_callback()); if (p.initial_value.isProvided() && !p.control_name.isProvided()) @@ -763,6 +762,27 @@ LLUICtrl* LLUICtrl::getParentUICtrl() const return NULL; } +bool LLUICtrl::findHelpTopic(std::string& help_topic_out) +{ + LLUICtrl* ctrl = this; + + // search back through the control's parents for a panel + // with a help_topic string defined + while (ctrl) + { + LLPanel *panel = dynamic_cast<LLPanel *>(ctrl); + if (panel && !panel->getHelpTopic().empty()) + { + help_topic_out = panel->getHelpTopic(); + return true; // success + } + + ctrl = ctrl->getParentUICtrl(); + } + + return false; // no help topic found +} + // *TODO: Deprecate; for backwards compatability only: boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data) { @@ -800,14 +820,7 @@ namespace LLInitParam return false; } - template<> - bool ParamCompare<LLUICtrl::focus_callback_t>::equals( - const LLUICtrl::focus_callback_t &a, - const LLUICtrl::focus_callback_t &b) - { - return false; - } - + template<> bool ParamCompare<LLUICtrl::enable_callback_t>::equals( const LLUICtrl::enable_callback_t &a, diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 3add9393ea..c2502732f3 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -124,8 +124,6 @@ public: Optional<CommitCallbackParam> mouseenter_callback; Optional<CommitCallbackParam> mouseleave_callback; - Optional<focus_callback_t> focus_lost_callback; - Optional<std::string> control_name; Optional<EnableControls> enabled_controls; Optional<ControlVisibility> controls_visibility; @@ -225,6 +223,10 @@ public: LLUICtrl* getParentUICtrl() const; + // return true if help topic found by crawling through parents - + // topic then put in help_topic_out + bool findHelpTopic(std::string& help_topic_out); + boost::signals2::connection setCommitCallback( const commit_signal_t::slot_type& cb ) { return mCommitSignal.connect(cb); } boost::signals2::connection setValidateCallback( const enable_signal_t::slot_type& cb ) { return mValidateSignal.connect(cb); } @@ -309,11 +311,6 @@ namespace LLInitParam const LLUICtrl::enable_callback_t &a, const LLUICtrl::enable_callback_t &b); - template<> - bool ParamCompare<LLUICtrl::focus_callback_t>::equals( - const LLUICtrl::focus_callback_t &a, - const LLUICtrl::focus_callback_t &b); - template<> bool ParamCompare<LLLazyValue<LLColor4> >::equals( const LLLazyValue<LLColor4> &a, const LLLazyValue<LLColor4> &b); diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index 3b689b93c0..f3401f91f7 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -134,4 +134,3 @@ void LLUrlAction::copyLabelToClipboard(std::string url) LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel())); } } - diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 256c776293..10cb3fb377 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -466,16 +466,6 @@ LLRect LLView::getRequiredRect() return mRect; } -//virtual -void LLView::onFocusLost() -{ -} - -//virtual -void LLView::onFocusReceived() -{ -} - BOOL LLView::focusNextRoot() { LLView::child_list_t result = LLView::getFocusRootsQuery().run(this); diff --git a/indra/llui/llview.h b/indra/llui/llview.h index bf3b5d0614..7a37d6f430 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -405,10 +405,6 @@ public: BOOL getSaveToXML() const { return mSaveToXML; } void setSaveToXML(BOOL b) { mSaveToXML = b; } - // inherited from LLFocusableElement - /* virtual */ void onFocusLost(); - /* virtual */ void onFocusReceived(); - typedef enum e_hit_test_type { HIT_TEST_USE_BOUNDING_RECT, diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index 24efcb8ae8..7a531e0fbf 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -383,7 +383,7 @@ BOOL LLDir_Linux::fileExists(const std::string &filename) const /*virtual*/ std::string LLDir_Linux::getLLPluginLauncher() { - return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + "SLPlugin"; } diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp index 9be787df11..346f7dd8ed 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -424,7 +424,7 @@ BOOL LLDir_Mac::fileExists(const std::string &filename) const /*virtual*/ std::string LLDir_Mac::getLLPluginLauncher() { - return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + return gDirUtilp->getAppRODataDir() + gDirUtilp->getDirDelimiter() + "SLPlugin"; } diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 872f2cf1c1..3e302764de 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -397,7 +397,7 @@ BOOL LLDir_Win32::fileExists(const std::string &filename) const /*virtual*/ std::string LLDir_Win32::getLLPluginLauncher() { - return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + "SLPlugin.exe"; } diff --git a/indra/lscript/lscript_compile/CMakeLists.txt b/indra/lscript/lscript_compile/CMakeLists.txt index 252085bab2..3ed2892e0e 100644 --- a/indra/lscript/lscript_compile/CMakeLists.txt +++ b/indra/lscript/lscript_compile/CMakeLists.txt @@ -5,6 +5,7 @@ include(LLCommon) include(LLMath) include(LLMessage) include(LLInventory) +include(LLPrimitive) include(LScript) include(FindCygwin) @@ -41,6 +42,7 @@ include_directories( ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} + ${LLPRIMITIVE_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS} ) diff --git a/indra/lscript/lscript_compile/indra.l b/indra/lscript/lscript_compile/indra.l index 9cc2841e8c..8c891b3e8f 100644 --- a/indra/lscript/lscript_compile/indra.l +++ b/indra/lscript/lscript_compile/indra.l @@ -34,6 +34,7 @@ FS (f|F) #include "llregionflags.h" #include "lscript_http.h" #include "llclickaction.h" +#include "llmediaentry.h" void count(); void line_comment(); @@ -233,7 +234,8 @@ extern "C" { int yyerror(const char *fmt, ...); } "CHANGED_OWNER" { count(); yylval.ival = CHANGED_OWNER; return(INTEGER_CONSTANT); } "CHANGED_REGION" { count(); yylval.ival = CHANGED_REGION; return(INTEGER_CONSTANT); } "CHANGED_TELEPORT" { count(); yylval.ival = CHANGED_TELEPORT; return(INTEGER_CONSTANT); } -"CHANGED_REGION_START" { count(); yylval.ival = CHANGED_REGION_START; return(INTEGER_CONSTANT); } +"CHANGED_REGION_START" { count(); yylval.ival = CHANGED_REGION_START; return(INTEGER_CONSTANT); } +"CHANGED_MEDIA" { count(); yylval.ival = CHANGED_MEDIA; return(INTEGER_CONSTANT); } "OBJECT_UNKNOWN_DETAIL" { count(); yylval.ival = OBJECT_UNKNOWN_DETAIL; return(INTEGER_CONSTANT); } "OBJECT_NAME" { count(); yylval.ival = OBJECT_NAME; return(INTEGER_CONSTANT); } @@ -622,6 +624,45 @@ extern "C" { int yyerror(const char *fmt, ...); } "TOUCH_INVALID_VECTOR" { count(); return(TOUCH_INVALID_VECTOR); } "TOUCH_INVALID_TEXCOORD" { count(); return(TOUCH_INVALID_TEXCOORD); } +"PRIM_MEDIA_ALT_IMAGE_ENABLE" { count(); yylval.ival = LLMediaEntry::ALT_IMAGE_ENABLE_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_CONTROLS" { count(); yylval.ival = LLMediaEntry::CONTROLS_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_CURRENT_URL" { count(); yylval.ival = LLMediaEntry::CURRENT_URL_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_HOME_URL" { count(); yylval.ival = LLMediaEntry::HOME_URL_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_AUTO_LOOP" { count(); yylval.ival = LLMediaEntry::AUTO_LOOP_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_AUTO_PLAY" { count(); yylval.ival = LLMediaEntry::AUTO_PLAY_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_AUTO_SCALE" { count(); yylval.ival = LLMediaEntry::AUTO_SCALE_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_AUTO_ZOOM" { count(); yylval.ival = LLMediaEntry::AUTO_ZOOM_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_FIRST_CLICK_INTERACT" { count(); yylval.ival = LLMediaEntry::FIRST_CLICK_INTERACT_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_WIDTH_PIXELS" { count(); yylval.ival = LLMediaEntry::WIDTH_PIXELS_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_HEIGHT_PIXELS" { count(); yylval.ival = LLMediaEntry::HEIGHT_PIXELS_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_WHITELIST_ENABLE" { count(); yylval.ival = LLMediaEntry::WHITELIST_ENABLE_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_WHITELIST" { count(); yylval.ival = LLMediaEntry::WHITELIST_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PERMS_INTERACT" { count(); yylval.ival = LLMediaEntry::PERMS_INTERACT_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PERMS_CONTROL" { count(); yylval.ival = LLMediaEntry::PERMS_CONTROL_ID; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PARAM_MAX" { count(); yylval.ival = LLMediaEntry::PARAM_MAX_ID; return(INTEGER_CONSTANT); } + +"PRIM_MEDIA_CONTROLS_STANDARD" { count(); yylval.ival = LLMediaEntry::STANDARD; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_CONTROLS_MINI" { count(); yylval.ival = LLMediaEntry::MINI; return(INTEGER_CONSTANT); } + +"PRIM_MEDIA_PERM_NONE" { count(); yylval.ival = LLMediaEntry::PERM_NONE; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PERM_OWNER" { count(); yylval.ival = LLMediaEntry::PERM_OWNER; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PERM_GROUP" { count(); yylval.ival = LLMediaEntry::PERM_GROUP; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_PERM_ANYONE" { count(); yylval.ival = LLMediaEntry::PERM_ANYONE; return(INTEGER_CONSTANT); } + +"PRIM_MEDIA_MAX_URL_LENGTH" { count(); yylval.ival = LLMediaEntry::MAX_URL_LENGTH; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_MAX_WHITELIST_SIZE" { count(); yylval.ival = LLMediaEntry::MAX_WHITELIST_SIZE; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_MAX_WHITELIST_COUNT" { count(); yylval.ival = LLMediaEntry::MAX_WHITELIST_COUNT; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_MAX_WIDTH_PIXELS" { count(); yylval.ival = LLMediaEntry::MAX_WIDTH_PIXELS; return(INTEGER_CONSTANT); } +"PRIM_MEDIA_MAX_HEIGHT_PIXELS" { count(); yylval.ival = LLMediaEntry::MAX_HEIGHT_PIXELS; return(INTEGER_CONSTANT); } + +"STATUS_OK" { count(); yylval.ival = LSL_STATUS_OK; return(INTEGER_CONSTANT); } +"STATUS_MALFORMED_PARAMS" { count(); yylval.ival = LSL_STATUS_MALFORMED_PARAMS; return(INTEGER_CONSTANT); } +"STATUS_TYPE_MISMATCH" { count(); yylval.ival = LSL_STATUS_TYPE_MISMATCH; return(INTEGER_CONSTANT); } +"STATUS_BOUNDS_ERROR" { count(); yylval.ival = LSL_STATUS_BOUNDS_ERROR; return(INTEGER_CONSTANT); } +"STATUS_NOT_FOUND" { count(); yylval.ival = LSL_STATUS_NOT_FOUND; return(INTEGER_CONSTANT); } +"STATUS_NOT_SUPPORTED" { count(); yylval.ival = LSL_STATUS_NOT_SUPPORTED; return(INTEGER_CONSTANT); } +"STATUS_INTERNAL_ERROR" { count(); yylval.ival = LSL_STATUS_INTERNAL_ERROR; return(INTEGER_CONSTANT); } +"STATUS_WHITELIST_FAILED" { count(); yylval.ival = LSL_STATUS_WHITELIST_FAILED; return(INTEGER_CONSTANT); } {L}({L}|{N})* { count(); yylval.sval = new char[strlen(yytext) + 1]; strcpy(yylval.sval, yytext); return(IDENTIFIER); } diff --git a/indra/lscript/lscript_library/lscript_library.cpp b/indra/lscript/lscript_library/lscript_library.cpp index 0d51c27c92..5e394644c2 100644 --- a/indra/lscript/lscript_library/lscript_library.cpp +++ b/indra/lscript/lscript_library/lscript_library.cpp @@ -450,7 +450,12 @@ void LLScriptLibrary::init() addFunction(10.f, 0.f, dummy_func, "llHTTPResponse", NULL, "kis"); addFunction(10.f, 0.f, dummy_func, "llGetHTTPHeader", "s", "ks"); - // energy, sleep, dummy_func, name, return type, parameters, gods-only + // Prim media (see lscript_prim_media.h) + addFunction(10.f, 1.0f, dummy_func, "llSetPrimMediaParams", "i", "il"); + addFunction(10.f, 1.0f, dummy_func, "llGetPrimMediaParams", "l", "il"); + addFunction(10.f, 1.0f, dummy_func, "llClearPrimMedia", "i", "i"); + + // energy, sleep, dummy_func, name, return type, parameters, help text, gods-only // IF YOU ADD NEW SCRIPT CALLS, YOU MUST PUT THEM AT THE END OF THIS LIST. // Otherwise the bytecode numbers for each call will be wrong, and all @@ -495,7 +500,7 @@ void LLScriptLibData::print(std::ostream &s, BOOL b_prepend_comma) s << ", "; } switch (mType) - { + { case LST_INTEGER: s << mInteger; break; diff --git a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp index 647db7a5bf..a4c43988ba 100644 --- a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp +++ b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp @@ -975,10 +975,7 @@ void MediaPluginGStreamer010::receiveMessage(const char *message_string) else if(message_name == "shm_added") { SharedSegmentInfo info; - U64 address_lo = message_in.getValueU32("address"); - U64 address_hi = message_in.hasValue("address_1") ? message_in.getValueU32("address_1") : 0; - info.mAddress = (void*)((address_lo) | - (address_hi * (U64(1)<<31))); + info.mAddress = message_in.getValuePointer("address"); info.mSize = (size_t)message_in.getValueS32("size"); std::string name = message_in.getValue("name"); diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp index e9be458960..fbda65120d 100644 --- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp +++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp @@ -772,10 +772,7 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string) else if(message_name == "shm_added") { SharedSegmentInfo info; - U64 address_lo = message_in.getValueU32("address"); - U64 address_hi = message_in.hasValue("address_1") ? message_in.getValueU32("address_1") : 0; - info.mAddress = (void*)((address_lo) | - (address_hi * (U64(1)<<31))); + info.mAddress = message_in.getValuePointer("address"); info.mSize = (size_t)message_in.getValueS32("size"); std::string name = message_in.getValue("name"); diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 2928b7e6b3..eb2457744a 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -147,8 +147,11 @@ private: #if LL_WINDOWS // Enable plugins - LLQtWebKit::getInstance()->enablePlugins(true); -#else + LLQtWebKit::getInstance()->enablePlugins(false); +#elif LL_DARWIN + // Disable plugins + LLQtWebKit::getInstance()->enablePlugins(false); +#elif LL_LINUX // Disable plugins LLQtWebKit::getInstance()->enablePlugins(false); #endif @@ -164,6 +167,11 @@ private: // don't flip bitmap LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); + + // Set the background color to black + LLQtWebKit::getInstance()-> + // set background color to be black - mostly for initial login page + LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, 0x00, 0x00, 0x00 ); // go to the "home page" // Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. @@ -483,8 +491,8 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) mDepth = 4; message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); - message.setValueS32("default_width", 800); - message.setValueS32("default_height", 600); + message.setValueS32("default_width", 1024); + message.setValueS32("default_height", 1024); message.setValueS32("depth", mDepth); message.setValueU32("internalformat", GL_RGBA); message.setValueU32("format", GL_RGBA); @@ -507,10 +515,7 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) else if(message_name == "shm_added") { SharedSegmentInfo info; - U64 address_lo = message_in.getValueU32("address"); - U64 address_hi = message_in.hasValue("address_1") ? message_in.getValueU32("address_1") : 0; - info.mAddress = (void*)((address_lo) | - (address_hi * (U64(1)<<31))); + info.mAddress = message_in.getValuePointer("address"); info.mSize = (size_t)message_in.getValueS32("size"); std::string name = message_in.getValue("name"); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7b707a6720..4482a75405 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -169,9 +169,9 @@ set(viewer_SOURCE_FILES llfloatergroups.cpp llfloaterhandler.cpp llfloaterhardwaresettings.cpp - llfloaterhtmlcurrency.cpp + llfloaterhelpbrowser.cpp llfloatermediabrowser.cpp - llfloaterhtmlsimple.cpp + llfloatermediasettings.cpp llfloaterhud.cpp llfloaterimagepreview.cpp llfloaterinspect.cpp @@ -208,6 +208,7 @@ set(viewer_SOURCE_FILES llfloaterurlentry.cpp llfloatervoicedevicesettings.cpp llfloaterwater.cpp + llfloaterwhitelistentry.cpp llfloaterwindlight.cpp llfloaterworldmap.cpp llfoldertype.cpp @@ -260,6 +261,9 @@ set(viewer_SOURCE_FILES llmanipscale.cpp llmaniptranslate.cpp llmapresponders.cpp + llmediactrl.cpp + llmediadataresponder.cpp + llmediadatafetcher.cpp llmediaremotectrl.cpp llmemoryview.cpp llmenucommands.cpp @@ -321,6 +325,9 @@ set(viewer_SOURCE_FILES llpanelmediahud.cpp llpanelmeprofile.cpp llpanelmovetip.cpp + llpanelmediasettingsgeneral.cpp + llpanelmediasettingssecurity.cpp + llpanelmediasettingspermissions.cpp llpanelobject.cpp llpanelpeople.cpp llpanelpeoplemenus.cpp @@ -426,6 +433,8 @@ set(viewer_SOURCE_FILES llviewerfloaterreg.cpp llviewergenericmessage.cpp llviewergesture.cpp + llviewerhelp.cpp + llviewerhelputil.cpp llviewerinventory.cpp llviewerjointattachment.cpp llviewerjoint.cpp @@ -490,7 +499,6 @@ set(viewer_SOURCE_FILES llwearabledictionary.cpp llwearablelist.cpp llweb.cpp - llmediactrl.cpp llwind.cpp llwlanimator.cpp llwldaycycle.cpp @@ -632,9 +640,9 @@ set(viewer_HEADER_FILES llfloatergroups.h llfloaterhandler.h llfloaterhardwaresettings.h - llfloaterhtmlcurrency.h + llfloaterhelpbrowser.h llfloatermediabrowser.h - llfloaterhtmlsimple.h + llfloatermediasettings.h llfloaterhud.h llfloaterimagepreview.h llfloaterinspect.h @@ -671,6 +679,7 @@ set(viewer_HEADER_FILES llfloaterurlentry.h llfloatervoicedevicesettings.h llfloaterwater.h + llfloaterwhitelistentry.h llfloaterwindlight.h llfloaterworldmap.h llfoldertype.h @@ -723,6 +732,8 @@ set(viewer_HEADER_FILES llmanipscale.h llmaniptranslate.h llmapresponders.h + llmediadataresponder.h + llmediadatafetcher.h llmediaremotectrl.h llmemoryview.h llmenucommands.h @@ -781,6 +792,9 @@ set(viewer_HEADER_FILES llpanelmediahud.h llpanelmeprofile.h llpanelmovetip.h + llpanelmediasettingsgeneral.h + llpanelmediasettingssecurity.h + llpanelmediasettingspermissions.h llpanelobject.h llpanelpeople.h llpanelpeoplemenus.h @@ -891,6 +905,7 @@ set(viewer_HEADER_FILES llviewerfloaterreg.h llviewergenericmessage.h llviewergesture.h + llviewerhelp.h llviewerinventory.h llviewerjoint.h llviewerjointattachment.h @@ -1526,6 +1541,7 @@ endif (INSTALL) include(LLAddBuildTest) SET(viewer_TEST_SOURCE_FILES llagentaccess.cpp + llviewerhelputil.cpp ) set_source_files_properties( ${viewer_TEST_SOURCE_FILES} @@ -1565,7 +1581,7 @@ if (WINDOWS) -E copy_if_different ${BUILT_SLPLUGIN} - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} COMMENT "Copying SLPlugin executable to the runtime folder." ) diff --git a/indra/newview/app_settings/keywords.ini b/indra/newview/app_settings/keywords.ini index eaf5213985..5d52158298 100644 --- a/indra/newview/app_settings/keywords.ini +++ b/indra/newview/app_settings/keywords.ini @@ -40,14 +40,14 @@ not_at_rot_target not_at_rot_target():Result of LLRotTarget library function cal money money(key id, integer amount):Triggered when L$ is given to task email email(string time, string address, string subj, string message, integer num_left):Triggered when task receives email run_time_permissions run_time_permissions(integer perm):Triggered when an agent grants run time permissions to task -attach attach(key id):Triggered when an agent attaches or detaches from agent +attach attach(key id):Triggered when task attaches or detaches from agent dataserver dataserver(key queryid, string data):Triggered when task receives asynchronous data moving_start moving_start():Triggered when task begins moving moving_end moving_end():Triggered when task stops moving on_rez on_rez(integer start_param):Triggered when task is rezed in from inventory or another task object_rez object_rez(key id):Triggered when task rezes in another task link_message link_message(integer sender_num, integer num, string str, key id):Triggered when task receives a link message via LLMessageLinked library function call -changed changed( integer change ):Triggered various event change the task:(test change with CHANGED_INVENTORY, CHANGED_COLOR, CHANGED_SHAPE, CHANGED_SCALE, CHANGED_TEXTURE, CHANGED_LINK, CHANGED_ALLOWED_DROP, CHANGED_OWNER, CHANGED_REGION, CHANGED_TELEPORT) +changed changed( integer change ):Triggered various event change the task:(test change with CHANGED_INVENTORY, CHANGED_COLOR, CHANGED_SHAPE, CHANGED_SCALE, CHANGED_TEXTURE, CHANGED_LINK, CHANGED_ALLOWED_DROP, CHANGED_OWNER, CHANGED_REGION, CHANGED_TELEPORT, CHANGED_REGION_START, CHANGED_MEDIA) remote_data remote_data(integer event_type, key channel, key message_id, string sender,integer idata, string sdata):Triggered by various XML-RPC calls (event_type will be one of REMOTE_DATA_CHANNEL, REMOTE_DATA_REQUEST, REMOTE_DATA_REPLY) http_response http_response(key request_id, integer status, list metadata, string body):Triggered when task receives a response to one of its llHTTPRequests http_request http_request(key id, string method, string body):Triggered when task receives an http request against a public URL @@ -320,6 +320,7 @@ CHANGED_OWNER Parameter of changed event handler used to indicate change to tas CHANGED_REGION Parameter of changed event handler used to indicate the region has changed CHANGED_TELEPORT Parameter of changed event handler used to indicate teleport has completed CHANGED_REGION_START Parameter of changed event handler used to indicate the region has been restarted +CHANGED_MEDIA Parameter of changed event handler used to indicate that media has changed on a face of the task TYPE_INTEGER Indicates that the list entry is holding an integer TYPE_FLOAT Indicates that the list entry is holding an float @@ -513,6 +514,46 @@ TOUCH_INVALID_TEXCOORD Value returned by llDetectedTouchUV() and llDetectedTouc TOUCH_INVALID_VECTOR Value returned by llDetectedTouchPos(), llDetectedTouchNormal(), and llDetectedTouchBinormal() when the touch position is not valid. TOUCH_INVALID_FACE Value returned by llDetectedTouchFace() when the touch position is not valid. +PRIM_MEDIA_ALT_IMAGE_ENABLE Used with ll{Get,Set}PrimMediaParams to enable the default alt image for media +PRIM_MEDIA_CONTROLS Used with ll{Get,Set}PrimMediaParams to determine the controls shown for media +PRIM_MEDIA_CURRENT_URL Used with ll{Get,Set}PrimMediaParams to navigate/access the current URL +PRIM_MEDIA_HOME_URL Used with ll{Get,Set}PrimMediaParams to access the home URL +PRIM_MEDIA_AUTO_LOOP Used with ll{Get,Set}PrimMediaParams to determine if media should auto-loop (if applicable) +PRIM_MEDIA_AUTO_PLAY Used with ll{Get,Set}PrimMediaParams to determine if media should start playing as soon as it is created +PRIM_MEDIA_AUTO_SCALE Used with ll{Get,Set}PrimMediaParams to determine if media should scale to fit the face it is on +PRIM_MEDIA_AUTO_ZOOM Used with ll{Get,Set}PrimMediaParams to determine if the user would zoom in when viewing media +PRIM_MEDIA_FIRST_CLICK_INTERACT Used with ll{Get,Set}PrimMediaParams to determine whether the user interacts with media or not when she first clicks it (versus selection) +PRIM_MEDIA_WIDTH_PIXELS Used with ll{Get,Set}PrimMediaParams to access the media's width in pixels +PRIM_MEDIA_HEIGHT_PIXELS Used with ll{Get,Set}PrimMediaParams to access the media's height in pixels +PRIM_MEDIA_WHITELIST_ENABLE Used with ll{Get,Set}PrimMediaParams to determine if the domain whitelist is enabled +PRIM_MEDIA_WHITELIST Used with ll{Get,Set}PrimMediaParams to access the media's list of allowable URL prefixes to navigate to +PRIM_MEDIA_PERMS_INTERACT Used with ll{Get,Set}PrimMediaParams to determine the permissions for who can interact with the media +PRIM_MEDIA_PERMS_CONTROL Used with ll{Get,Set}PrimMediaParams to determine the permissions for who has controls +PRIM_MEDIA_PARAM_MAX The value of the largest media param + +PRIM_MEDIA_CONTROLS_STANDARD Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_CONTROLS value meaning "standard controls" +PRIM_MEDIA_CONTROLS_MINI Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_CONTROLS value meaning "mini controls" + +PRIM_MEDIA_PERM_NONE Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_PERMS_INTERACT or PRIM_MEDIA_PERMS_CONTROL bit, no permissions +PRIM_MEDIA_PERM_OWNER Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_PERMS_INTERACT or PRIM_MEDIA_PERMS_CONTROL bit, owner permissions +PRIM_MEDIA_PERM_GROUP Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_PERMS_INTERACT or PRIM_MEDIA_PERMS_CONTROL bit, group permissions +PRIM_MEDIA_PERM_ANYONE Used with ll{Get,Set}PrimMediaParams, a PRIM_MEDIA_PERMS_INTERACT or PRIM_MEDIA_PERMS_CONTROL bit, anyone has permissions + +PRIM_MEDIA_MAX_URL_LENGTH Used with ll{Get,Set}PrimMediaParams, the maximum length of PRIM_MEDIA_CURRENT_URL or PRIM_MEDIA_HOME_URL +PRIM_MEDIA_MAX_WHITELIST_SIZE Used with ll{Get,Set}PrimMediaParams, the maximum length, in bytes, of PRIM_MEDIA_WHITELIST +PRIM_MEDIA_MAX_WHITELIST_COUNT Used with ll{Get,Set}PrimMediaParams, the maximum number of items allowed in PRIM_MEDIA_WHITELIST +PRIM_MEDIA_MAX_WIDTH_PIXELS Used with ll{Get,Set}PrimMediaParams, the maximum width allowed in PRIM_MEDIA_WIDTH_PIXELS +PRIM_MEDIA_MAX_HEIGHT_PIXELS Used with ll{Get,Set}PrimMediaParams, the maximum width allowed in PRIM_MEDIA_HEIGHT_PIXELS + +STATUS_OK Result of function call was success +STATUS_MALFORMED_PARAMS Function was called with malformed params +STATUS_TYPE_MISMATCH Argument(s) passed to function had a type mismatch +STATUS_BOUNDS_ERROR Argument(s) passed to function had a bounds error +STATUS_NOT_FOUND Object or other item was not found +STATUS_NOT_SUPPORTED Feature not supported +STATUS_INTERNAL_ERROR An internal error occurred +STATUS_WHITELIST_FAILED URL failed to pass whitelist + # string constants [word .1, .3, .5] NULL_KEY Indicates an empty key diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 19d503390c..99b662a63f 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3542,28 +3542,28 @@ <string>S32</string> <key>Value</key> <integer>400</integer> - </map> - <key>HelpHomeURL</key> + </map> + <key>HelpUseLocal</key> <map> <key>Comment</key> - <string>URL of initial help page</string> + <string>If set, always use this for help: skins/default/html/[LANGUAGE]/help-offline/index.html</string> <key>Persist</key> - <integer>1</integer> + <integer>0</integer> <key>Type</key> - <string>String</string> + <string>Boolean</string> <key>Value</key> - <string>help/index.html</string> + <integer>0</integer> </map> - <key>HelpLastVisitedURL</key> + <key>HelpURLFormat</key> <map> <key>Comment</key> - <string>URL of last help page, will be shown next time help is accessed</string> + <string>URL pattern for help page; arguments will be encoded; see llviewerhelp.cpp:buildHelpURL for arguments</string> <key>Persist</key> - <integer>1</integer> + <integer>0</integer> <key>Type</key> <string>String</string> <key>Value</key> - <string>help/index.html</string> + <string>http://www.google.com/search?q=site%3Awiki.secondlife.com+[TOPIC]&ignore_channel=[CHANNEL]&ignore_version=[VERSION]&ignore_os=[OS]&ignore_language=[LANGUAGE]&ignore_version_major=[VERSION_MAJOR]&ignore_version_minor=[VERSION_MINOR]&ignore_version_patch=[VERSION_PATCH]&ignore_version_build=[VERSION_BUILD]</string> </map> <key>HighResSnapshot</key> <map> @@ -3994,6 +3994,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>LastMediaSettingsTab</key> + <map> + <key>Comment</key> + <string>Last selected tab in media settings window</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>0</integer> + </map> <key>LastRunVersion</key> <map> <key>Comment</key> @@ -4455,7 +4466,7 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>0</integer> + <integer>1</integer> </map> <key>MemoryLogFrequency</key> <map> @@ -5216,6 +5227,51 @@ <key>Value</key> <integer>1</integer> </map> + + <key>PluginInstancesCPULimit</key> + <map> + <key>Comment</key> + <string>Amount of total plugin CPU usage before inworld plugins start getting turned down to "slideshow" priority. Set to 0 to disable this check.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.0</real> + </map> + <key>PluginInstancesLow</key> + <map> + <key>Comment</key> + <string>Limit on the number of inworld media plugins that will run at "low" priority</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>4</integer> + </map> + <key>PluginInstancesNormal</key> + <map> + <key>Comment</key> + <string>Limit on the number of inworld media plugins that will run at "normal" priority</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>4</integer> + </map> + <key>PluginInstancesTotal</key> + <map> + <key>Comment</key> + <string>Hard limit on the number of plugins that will be instantiated at once</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>16</integer> + </map> <key>PrecachingDelay</key> <map> <key>Comment</key> @@ -5238,6 +5294,28 @@ <key>Value</key> <integer>13</integer> </map> + <key>PrimMediaFetchQueueDelay</key> + <map> + <key>Comment</key> + <string>Timer delay for fetching media from the queue (in seconds).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.0</real> + </map> + <key>PrimMediaRetryTimerDelay</key> + <map> + <key>Comment</key> + <string>Timer delay for retrying on media queries (in seconds).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>5.0</real> + </map> <key>ProbeHardwareOnStartup</key> <map> <key>Comment</key> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 355660faa5..30e0a5770c 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -67,6 +67,7 @@ #include "llviewerobjectlist.h" #include "llworldmap.h" #include "llmutelist.h" +#include "llviewerhelp.h" #include "lluicolortable.h" #include "llurldispatcher.h" #include "llurlhistory.h" @@ -663,8 +664,6 @@ bool LLAppViewer::init() mNumSessions++; gSavedSettings.setS32("NumSessions", mNumSessions); - gSavedSettings.setString("HelpLastVisitedURL",gSavedSettings.getString("HelpHomeURL")); - if (gSavedSettings.getBOOL("VerboseLogs")) { LLError::setPrintLocation(true); @@ -694,6 +693,9 @@ bool LLAppViewer::init() LLUrlAction::setOpenURLExternalCallback(&LLWeb::loadURLExternal); LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); + // Let code in llui access the viewer help floater + LLUI::sHelpImpl = LLViewerHelp::getInstance(); + // Set the link color for any Urls in text fields LLTextBase::setLinkColor( LLUIColorTable::instance().getColor("HTMLLinkColor") ); diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index ee14a2ff86..36f9780ad0 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -41,6 +41,10 @@ static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list"); +// Maximum number of avatars that can be added to a list in one pass. +// Used to limit time spent for avatar list update per frame. +static const unsigned ADD_LIMIT = 50; + static bool findInsensitive(std::string haystack, const std::string& needle_upper) { LLStringUtil::toUpper(haystack); @@ -65,6 +69,7 @@ LLAvatarList::LLAvatarList(const Params& p) : LLFlatListView(p) , mOnlineGoFirst(p.online_go_first) , mContextMenu(NULL) +, mDirty(true) // to force initial update { setCommitOnSelectionChange(true); @@ -72,44 +77,40 @@ LLAvatarList::LLAvatarList(const Params& p) setComparator(&NAME_COMPARATOR); } -void LLAvatarList::computeDifference( - const std::vector<LLUUID>& vnew_unsorted, - std::vector<LLUUID>& vadded, - std::vector<LLUUID>& vremoved) +// virtual +void LLAvatarList::draw() { - std::vector<LLUUID> vcur; - std::vector<LLUUID> vnew = vnew_unsorted; + if (mDirty) + refresh(); - // Convert LLSDs to LLUUIDs. - { - std::vector<LLSD> vcur_values; - getValues(vcur_values); + LLFlatListView::draw(); +} - for (size_t i=0; i<vcur_values.size(); i++) - vcur.push_back(vcur_values[i].asUUID()); +void LLAvatarList::setNameFilter(const std::string& filter) +{ + if (mNameFilter != filter) + { + mNameFilter = filter; + setDirty(); } +} - std::sort(vcur.begin(), vcur.end()); - std::sort(vnew.begin(), vnew.end()); - - std::vector<LLUUID>::iterator it; - size_t maxsize = llmax(vcur.size(), vnew.size()); - vadded.resize(maxsize); - vremoved.resize(maxsize); - - // what to remove - it = set_difference(vcur.begin(), vcur.end(), vnew.begin(), vnew.end(), vremoved.begin()); - vremoved.erase(it, vremoved.end()); - - // what to add - it = set_difference(vnew.begin(), vnew.end(), vcur.begin(), vcur.end(), vadded.begin()); - vadded.erase(it, vadded.end()); +void LLAvatarList::sortByName() +{ + setComparator(&NAME_COMPARATOR); + sort(); } -BOOL LLAvatarList::update(const std::vector<LLUUID>& all_buddies, const std::string& name_filter) +////////////////////////////////////////////////////////////////////////// +// PROTECTED SECTION +////////////////////////////////////////////////////////////////////////// + +void LLAvatarList::refresh() { - BOOL have_names = TRUE; - bool have_filter = name_filter != LLStringUtil::null; + bool have_names = TRUE; + bool add_limit_exceeded = false; + bool modified = false; + bool have_filter = !mNameFilter.empty(); // Save selection. std::vector<LLUUID> selected_ids; @@ -118,22 +119,36 @@ BOOL LLAvatarList::update(const std::vector<LLUUID>& all_buddies, const std::str // Determine what to add and what to remove. std::vector<LLUUID> added, removed; - LLAvatarList::computeDifference(all_buddies, added, removed); + LLAvatarList::computeDifference(getIDs(), added, removed); // Handle added items. + unsigned nadded = 0; for (std::vector<LLUUID>::const_iterator it=added.begin(); it != added.end(); it++) { std::string name; const LLUUID& buddy_id = *it; - have_names &= gCacheName->getFullName(buddy_id, name); - if (!have_filter || findInsensitive(name, name_filter)) - addNewItem(buddy_id, name, LLAvatarTracker::instance().isBuddyOnline(buddy_id)); + have_names &= (bool)gCacheName->getFullName(buddy_id, name); + if (!have_filter || findInsensitive(name, mNameFilter)) + { + if (nadded >= ADD_LIMIT) + { + add_limit_exceeded = true; + break; + } + else + { + addNewItem(buddy_id, name, LLAvatarTracker::instance().isBuddyOnline(buddy_id)); + modified = true; + nadded++; + } + } } // Handle removed items. for (std::vector<LLUUID>::const_iterator it=removed.begin(); it != removed.end(); it++) { removeItemByUUID(*it); + modified = true; } // Handle filter. @@ -146,9 +161,12 @@ BOOL LLAvatarList::update(const std::vector<LLUUID>& all_buddies, const std::str { std::string name; const LLUUID& buddy_id = it->asUUID(); - have_names &= gCacheName->getFullName(buddy_id, name); - if (!findInsensitive(name, name_filter)) + have_names &= (bool)gCacheName->getFullName(buddy_id, name); + if (!findInsensitive(name, mNameFilter)) + { removeItemByUUID(buddy_id); + modified = true; + } } } @@ -167,18 +185,15 @@ BOOL LLAvatarList::update(const std::vector<LLUUID>& all_buddies, const std::str // // Otherwise, if we have no filter then no need to update again // because the items will update their names. - return !have_filter || have_names; -} + bool dirty = add_limit_exceeded || (have_filter && !have_names); + setDirty(dirty); -void LLAvatarList::sortByName() -{ - setComparator(&NAME_COMPARATOR); - sort(); + // Commit if we've added/removed items. + if (modified) + onCommit(); } -////////////////////////////////////////////////////////////////////////// -// PROTECTED SECTION -////////////////////////////////////////////////////////////////////////// + void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_bold, EAddPosition pos) { LLAvatarListItem* item = new LLAvatarListItem(); @@ -194,8 +209,39 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is addItem(item, id, pos); } +void LLAvatarList::computeDifference( + const std::vector<LLUUID>& vnew_unsorted, + std::vector<LLUUID>& vadded, + std::vector<LLUUID>& vremoved) +{ + std::vector<LLUUID> vcur; + std::vector<LLUUID> vnew = vnew_unsorted; + // Convert LLSDs to LLUUIDs. + { + std::vector<LLSD> vcur_values; + getValues(vcur_values); + for (size_t i=0; i<vcur_values.size(); i++) + vcur.push_back(vcur_values[i].asUUID()); + } + + std::sort(vcur.begin(), vcur.end()); + std::sort(vnew.begin(), vnew.end()); + + std::vector<LLUUID>::iterator it; + size_t maxsize = llmax(vcur.size(), vnew.size()); + vadded.resize(maxsize); + vremoved.resize(maxsize); + + // what to remove + it = set_difference(vcur.begin(), vcur.end(), vnew.begin(), vnew.end(), vremoved.begin()); + vremoved.erase(it, vremoved.end()); + + // what to add + it = set_difference(vnew.begin(), vnew.end(), vcur.begin(), vcur.end(), vadded.begin()); + vadded.erase(it, vadded.end()); +} bool LLAvatarItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const { diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index 8d79e073d2..ec801645fe 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -37,10 +37,22 @@ #include "llavatarlistitem.h" +/** + * Generic list of avatars. + * + * Updates itself when it's dirty, using optional name filter. + * To initiate update, modify the UUID list and call setDirty(). + * + * @see getIDs() + * @see setDirty() + * @see setNameFilter() + */ class LLAvatarList : public LLFlatListView { LOG_CLASS(LLAvatarList); public: + typedef std::vector<LLUUID> uuid_vector_t; + struct Params : public LLInitParam::Block<Params, LLFlatListView::Params> { Optional<S32> volume_column_width; @@ -51,14 +63,19 @@ public: LLAvatarList(const Params&); virtual ~LLAvatarList() {} - BOOL update(const std::vector<LLUUID>& all_buddies, - const std::string& name_filter = LLStringUtil::null); + virtual void draw(); // from LLView + + void setNameFilter(const std::string& filter); + void setDirty(bool val = true) { mDirty = val; } + uuid_vector_t& getIDs() { return mIDs; } void setContextMenu(LLAvatarListItem::ContextMenu* menu) { mContextMenu = menu; } void sortByName(); protected: + void refresh(); + void addNewItem(const LLUUID& id, const std::string& name, BOOL is_bold, EAddPosition pos = ADD_BOTTOM); void computeDifference( const std::vector<LLUUID>& vnew, @@ -68,6 +85,10 @@ protected: private: bool mOnlineGoFirst; + bool mDirty; + + std::string mNameFilter; + uuid_vector_t mIDs; LLAvatarListItem::ContextMenu* mContextMenu; }; diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index 46151b469f..8771611b1c 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -133,6 +133,7 @@ LLIMChiclet* LLBottomTray::createIMChiclet(const LLUUID& session_id) case LLIMChiclet::TYPE_IM: return getChicletPanel()->createChiclet<LLIMP2PChiclet>(session_id); case LLIMChiclet::TYPE_GROUP: + case LLIMChiclet::TYPE_AD_HOC: return getChicletPanel()->createChiclet<LLIMGroupChiclet>(session_id); case LLIMChiclet::TYPE_UNKNOWN: break; @@ -231,7 +232,7 @@ void LLBottomTray::showBottomTrayContextMenu(S32 x, S32 y, MASK mask) mBottomTrayContextMenu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, mBottomTrayContextMenu, x, y); - } + } } void LLBottomTray::showGestureButton(BOOL visible) @@ -243,7 +244,7 @@ void LLBottomTray::showGestureButton(BOOL visible) mGestureCombo->setVisible(visible); if (!visible) - { + { LLFloaterReg::hideFloaterInstance("gestures"); r.mRight -= mGestureCombo->getRect().getWidth(); } diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp index 7ae9976338..c4619dc57a 100644 --- a/indra/newview/llchannelmanager.cpp +++ b/indra/newview/llchannelmanager.cpp @@ -77,7 +77,7 @@ LLScreenChannel* LLChannelManager::createNotificationChannel() p.channel_align = CA_RIGHT; // Getting a Channel for our notifications - return LLChannelManager::getInstance()->getChannel(p); + return dynamic_cast<LLScreenChannel*> (LLChannelManager::getInstance()->getChannel(p)); } //-------------------------------------------------------------------------- @@ -113,7 +113,7 @@ void LLChannelManager::onLoginCompleted() LLChannelManager::Params p; p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID")); p.channel_align = CA_RIGHT; - mStartUpChannel = getChannel(p); + mStartUpChannel = createChannel(p); if(!mStartUpChannel) { @@ -147,22 +147,32 @@ void LLChannelManager::onStartUpToastClose() LLScreenChannel::setStartUpToastShown(); // force NEARBY CHAT CHANNEL to repost all toasts if present - LLScreenChannel* nearby_channel = findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); - nearby_channel->loadStoredToastsToChannel(); - nearby_channel->setCanStoreToasts(false); + //LLScreenChannelBase* nearby_channel = findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); + //!!!!!!!!!!!!!! + //FIXME + //nearby_channel->loadStoredToastsToChannel(); + //nearby_channel->setCanStoreToasts(false); } //-------------------------------------------------------------------------- -LLScreenChannel* LLChannelManager::getChannel(LLChannelManager::Params& p) + +LLScreenChannelBase* LLChannelManager::addChannel(LLScreenChannelBase* channel) { - LLScreenChannel* new_channel = NULL; + if(!channel) + return 0; - new_channel = findChannelByID(p.id); + ChannelElem new_elem; + new_elem.id = channel->getChannelID(); + new_elem.channel = channel; - if(new_channel) - return new_channel; + mChannelList.push_back(new_elem); - new_channel = new LLScreenChannel(p.id); + return channel; +} + +LLScreenChannel* LLChannelManager::createChannel(LLChannelManager::Params& p) +{ + LLScreenChannel* new_channel = new LLScreenChannel(p.id); if(!new_channel) { @@ -172,20 +182,26 @@ LLScreenChannel* LLChannelManager::getChannel(LLChannelManager::Params& p) { new_channel->setToastAlignment(p.toast_align); new_channel->setChannelAlignment(p.channel_align); - new_channel->setDisplayToastsAlways(p.display_toasts_always); - - ChannelElem new_elem; - new_elem.id = p.id; - new_elem.channel = new_channel; + new_channel->setDisplayToastsAlways(p.display_toasts_always); - mChannelList.push_back(new_elem); + addChannel(new_channel); } - return new_channel; } +LLScreenChannelBase* LLChannelManager::getChannel(LLChannelManager::Params& p) +{ + LLScreenChannelBase* new_channel = findChannelByID(p.id); + + if(new_channel) + return new_channel; + + return createChannel(p); + +} + //-------------------------------------------------------------------------- -LLScreenChannel* LLChannelManager::findChannelByID(const LLUUID id) +LLScreenChannelBase* LLChannelManager::findChannelByID(const LLUUID id) { std::vector<ChannelElem>::iterator it = find(mChannelList.begin(), mChannelList.end(), id); if(it != mChannelList.end()) diff --git a/indra/newview/llchannelmanager.h b/indra/newview/llchannelmanager.h index 811fa06d2b..b927d369cd 100644 --- a/indra/newview/llchannelmanager.h +++ b/indra/newview/llchannelmanager.h @@ -52,8 +52,8 @@ class LLChannelManager : public LLSingleton<LLChannelManager> public: struct Params { - LLUUID id; - bool display_toasts_always; + LLUUID id; + bool display_toasts_always; EToastAlignment toast_align; EChannelAlignment channel_align; @@ -64,7 +64,7 @@ public: struct ChannelElem { LLUUID id; - LLScreenChannel* channel; + LLScreenChannelBase* channel; ChannelElem() : id(LLUUID("")), channel(NULL) { } @@ -89,19 +89,23 @@ public: void onStartUpToastClose(); // creates a new ScreenChannel according to the given parameters or returns existing if present - LLScreenChannel* getChannel(LLChannelManager::Params& p); + LLScreenChannelBase* getChannel(LLChannelManager::Params& p); + + LLScreenChannelBase* addChannel(LLScreenChannelBase* channel); // returns a channel by its ID - LLScreenChannel* findChannelByID(const LLUUID id); + LLScreenChannelBase* findChannelByID(const LLUUID id); // creator of the Notification channel, that is used in more than one handler - LLScreenChannel* createNotificationChannel(); + LLScreenChannel* createNotificationChannel(); // remove channel methods void removeChannelByID(const LLUUID id); private: + LLScreenChannel* createChannel(LLChannelManager::Params& p); + LLScreenChannel* mStartUpChannel; std::vector<ChannelElem> mChannelList; }; diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 96c707b08f..4523267edd 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -125,8 +125,8 @@ BOOL LLChatBar::postBuild() mInputEditor = getChild<LLLineEditor>("Chat Editor"); mInputEditor->setKeystrokeCallback(&onInputEditorKeystroke, this); - mInputEditor->setFocusLostCallback(&onInputEditorFocusLost, this); - mInputEditor->setFocusReceivedCallback( &onInputEditorGainFocus, this ); + mInputEditor->setFocusLostCallback(boost::bind(&LLChatBar::onInputEditorFocusLost)); + mInputEditor->setFocusReceivedCallback(boost::bind(&LLChatBar::onInputEditorGainFocus)); mInputEditor->setCommitOnFocusLost( FALSE ); mInputEditor->setRevertOnEsc( FALSE ); mInputEditor->setIgnoreTab(TRUE); @@ -538,14 +538,14 @@ void LLChatBar::onInputEditorKeystroke( LLLineEditor* caller, void* userdata ) } // static -void LLChatBar::onInputEditorFocusLost( LLFocusableElement* caller, void* userdata) +void LLChatBar::onInputEditorFocusLost() { // stop typing animation gAgent.stopTyping(); } // static -void LLChatBar::onInputEditorGainFocus( LLFocusableElement* caller, void* userdata ) +void LLChatBar::onInputEditorGainFocus() { LLFloaterChat::setHistoryCursorAndScrollToEnd(); } diff --git a/indra/newview/llchatbar.h b/indra/newview/llchatbar.h index a41947218d..86aa3ebd2a 100644 --- a/indra/newview/llchatbar.h +++ b/indra/newview/llchatbar.h @@ -87,8 +87,8 @@ public: static void onTabClick( void* userdata ); static void onInputEditorKeystroke(LLLineEditor* caller, void* userdata); - static void onInputEditorFocusLost(LLFocusableElement* caller,void* userdata); - static void onInputEditorGainFocus(LLFocusableElement* caller,void* userdata); + static void onInputEditorFocusLost(); + static void onInputEditorGainFocus(); void onCommitGesture(LLUICtrl* ctrl); diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 6fb6552f2d..c2d7e0d935 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -44,6 +44,7 @@ #include "llviewercontrol.h" #include "llagentdata.h" +/* static const S32 BORDER_MARGIN = 2; static const S32 PARENT_BORDER_MARGIN = 0; @@ -53,33 +54,27 @@ static const F32 MIN_AUTO_SCROLL_RATE = 120.f; static const F32 MAX_AUTO_SCROLL_RATE = 500.f; static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f; -static const S32 msg_left_offset = 30; -static const S32 msg_right_offset = 10; - #define MAX_CHAT_HISTORY 100 +*/ +static const S32 msg_left_offset = 30; +static const S32 msg_right_offset = 10; -static LLDefaultChildRegistry::Register<LLChatItemsContainerCtrl> t2("chat_items_container"); - - +//static LLDefaultChildRegistry::Register<LLChatItemsContainerCtrl> t2("chat_items_container"); //******************************************************************************************************************* //LLChatItemCtrl //******************************************************************************************************************* -LLChatItemCtrl* LLChatItemCtrl::createInstance() +LLNearbyChatToastPanel* LLNearbyChatToastPanel::createInstance() { - LLChatItemCtrl* item = new LLChatItemCtrl(); + LLNearbyChatToastPanel* item = new LLNearbyChatToastPanel(); LLUICtrlFactory::getInstance()->buildPanel(item, "panel_chat_item.xml"); + item->setFollows(FOLLOWS_NONE); return item; } -void LLChatItemCtrl::draw() -{ - LLPanel::draw(); -} - -void LLChatItemCtrl::reshape (S32 width, S32 height, BOOL called_from_parent ) +void LLNearbyChatToastPanel::reshape (S32 width, S32 height, BOOL called_from_parent ) { LLPanel::reshape(width, height,called_from_parent); @@ -101,13 +96,13 @@ void LLChatItemCtrl::reshape (S32 width, S32 height, BOOL called_from_parent ) } } -BOOL LLChatItemCtrl::postBuild() +BOOL LLNearbyChatToastPanel::postBuild() { return LLPanel::postBuild(); } -std::string LLChatItemCtrl::appendTime() +std::string LLNearbyChatToastPanel::appendTime() { time_t utc_time; utc_time = time_corrected(); @@ -124,48 +119,63 @@ std::string LLChatItemCtrl::appendTime() -void LLChatItemCtrl::addText (const std::string& message) +void LLNearbyChatToastPanel::addText (const std::string& message) { LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false); msg_text->addText(message); mMessages.push_back(message); } -void LLChatItemCtrl::setMessage (const LLChat& msg) +void LLNearbyChatToastPanel::init(LLSD& notification) { LLPanel* caption = getChild<LLPanel>("msg_caption", false); + mText = notification["message"].asString(); // UTF-8 line of text + mFromName = notification["from"].asString(); // agent or object name + mFromID = notification["from_id"].asUUID(); // agent id or object id + int sType = notification["source"].asInteger(); + mSourceType = (EChatSourceType)sType; + std::string str_sender; - - if(gAgentID != msg.mFromID) - str_sender = msg.mFromName; + if(gAgentID != mFromID) + str_sender = mFromName; else str_sender = LLTrans::getString("You");; caption->getChild<LLTextBox>("sender_name", false)->setText(str_sender); - std::string tt = appendTime(); - - caption->getChild<LLTextBox>("msg_time", false)->setText(tt); - - - caption->getChild<LLAvatarIconCtrl>("avatar_icon", false)->setValue(msg.mFromID); + caption->getChild<LLTextBox>("msg_time", false)->setText(appendTime()); - mOriginalMessage = msg; LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false); - msg_text->setText(msg.mText); + msg_text->setText(mText); LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); - if(mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + if(mSourceType != CHAT_SOURCE_AGENT) msg_inspector->setVisible(false); mMessages.clear(); + snapToMessageHeight (); + + mIsDirty = true;//will set Avatar Icon in draw +} + +void LLNearbyChatToastPanel::setMessage (const LLChat& chat_msg) +{ + LLSD notification; + notification["message"] = chat_msg.mText; + notification["from"] = chat_msg.mFromName; + notification["from_id"] = chat_msg.mFromID; + notification["time"] = chat_msg.mTime; + notification["source"] = (S32)chat_msg.mSourceType; + + init(notification); + } -void LLChatItemCtrl::snapToMessageHeight () +void LLNearbyChatToastPanel::snapToMessageHeight () { LLChatMsgBox* text_box = getChild<LLChatMsgBox>("msg_text", false); S32 new_height = text_box->getTextPixelHeight(); @@ -184,14 +194,14 @@ void LLChatItemCtrl::snapToMessageHeight () } -void LLChatItemCtrl::setWidth(S32 width) +void LLNearbyChatToastPanel::setWidth(S32 width) { LLChatMsgBox* text_box = getChild<LLChatMsgBox>("msg_text", false); text_box->reshape(width - msg_left_offset - msg_right_offset,100/*its not magic number, we just need any number*/); LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false); - if(mOriginalMessage.mText.length()) - msg_text->setText(mOriginalMessage.mText); + if(mText.length()) + msg_text->setText(mText); for(size_t i=0;i<mMessages.size();++i) msg_text->addText(mMessages[i]); @@ -200,25 +210,25 @@ void LLChatItemCtrl::setWidth(S32 width) snapToMessageHeight (); } -void LLChatItemCtrl::onMouseLeave (S32 x, S32 y, MASK mask) +void LLNearbyChatToastPanel::onMouseLeave (S32 x, S32 y, MASK mask) { LLPanel* caption = getChild<LLPanel>("msg_caption", false); LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); msg_inspector->setVisible(false); } -void LLChatItemCtrl::onMouseEnter (S32 x, S32 y, MASK mask) +void LLNearbyChatToastPanel::onMouseEnter (S32 x, S32 y, MASK mask) { - if(mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + if(mSourceType != CHAT_SOURCE_AGENT) return; LLPanel* caption = getChild<LLPanel>("msg_caption", false); LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); msg_inspector->setVisible(true); } -BOOL LLChatItemCtrl::handleMouseDown (S32 x, S32 y, MASK mask) +BOOL LLNearbyChatToastPanel::handleMouseDown (S32 x, S32 y, MASK mask) { - if(mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + if(mSourceType != CHAT_SOURCE_AGENT) return LLPanel::handleMouseDown(x,y,mask); LLPanel* caption = getChild<LLPanel>("msg_caption", false); LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); @@ -226,12 +236,16 @@ BOOL LLChatItemCtrl::handleMouseDown (S32 x, S32 y, MASK mask) S32 local_y = y - msg_inspector->getRect().mBottom - caption->getRect().mBottom; if(msg_inspector->pointInView(local_x, local_y)) { - LLFloaterReg::showInstance("inspect_avatar", mOriginalMessage.mFromID); + LLFloaterReg::showInstance("inspect_avatar", mFromID); + } + else + { + LLFloaterReg::showInstance("nearby_chat",LLSD()); } return LLPanel::handleMouseDown(x,y,mask); } -void LLChatItemCtrl::setHeaderVisibility(EShowItemHeader e) +void LLNearbyChatToastPanel::setHeaderVisibility(EShowItemHeader e) { LLPanel* caption = getChild<LLPanel>("msg_caption", false); @@ -243,7 +257,7 @@ void LLChatItemCtrl::setHeaderVisibility(EShowItemHeader e) } -bool LLChatItemCtrl::canAddText () +bool LLNearbyChatToastPanel::canAddText () { LLChatMsgBox* msg_text = findChild<LLChatMsgBox>("msg_text"); if(!msg_text) @@ -251,7 +265,7 @@ bool LLChatItemCtrl::canAddText () return msg_text->getTextLinesNum()<10; } -BOOL LLChatItemCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +BOOL LLNearbyChatToastPanel::handleRightMouseDown(S32 x, S32 y, MASK mask) { LLPanel* caption = getChild<LLPanel>("msg_caption", false); LLUICtrl* avatar_icon = caption->getChild<LLUICtrl>("avatar_icon", false); @@ -260,296 +274,20 @@ BOOL LLChatItemCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) S32 local_y = y - avatar_icon->getRect().mBottom - caption->getRect().mBottom; //eat message for avatar icon if msg was from object - if(avatar_icon->pointInView(local_x, local_y) && mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + if(avatar_icon->pointInView(local_x, local_y) && mSourceType != CHAT_SOURCE_AGENT) return TRUE; return LLPanel::handleRightMouseDown(x,y,mask); } - - -//******************************************************************************************************************* -//LLChatItemsContainerCtrl -//******************************************************************************************************************* - -LLChatItemsContainerCtrl::LLChatItemsContainerCtrl(const Params& params):LLPanel(params) -{ - mEShowItemHeader = CHATITEMHEADER_SHOW_BOTH; -} - - -void LLChatItemsContainerCtrl::addMessage(const LLChat& msg) -{ - /* - if(msg.mChatType == CHAT_TYPE_DEBUG_MSG) - return; - */ - if(mItems.size() >= MAX_CHAT_HISTORY) - { - LLChatItemCtrl* item = mItems[0]; - removeChild(item); - delete item; - mItems.erase(mItems.begin()); - } - - - if(mItems.size() > 0 - && msg.mFromID == mItems[mItems.size()-1]->getMessage().mFromID - && (msg.mTime-mItems[mItems.size()-1]->getMessage().mTime)<60 - && mItems[mItems.size()-1]->canAddText() - ) - { - mItems[mItems.size()-1]->addText(msg.mText); - mItems[mItems.size()-1]->snapToMessageHeight(); - } - else - { - LLChatItemCtrl* item = LLChatItemCtrl::createInstance(); - mItems.push_back(item); - addChild(item,0); - item->setWidth(getRect().getWidth() - 16); - item->setMessage(msg); - item->snapToMessageHeight(); - - item->setHeaderVisibility((EShowItemHeader)gSavedSettings.getS32("nearbychat_showicons_and_names")); - - item->setVisible(true); - } - - arrange(getRect().getWidth(),getRect().getHeight()); - updateLayout(getRect().getWidth(),getRect().getHeight()); - scrollToBottom(); -} - -void LLChatItemsContainerCtrl::scrollToBottom () -{ - if(mScrollbar->getVisible()) - { - mScrollbar->setDocPos(mScrollbar->getDocPosMax()); - onScrollPosChangeCallback(0,0); - } -} - -void LLChatItemsContainerCtrl::draw() -{ - LLLocalClipRect clip(getRect()); - LLPanel::draw(); -} - -void LLChatItemsContainerCtrl::reshape (S32 width, S32 height, BOOL called_from_parent ) -{ - S32 delta_width = width - getRect().getWidth(); - S32 delta_height = height - getRect().getHeight(); - - if (delta_width || delta_height || sForceReshape) - { - arrange(width, height); - } - - updateBoundingRect(); -} - -void LLChatItemsContainerCtrl::arrange (S32 width, S32 height) +void LLNearbyChatToastPanel::draw() { - S32 delta_width = width - getRect().getWidth(); - if(delta_width)//width changed...too bad. now we need to reformat all items - reformatHistoryScrollItems(width); - - calcRecuiredHeight(); - - show_hide_scrollbar(width,height); - - updateLayout(width,height); -} - -void LLChatItemsContainerCtrl::reformatHistoryScrollItems(S32 width) -{ - for(std::vector<LLChatItemCtrl*>::iterator it = mItems.begin(); it != mItems.end();++it) - { - (*it)->setWidth(width); - } -} - -S32 LLChatItemsContainerCtrl::calcRecuiredHeight () -{ - S32 rec_height = 0; - - std::vector<LLChatItemCtrl*>::iterator it; - for(it=mItems.begin(); it!=mItems.end(); ++it) - { - rec_height += (*it)->getRect().getHeight(); - } - - mInnerRect.setLeftTopAndSize(0,rec_height + BORDER_MARGIN*2,getRect().getWidth(),rec_height + BORDER_MARGIN); - - return mInnerRect.getHeight(); -} - - -void LLChatItemsContainerCtrl::updateLayout (S32 width, S32 height) -{ - S32 panel_top = height - BORDER_MARGIN ; - S32 panel_width = width; - if(mScrollbar->getVisible()) - { - static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - - panel_top+=mScrollbar->getDocPos(); - panel_width-=scrollbar_size; - } - - - //set sizes for first panels and dragbars - for(size_t i=0;i<mItems.size();++i) - { - LLRect panel_rect = mItems[i]->getRect(); - panelSetLeftTopAndSize(mItems[i],panel_rect.mLeft,panel_top,panel_width,panel_rect.getHeight()); - panel_top-=panel_rect.getHeight(); - } -} - -void LLChatItemsContainerCtrl::show_hide_scrollbar (S32 width, S32 height) -{ - calcRecuiredHeight(); - if(getRecuiredHeight() > height ) - showScrollbar(width, height); - else - hideScrollbar(width, height); -} - -void LLChatItemsContainerCtrl::showScrollbar (S32 width, S32 height) -{ - bool was_visible = mScrollbar->getVisible(); - - mScrollbar->setVisible(true); - - static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - - panelSetLeftTopAndSize(mScrollbar,width-scrollbar_size - ,height-PARENT_BORDER_MARGIN,scrollbar_size,height-2*PARENT_BORDER_MARGIN); - - mScrollbar->setPageSize(height); - mScrollbar->setDocParams(mInnerRect.getHeight(),mScrollbar->getDocPos()); - - if(was_visible) - { - S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1); - mScrollbar->setDocPos(scroll_pos); - updateLayout(width,height); - return; - } -} - -void LLChatItemsContainerCtrl::hideScrollbar (S32 width, S32 height) -{ - if(mScrollbar->getVisible() == false) - return; - mScrollbar->setVisible(false); - - mScrollbar->setDocPos(0); - - if(mItems.size()>0) - { - S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel - S32 diff = panel_top - mItems[0]->getRect().mTop; - shiftPanels(diff); - } -} - -//--------------------------------------------------------------------------------- -void LLChatItemsContainerCtrl::panelSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height) -{ - if(!panel) - return; - LLRect panel_rect = panel->getRect(); - panel_rect.setLeftTopAndSize( left, top, width, height); - panel->reshape( width, height, 1); - panel->setRect(panel_rect); -} - -void LLChatItemsContainerCtrl::panelShiftVertical(LLView* panel,S32 delta) -{ - if(!panel) - return; - panel->translate(0,delta); -} - -void LLChatItemsContainerCtrl::shiftPanels(S32 delta) -{ - //Arrange panels - for(std::vector<LLChatItemCtrl*>::iterator it = mItems.begin(); it != mItems.end();++it) - { - panelShiftVertical((*it),delta); - } - -} - -//--------------------------------------------------------------------------------- - -void LLChatItemsContainerCtrl::onScrollPosChangeCallback(S32, LLScrollbar*) -{ - updateLayout(getRect().getWidth(),getRect().getHeight()); -} - -BOOL LLChatItemsContainerCtrl::postBuild() -{ - static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - - LLRect scroll_rect; - scroll_rect.setOriginAndSize( - getRect().getWidth() - scrollbar_size, - 1, - scrollbar_size, - getRect().getHeight() - 1); - - - LLScrollbar::Params sbparams; - sbparams.name("scrollable vertical"); - sbparams.rect(scroll_rect); - sbparams.orientation(LLScrollbar::VERTICAL); - sbparams.doc_size(mInnerRect.getHeight()); - sbparams.doc_pos(0); - sbparams.page_size(mInnerRect.getHeight()); - sbparams.step_size(VERTICAL_MULTIPLE); - sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); - sbparams.change_callback(boost::bind(&LLChatItemsContainerCtrl::onScrollPosChangeCallback, this, _1, _2)); - - mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams); - LLView::addChild( mScrollbar ); - mScrollbar->setVisible( true ); - mScrollbar->setFollowsRight(); - mScrollbar->setFollowsTop(); - mScrollbar->setFollowsBottom(); - - reformatHistoryScrollItems(getRect().getWidth()); - arrange(getRect().getWidth(),getRect().getHeight()); - - return LLPanel::postBuild(); -} -BOOL LLChatItemsContainerCtrl::handleMouseDown (S32 x, S32 y, MASK mask) -{ - return LLPanel::handleMouseDown(x,y,mask); -} -BOOL LLChatItemsContainerCtrl::handleKeyHere (KEY key, MASK mask) -{ - if( mScrollbar->getVisible() && mScrollbar->handleKeyHere( key,mask ) ) - return TRUE; - return LLPanel::handleKeyHere(key,mask); -} -BOOL LLChatItemsContainerCtrl::handleScrollWheel ( S32 x, S32 y, S32 clicks ) -{ - if( mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) ) - return TRUE; - return false; -} - -void LLChatItemsContainerCtrl::setHeaderVisibility(EShowItemHeader e) -{ - if(e == mEShowItemHeader) - return; - mEShowItemHeader = e; - for(std::vector<LLChatItemCtrl*>::iterator it = mItems.begin(); it != mItems.end();++it) + if(mIsDirty) { - (*it)->setHeaderVisibility(e); + LLPanel* caption = findChild<LLPanel>("msg_caption", false); + if(caption) + caption->getChild<LLAvatarIconCtrl>("avatar_icon", false)->setValue(mFromID); + mIsDirty = false; } + LLToastPanelBase::draw(); } diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h index de16cf9505..8fb045b6d9 100644 --- a/indra/newview/llchatitemscontainerctrl.h +++ b/indra/newview/llchatitemscontainerctrl.h @@ -37,6 +37,7 @@ #include "llscrollbar.h" #include "string" #include "llchat.h" +#include "lltoastpanel.h" typedef enum e_show_item_header { @@ -45,20 +46,18 @@ typedef enum e_show_item_header CHATITEMHEADER_SHOW_BOTH } EShowItemHeader; -class LLChatItemCtrl: public LLPanel +class LLNearbyChatToastPanel: public LLToastPanelBase { protected: - LLChatItemCtrl(){}; + LLNearbyChatToastPanel():mIsDirty(false){}; public: - ~LLChatItemCtrl(){} + ~LLNearbyChatToastPanel(){} - static LLChatItemCtrl* createInstance(); + static LLNearbyChatToastPanel* createInstance(); - void draw(); - - const LLChat& getMessage() const { return mOriginalMessage;} + const LLUUID& getFromID() const { return mFromID;} void addText (const std::string& message); void setMessage (const LLChat& msg); @@ -77,78 +76,27 @@ public: void setHeaderVisibility(EShowItemHeader e); BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); -private: - - std::string appendTime (); - -private: - LLChat mOriginalMessage; - - std::vector<std::string> mMessages; -}; - -class LLChatItemsContainerCtrl: public LLPanel -{ -public: - struct Params - : public LLInitParam::Block<Params, LLPanel::Params> - { - Params(){}; - }; - - LLChatItemsContainerCtrl(const Params& params); - - - ~LLChatItemsContainerCtrl(){} - - void addMessage (const LLChat& msg); - - void draw(); - - void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE); - - void onScrollPosChangeCallback(S32, LLScrollbar*); - - virtual BOOL postBuild(); - - BOOL handleMouseDown (S32 x, S32 y, MASK mask); - BOOL handleKeyHere (KEY key, MASK mask); - BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - - void scrollToBottom (); - - void setHeaderVisibility(EShowItemHeader e); - EShowItemHeader getHeaderVisibility() const { return mEShowItemHeader;}; + virtual void init(LLSD& data); + virtual void draw(); private: - void reformatHistoryScrollItems(S32 width); - void arrange (S32 width, S32 height); - - S32 calcRecuiredHeight (); - S32 getRecuiredHeight () const { return mInnerRect.getHeight(); } - - void updateLayout (S32 width, S32 height); - - void show_hide_scrollbar (S32 width, S32 height); - - void showScrollbar (S32 width, S32 height); - void hideScrollbar (S32 width, S32 height); - - void panelSetLeftTopAndSize (LLView* panel, S32 left, S32 top, S32 width, S32 height); - void panelShiftVertical (LLView* panel,S32 delta); - void shiftPanels (S32 delta); + + std::string appendTime (); private: - std::vector<LLChatItemCtrl*> mItems; + std::string mText; // UTF-8 line of text + std::string mFromName; // agent or object name + LLUUID mFromID; // agent id or object id + EChatSourceType mSourceType; - EShowItemHeader mEShowItemHeader; - LLRect mInnerRect; - LLScrollbar* mScrollbar; + std::vector<std::string> mMessages; + bool mIsDirty; }; + #endif diff --git a/indra/newview/llchatmsgbox.cpp b/indra/newview/llchatmsgbox.cpp index e6398dd47a..bd0c36b44a 100644 --- a/indra/newview/llchatmsgbox.cpp +++ b/indra/newview/llchatmsgbox.cpp @@ -102,7 +102,7 @@ void LLChatMsgBox::drawText(S32 x, S32 y, const LLWString &text, const LLColor4 // iterate through each block of text that has been added y -= mLineSpacing; - for (std::vector<S32>::iterator it = mSeparatorOffset.begin(); true ;) + for (std::vector<S32>::iterator it = mSeparatorOffset.begin(); it != mSeparatorOffset.end() ;) { // display the text for this block S32 num_chars = *it - start; diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 20c44d5b11..98e492cada 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -49,6 +49,7 @@ #include "llvoicecontrolpanel.h" #include "llgroupmgr.h" #include "llnotificationmanager.h" +#include "lltransientfloatermgr.h" static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel"); static LLDefaultChildRegistry::Register<LLTalkButton> t2("chiclet_talk"); @@ -243,26 +244,36 @@ void LLIMChiclet::draw() LLIMChiclet::EType LLIMChiclet::getIMSessionType(const LLUUID& session_id) { EType type = TYPE_UNKNOWN; - LLFloaterIMPanel* im = NULL; if(session_id.isNull()) return type; - if (!(im = LLIMMgr::getInstance()->findFloaterBySession(session_id))) + EInstantMessage im_type = LLIMModel::getInstance()->getType(session_id); + if (IM_COUNT == im_type) { llassert_always(0 && "IM session not found"); // should never happen return type; } - switch(im->getDialogType()) + switch(im_type) { case IM_NOTHING_SPECIAL: + case IM_SESSION_P2P_INVITE: type = TYPE_IM; break; case IM_SESSION_GROUP_START: case IM_SESSION_INVITE: - type = TYPE_GROUP; + if (gAgent.isInGroup(session_id)) + { + type = TYPE_GROUP; + } + else + { + type = TYPE_AD_HOC; + } break; + case IM_SESSION_CONFERENCE_START: + type = TYPE_AD_HOC; default: break; } @@ -285,6 +296,11 @@ LLIMP2PChiclet::Params::Params() avatar_icon.name("avatar_icon"); avatar_icon.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP | FOLLOWS_BOTTOM); + + // *NOTE dzaporozhan + // Changed icon height from 25 to 24 to fix ticket EXT-794. + // In some cases(after changing UI scale) 25 pixel height icon was + // drawn incorrectly, i'm not sure why. avatar_icon.rect(LLRect(0, 24, 25, 0)); avatar_icon.mouse_opaque(false); @@ -458,6 +474,11 @@ LLIMGroupChiclet::Params::Params() rect(LLRect(0, 25, 45, 0)); group_icon.name("group_icon"); + + // *NOTE dzaporozhan + // Changed icon height from 25 to 24 to fix ticket EXT-794. + // In some cases(after changing UI scale) 25 pixel height icon was + // drawn incorrectly, i'm not sure why. group_icon.rect(LLRect(0, 24, 25, 0)); unread_notifications.name("unread"); @@ -1164,6 +1185,7 @@ LLTalkButton::LLTalkButton(const Params& p) speak_params.rect(speak_rect); mSpeakBtn = LLUICtrlFactory::create<LLButton>(speak_params); addChild(mSpeakBtn); + LLTransientFloaterMgr::getInstance()->addControlView(mSpeakBtn); mSpeakBtn->setClickedCallback(boost::bind(&LLTalkButton::onClick_SpeakBtn, this)); mSpeakBtn->setToggleState(FALSE); @@ -1172,6 +1194,7 @@ LLTalkButton::LLTalkButton(const Params& p) show_params.rect(show_rect); mShowBtn = LLUICtrlFactory::create<LLButton>(show_params); addChild(mShowBtn); + LLTransientFloaterMgr::getInstance()->addControlView(mShowBtn); mShowBtn->setClickedCallback(boost::bind(&LLTalkButton::onClick_ShowBtn, this)); mShowBtn->setToggleState(FALSE); diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index 316348cf1d..ef47b54333 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -275,7 +275,8 @@ public: enum EType { TYPE_UNKNOWN, TYPE_IM, - TYPE_GROUP + TYPE_GROUP, + TYPE_AD_HOC }; /*virtual*/ ~LLIMChiclet() {}; diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp index 9957694727..979a1a9a60 100644 --- a/indra/newview/llcurrencyuimanager.cpp +++ b/indra/newview/llcurrencyuimanager.cpp @@ -125,7 +125,7 @@ LLCurrencyUIManager::Impl::Impl(LLPanel& dialog) mUserCurrencyBuy(2000), // note, this is a default, real value set in llfloaterbuycurrency.cpp mUserEnteredCurrencyBuy(false), mSiteCurrencyEstimated(false), - mSiteCurrencyEstimatedCost(0), + mSiteCurrencyEstimatedCost(0), mBought(false), mTransactionType(TransactionNone), mTransaction(0), mCurrencyChanged(false) @@ -394,7 +394,7 @@ void LLCurrencyUIManager::Impl::updateUI() } } - mPanel.childSetTextArg("currency_est", "[USD]", llformat("%#.2f", mSiteCurrencyEstimatedCost / 100.0)); + mPanel.childSetTextArg("currency_est", "[LOCALAMOUNT]", "US$ " + llformat("%#.2f", mSiteCurrencyEstimatedCost / 100.0)); mPanel.childSetVisible("currency_est", mSiteCurrencyEstimated && mUserCurrencyBuy > 0); if (mPanel.childIsEnabled("buy_btn") @@ -478,7 +478,7 @@ void LLCurrencyUIManager::buy(const std::string& buy_msg) LLUIString msg = buy_msg; msg.setArg("[LINDENS]", llformat("%d", impl.mUserCurrencyBuy)); - msg.setArg("[USD]", llformat("%#.2f", impl.mSiteCurrencyEstimatedCost / 100.0)); + msg.setArg("[LOCALAMOUNT]", "US$ " + llformat("%#.2f", impl.mSiteCurrencyEstimatedCost / 100.0)); LLConfirmationManager::confirm(impl.mSiteConfirm, msg, impl, diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 4cf12a1533..069155c255 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -960,6 +960,30 @@ LLSpatialPartition* LLDrawable::getSpatialPartition() return retval; } +const S32 MIN_VIS_FRAME_RANGE = 2 ; //two frames:the current one and the last one. +//static +S32 LLDrawable::getMinVisFrameRange() +{ + return MIN_VIS_FRAME_RANGE ; +} + +BOOL LLDrawable::isRecentlyVisible() const +{ + //currently visible or visible in the previous frame. + BOOL vis = isVisible() || (sCurVisible - mVisible < MIN_VIS_FRAME_RANGE) ; + + if(!vis) + { + LLSpatialGroup* group = getSpatialGroup(); + if (group && group->isRecentlyVisible()) + { + mVisible = sCurVisible; + vis = TRUE ; + } + } + + return vis ; +} BOOL LLDrawable::isVisible() const { diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 986440397b..5a10b688da 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -78,7 +78,8 @@ public: BOOL isLight() const; - BOOL isVisible() const; + BOOL isVisible() const; + BOOL isRecentlyVisible() const; virtual void setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results = NULL, BOOL for_select = FALSE); @@ -278,7 +279,8 @@ public: S32 mQuietCount; static S32 getCurrentFrame() { return sCurVisible; } - + static S32 getMinVisFrameRange(); + void setSpatialBridge(LLSpatialBridge* bridge) { mSpatialBridge = (LLDrawable*) bridge; } LLSpatialBridge* getSpatialBridge() { return (LLSpatialBridge*) (LLDrawable*) mSpatialBridge; } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index fc5b27dd1b..a5b0b05603 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -270,16 +270,34 @@ void LLFace::setTexture(LLViewerTexture* tex) { mTexture->removeFace(this) ; removeAtlas() ; - } + } mTexture = tex ; - + if(mTexture.notNull()) { mTexture->addFace(this) ; } } +void LLFace::switchTexture(LLViewerTexture* new_texture) +{ + if(mTexture == new_texture) + { + return ; + } + + if(!new_texture) + { + llerrs << "Can not switch to a null texture." << llendl ; + } + new_texture->addTextureStats(mTexture->getMaxVirtualSize()) ; + + getViewerObject()->changeTEImage(mTEOffset, new_texture) ; + setTexture(new_texture) ; + gPipeline.markTextured(getDrawable()); +} + void LLFace::setTEOffset(const S32 te_offset) { mTEOffset = te_offset; diff --git a/indra/newview/llface.h b/indra/newview/llface.h index cafad5706c..f6ffefcb7c 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -89,6 +89,7 @@ public: U16 getGeomIndex() const { return mGeomIndex; } // index into draw pool U16 getGeomStart() const { return mGeomIndex; } // index into draw pool void setTexture(LLViewerTexture* tex) ; + void switchTexture(LLViewerTexture* new_texture); LLXformMatrix* getXform() const { return mXform; } BOOL hasGeometry() const { return mGeomCount > 0; } LLVector3 getPositionAgent() const; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 6b18984f88..ea947a5565 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -934,6 +934,17 @@ void LLFavoritesBarCtrl::onButtonRightClick( LLUUID item_id,LLView* fav_button,S LLMenuGL::showPopup(fav_button, menu, x, y); } +BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + BOOL handled = childrenHandleRightMouseDown( x, y, mask) != NULL; + if(!handled && !gMenuHolder->hasVisibleMenu()) + { + show_navbar_context_menu(this,x,y); + handled = true; + } + + return handled; +} void copy_slurl_to_clipboard_cb(std::string& slurl) { gClipboard.copyFromString(utf8str_to_wstring(slurl)); diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index 0be8de29a9..97117c3b4a 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -62,7 +62,7 @@ public: std::string& tooltip_msg); /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); // LLInventoryObserver observer trigger virtual void changed(U32 mask); virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); diff --git a/indra/newview/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp index 0107cb6fe2..5c4b8552a6 100644 --- a/indra/newview/llfloaterbuycurrency.cpp +++ b/indra/newview/llfloaterbuycurrency.cpp @@ -159,6 +159,9 @@ void LLFloaterBuyCurrencyUI::draw() updateUI(); } + // disable the Buy button when we are not able to buy + childSetEnabled("buy_btn", mManager.canBuy()); + LLFloater::draw(); } @@ -194,29 +197,19 @@ void LLFloaterBuyCurrencyUI::updateUI() // error section if (hasError) { - mChildren.setBadge(std::string("step_error"), LLViewChildren::BADGE_ERROR); - - LLTextBox* message = getChild<LLTextBox>("error_message"); - if (message) - { - message->setVisible(true); - message->setWrappedText(mManager.errorMessage()); - } - - childSetVisible("error_web", !mManager.errorURI().empty()); - if (!mManager.errorURI().empty()) - { - childHide("getting_data"); - } + childHide("normal_background"); + childShow("error_background"); + childShow("cannot_buy_message"); + childShow("error_web"); } else { - childHide("step_error"); - childHide("error_message"); + childShow("normal_background"); + childHide("error_background"); + childHide("cannot_buy_message"); childHide("error_web"); } - - + // currency childSetVisible("contacting", false); childSetVisible("buy_action", false); @@ -224,8 +217,6 @@ void LLFloaterBuyCurrencyUI::updateUI() if (!hasError) { - mChildren.setBadge(std::string("step_1"), LLViewChildren::BADGE_NOTE); - if (mManager.buying()) { childSetVisible("contacting", true); @@ -286,9 +277,8 @@ void LLFloaterBuyCurrencyUI::updateUI() childHide("purchase_warning_notenough"); } - childSetEnabled("buy_btn", mManager.canBuy()); - - if (!mManager.canBuy() && !childIsVisible("error_web")) + childHide("getting_data"); + if (!mManager.canBuy() && !hasError) { childShow("getting_data"); } @@ -298,10 +288,6 @@ void LLFloaterBuyCurrencyUI::onClickBuy() { mManager.buy(getString("buy_currency")); updateUI(); - // JC: updateUI() doesn't get called again until progress is made - // with transaction processing, so the "Purchase" button would be - // left enabled for some time. Pre-emptively disable. - childSetEnabled("buy_btn", false); } void LLFloaterBuyCurrencyUI::onClickCancel() @@ -311,7 +297,7 @@ void LLFloaterBuyCurrencyUI::onClickCancel() void LLFloaterBuyCurrencyUI::onClickErrorWeb() { - LLWeb::loadURLExternal(mManager.errorURI()); + LLWeb::loadURLExternal(getString("account_website")); closeFloater(); } diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp index 14fb93df61..ca43f41d05 100644 --- a/indra/newview/llfloaterchat.cpp +++ b/indra/newview/llfloaterchat.cpp @@ -66,7 +66,6 @@ #include "lllogchat.h" #include "lltexteditor.h" #include "lltextparser.h" -#include "llfloaterhtml.h" #include "llweb.h" #include "llstylemap.h" diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp index 05ea800d0e..dea656b0e4 100644 --- a/indra/newview/llfloaterchatterbox.cpp +++ b/indra/newview/llfloaterchatterbox.cpp @@ -363,7 +363,8 @@ LLFloater* LLFloaterChatterBox::getCurrentVoiceFloater() { // only LLFloaterIMPanels are called "im_floater" LLFloaterIMPanel* im_floaterp = (LLFloaterIMPanel*)panelp; - if (im_floaterp->getVoiceChannel() == LLVoiceChannel::getCurrentVoiceChannel()) + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(im_floaterp->getSessionID()); + if (voice_channel == LLVoiceChannel::getCurrentVoiceChannel()) { return im_floaterp; } diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp new file mode 100644 index 0000000000..6b0b5ed5e0 --- /dev/null +++ b/indra/newview/llfloaterhelpbrowser.cpp @@ -0,0 +1,142 @@ +/** + * @file llfloaterhelpbrowser.cpp + * @brief HTML Help floater - uses embedded web browser control + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterhelpbrowser.h" + +#include "llfloaterreg.h" +#include "llpluginclassmedia.h" +#include "llmediactrl.h" +#include "llviewerwindow.h" +#include "llviewercontrol.h" +#include "llweb.h" +#include "llui.h" + +#include "llurlhistory.h" +#include "llmediactrl.h" +#include "llviewermedia.h" + + +LLFloaterHelpBrowser::LLFloaterHelpBrowser(const LLSD& key) + : LLFloater(key) +{ + // really really destroy the help browser when it's closed, it'll be recreated. + // *TODO: when onClose() is resurrected as a virtual, this bind can go away. + mCloseSignal.connect(boost::bind(&LLFloaterHelpBrowser::onClose, this)); +} + +BOOL LLFloaterHelpBrowser::postBuild() +{ + mBrowser = getChild<LLMediaCtrl>("browser"); + mBrowser->addObserver(this); + + childSetAction("open_browser", onClickOpenWebBrowser, this); + + buildURLHistory(); + return TRUE; +} + +void LLFloaterHelpBrowser::buildURLHistory() +{ + // Get all of the entries in the "browser" collection + LLSD browser_history = LLURLHistory::getURLHistory("browser"); + + // initialize URL history in the plugin + LLPluginClassMedia *plugin = mBrowser->getMediaPlugin(); + if (plugin) + { + plugin->initializeUrlHistory(browser_history); + } +} + +void LLFloaterHelpBrowser::onClose() +{ + destroy(); // really destroy this dialog on closure, it's relatively heavyweight. +} + +void LLFloaterHelpBrowser::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + if(event == MEDIA_EVENT_LOCATION_CHANGED) + { + setCurrentURL(self->getLocation()); + } + else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) + { + // nothing yet + } +} + +void LLFloaterHelpBrowser::setCurrentURL(const std::string& url) +{ + mCurrentURL = url; + + // redirects will navigate momentarily to about:blank, don't add to history + if (mCurrentURL != "about:blank") + { + // Serialize url history + LLURLHistory::removeURL("browser", mCurrentURL); + LLURLHistory::addURL("browser", mCurrentURL); + } +} + +//static +void LLFloaterHelpBrowser::onClickClose(void* user_data) +{ + LLFloaterHelpBrowser* self = (LLFloaterHelpBrowser*)user_data; + + self->closeFloater(); +} + +//static +void LLFloaterHelpBrowser::onClickOpenWebBrowser(void* user_data) +{ + LLFloaterHelpBrowser* self = (LLFloaterHelpBrowser*)user_data; + + std::string url = self->mCurrentURL.empty() ? + self->mBrowser->getHomePageUrl() : + self->mCurrentURL; + LLWeb::loadURLExternal(url); +} + +void LLFloaterHelpBrowser::openMedia(const std::string& media_url) +{ + mBrowser->setHomePageUrl(media_url); + //mBrowser->navigateTo("data:text/html;charset=utf-8,I'd really love to be going to:<br><b>" + media_url + "</b>"); // tofu HACK for debugging =:) + mBrowser->navigateTo(media_url); + setCurrentURL(media_url); +} + +void LLFloaterHelpBrowser::navigateToLocalPage( const std::string& subdir, const std::string& filename_in ) +{ + mBrowser->navigateToLocalPage(subdir, filename_in); +} diff --git a/indra/newview/llfloaterhelpbrowser.h b/indra/newview/llfloaterhelpbrowser.h new file mode 100644 index 0000000000..14a276b428 --- /dev/null +++ b/indra/newview/llfloaterhelpbrowser.h @@ -0,0 +1,72 @@ +/** + * @file llfloatermediabrowser.h + * @brief HTML Help floater - uses embedded web browser control + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERHELPBROWSER_H +#define LL_LLFLOATERHELPBROWSER_H + +#include "llfloater.h" +#include "llmediactrl.h" + + +class LLMediaCtrl; + +class LLFloaterHelpBrowser : + public LLFloater, + public LLViewerMediaObserver +{ + public: + LLFloaterHelpBrowser(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + void onClose(); + + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + + void openMedia(const std::string& media_url); + + void navigateToLocalPage( const std::string& subdir, const std::string& filename_in ); + + private: + void buildURLHistory(); + void setCurrentURL(const std::string& url); + + static void onClickClose(void* user_data); + static void onClickOpenWebBrowser(void* user_data); + + private: + LLMediaCtrl* mBrowser; + std::string mCurrentURL; +}; + +#endif // LL_LLFLOATERHELPBROWSER_H + diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp index 27eb12b9cc..116286329c 100644 --- a/indra/newview/llfloaterinventory.cpp +++ b/indra/newview/llfloaterinventory.cpp @@ -1169,7 +1169,8 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) mScroller(NULL), mSortOrderSetting(p.sort_order_setting), mInventory(p.inventory), - mAllowMultiSelect(p.allow_multi_select) + mAllowMultiSelect(p.allow_multi_select), + mHasInventoryConnection(false) { // contex menu callbacks mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2)); @@ -1230,9 +1231,10 @@ BOOL LLInventoryPanel::postBuild() mInventoryObserver = new LLInventoryPanelObserver(this); mInventory->addObserver(mInventoryObserver); // build view of inventory if inventory ready, otherwise wait for modelChanged() callback - if (mInventory->isInventoryUsable()) + if (mInventory->isInventoryUsable() && !mHasInventoryConnection) { rebuildViewsFor(LLUUID::null, LLInventoryObserver::ADD); + mHasInventoryConnection = true; } // bit of a hack to make sure the inventory is open. @@ -1332,9 +1334,10 @@ void LLInventoryPanel::modelChanged(U32 mask) bool handled = false; // inventory just initialized, do complete build - if ((mask & LLInventoryObserver::ADD) && gInventory.getChangedIDs().empty()) + if ((mask & LLInventoryObserver::ADD) && gInventory.getChangedIDs().empty() && !mHasInventoryConnection) { rebuildViewsFor(LLUUID::null, LLInventoryObserver::ADD); + mHasInventoryConnection = true; return; } diff --git a/indra/newview/llfloaterinventory.h b/indra/newview/llfloaterinventory.h index a40efe020b..1aaac74c87 100644 --- a/indra/newview/llfloaterinventory.h +++ b/indra/newview/llfloaterinventory.h @@ -179,6 +179,7 @@ protected: LLScrollContainer* mScroller; BOOL mAllowMultiSelect; std::string mSortOrderSetting; + bool mHasInventoryConnection; }; class LLFloaterInventory; diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index e5f5e8eedb..3fe7d8d9da 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -1043,7 +1043,7 @@ BOOL LLPanelLandObjects::postBuild() mSelectedObjects = getChild<LLTextBox>("selected_objects_text"); mCleanOtherObjectsTime = getChild<LLLineEditor>("clean other time"); - mCleanOtherObjectsTime->setFocusLostCallback(onLostFocus, this); + mCleanOtherObjectsTime->setFocusLostCallback(boost::bind(onLostFocus, _1, this)); mCleanOtherObjectsTime->setCommitCallback(onCommitClean, this); childSetPrevalidate("clean other time", LLLineEditor::prevalidateNonNegativeS32); diff --git a/indra/newview/llfloatermediabrowser.cpp b/indra/newview/llfloatermediabrowser.cpp index c580cdef8a..9b7f3305e5 100644 --- a/indra/newview/llfloatermediabrowser.cpp +++ b/indra/newview/llfloatermediabrowser.cpp @@ -1,6 +1,6 @@ /** - * @file llfloaterhtmlhelp.cpp - * @brief HTML Help floater - uses embedded web browser control + * @file llfloatermediabrowser.cpp + * @brief media browser floater - uses embedded media browser control * * $LicenseInfo:firstyear=2006&license=viewergpl$ * @@ -33,7 +33,6 @@ #include "llviewerprecompiledheaders.h" #include "llfloatermediabrowser.h" -#include "llfloaterhtml.h" #include "llfloaterreg.h" #include "llparcel.h" @@ -147,7 +146,10 @@ void LLFloaterMediaBrowser::buildURLHistory() } // initialize URL history in the plugin - mBrowser->getMediaPlugin()->initializeUrlHistory(browser_history); + if(mBrowser && mBrowser->getMediaPlugin()) + { + mBrowser->getMediaPlugin()->initializeUrlHistory(browser_history); + } } std::string LLFloaterMediaBrowser::getSupportURL() @@ -330,69 +332,3 @@ void LLFloaterMediaBrowser::openMedia(const std::string& media_url) mBrowser->navigateTo(media_url); setCurrentURL(media_url); } -//////////////////////////////////////////////////////////////////////////////// -// - -LLViewerHtmlHelp gViewerHtmlHelp; - - -//////////////////////////////////////////////////////////////////////////////// -// -LLViewerHtmlHelp::LLViewerHtmlHelp() -{ - - LLUI::setHtmlHelp(this); -} - -LLViewerHtmlHelp::~LLViewerHtmlHelp() -{ - - LLUI::setHtmlHelp(NULL); -} - -void LLViewerHtmlHelp::show() -{ - show(""); -} - -void LLViewerHtmlHelp::show(std::string url) -{ - LLFloaterMediaBrowser* floater_html = dynamic_cast<LLFloaterMediaBrowser*>(LLFloaterReg::getInstance("media_browser")); - floater_html->setVisible(FALSE); - - if (url.empty()) - { - url = floater_html->getSupportURL(); - } - - if (gSavedSettings.getBOOL("UseExternalBrowser")) - { - LLSD notificationData; - notificationData["url"] = url; - - LLNotifications::instance().add("ClickOpenF1Help", notificationData, LLSD(), onClickF1HelpLoadURL); - floater_html->closeFloater(); - } - else - { - // don't wait, just do it - floater_html->setVisible(TRUE); - floater_html->openMedia(url); - } -} - -// static -bool LLViewerHtmlHelp::onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response) -{ - LLFloaterMediaBrowser* floater_html = dynamic_cast<LLFloaterMediaBrowser*>(LLFloaterReg::getInstance("media_browser")); - floater_html->setVisible(FALSE); - std::string url = floater_html->getSupportURL(); - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0) - { - LLWeb::loadURL(url); - } - floater_html->closeFloater(); - return false; -} - diff --git a/indra/newview/llfloatermediabrowser.h b/indra/newview/llfloatermediabrowser.h index 76e8b517a0..c315f9e797 100644 --- a/indra/newview/llfloatermediabrowser.h +++ b/indra/newview/llfloatermediabrowser.h @@ -1,6 +1,6 @@ /** * @file llfloatermediabrowser.h - * @brief HTML Help floater - uses embedded web browser control + * @brief media browser floater - uses embedded media browser control * * $LicenseInfo:firstyear=2006&license=viewergpl$ * @@ -33,23 +33,9 @@ #ifndef LL_LLFLOATERMEDIABROWSER_H #define LL_LLFLOATERMEDIABROWSER_H -#include "llhtmlhelp.h" #include "llfloater.h" #include "llmediactrl.h" -class LLViewerHtmlHelp : public LLHtmlHelp -{ -public: - LLViewerHtmlHelp(); - virtual ~LLViewerHtmlHelp(); - - /*virtual*/ void show(); - /*virtual*/ void show(std::string start_url); - void show(std::string start_url, std::string title); - - static bool onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response); - -}; class LLComboBox; class LLMediaCtrl; @@ -93,7 +79,5 @@ private: std::string mCurrentURL; }; -extern LLViewerHtmlHelp gViewerHtmlHelp; - #endif // LL_LLFLOATERMEDIABROWSER_H diff --git a/indra/newview/llfloatermediasettings.cpp b/indra/newview/llfloatermediasettings.cpp new file mode 100644 index 0000000000..811cc26efb --- /dev/null +++ b/indra/newview/llfloatermediasettings.cpp @@ -0,0 +1,249 @@ +/** + * @file llfloatermediasettings.cpp + * @brief Tabbed dialog for media settings - class implementation + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterreg.h" +#include "llfloatermediasettings.h" +#include "llpanelmediasettingsgeneral.h" +#include "llpanelmediasettingssecurity.h" +#include "llpanelmediasettingspermissions.h" +#include "llviewercontrol.h" +#include "lluictrlfactory.h" +#include "llbutton.h" +#include "llselectmgr.h" + +LLFloaterMediaSettings* LLFloaterMediaSettings::sInstance = NULL; + +//////////////////////////////////////////////////////////////////////////////// +// +LLFloaterMediaSettings::LLFloaterMediaSettings(const LLSD& key) + : LLFloater(key), + mTabContainer(NULL), + mPanelMediaSettingsGeneral(NULL), + mPanelMediaSettingsSecurity(NULL), + mPanelMediaSettingsPermissions(NULL), + mWaitingToClose( false ) +{ +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_media_settings.xml"); +} + +//////////////////////////////////////////////////////////////////////////////// +// +LLFloaterMediaSettings::~LLFloaterMediaSettings() +{ + if ( mPanelMediaSettingsGeneral ) + { + delete mPanelMediaSettingsGeneral; + mPanelMediaSettingsGeneral = NULL; + } + + if ( mPanelMediaSettingsSecurity ) + { + delete mPanelMediaSettingsSecurity; + mPanelMediaSettingsSecurity = NULL; + } + + if ( mPanelMediaSettingsPermissions ) + { + delete mPanelMediaSettingsPermissions; + mPanelMediaSettingsPermissions = NULL; + } + + sInstance = NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLFloaterMediaSettings::postBuild() +{ + mCloseSignal.connect(boost::bind(&LLFloaterMediaSettings::onClose, this)); + + mApplyBtn = getChild<LLButton>("Apply"); + mApplyBtn->setClickedCallback(onBtnApply, this); + + mCancelBtn = getChild<LLButton>("Cancel"); + mCancelBtn->setClickedCallback(onBtnCancel, this); + + mOKBtn = getChild<LLButton>("OK"); + mOKBtn->setClickedCallback(onBtnOK, this); + + mTabContainer = getChild<LLTabContainer>( "tab_container" ); + + mPanelMediaSettingsGeneral = new LLPanelMediaSettingsGeneral(); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(mPanelMediaSettingsGeneral)); + mPanelMediaSettingsGeneral->setParent( this ); + + // note that "permissions" tab is really "Controls" tab - refs to 'perms' and + // 'permissions' not changed to 'controls' since we don't want to change + // shared files in server code and keeping everything the same seemed best. + mPanelMediaSettingsPermissions = new LLPanelMediaSettingsPermissions(); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(mPanelMediaSettingsPermissions)); + + mPanelMediaSettingsSecurity = new LLPanelMediaSettingsSecurity(); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(mPanelMediaSettingsSecurity)); + + // restore the last tab viewed from persistance variable storage + if (!mTabContainer->selectTab(gSavedSettings.getS32("LastMediaSettingsTab"))) + { + mTabContainer->selectFirstTab(); + }; + + sInstance = this; + + return TRUE; +} + +//static +LLFloaterMediaSettings* LLFloaterMediaSettings::getInstance() +{ + if ( !sInstance ) + { + sInstance = (LLFloaterReg::getTypedInstance<LLFloaterMediaSettings>("media_settings")); + } + + return sInstance; +} + +//static +void LLFloaterMediaSettings::apply() +{ + + LLSD settings; + sInstance->mPanelMediaSettingsGeneral->getValues( settings ); + sInstance->mPanelMediaSettingsSecurity->getValues( settings ); + sInstance->mPanelMediaSettingsPermissions->getValues( settings ); + LLSelectMgr::getInstance()->selectionSetMedia( LLTextureEntry::MF_HAS_MEDIA ); + LLSelectMgr::getInstance()->selectionSetMediaData(settings); +} + +//////////////////////////////////////////////////////////////////////////////// +void LLFloaterMediaSettings::onClose() +{ + if(mPanelMediaSettingsGeneral) + { + mPanelMediaSettingsGeneral->onClose(); + } + LLFloaterReg::hideInstance("whitelist_entry"); +} + +//////////////////////////////////////////////////////////////////////////////// +//static +void LLFloaterMediaSettings::initValues( const LLSD& media_settings ) +{ + sInstance->clearValues(); + // update all panels with values from simulator + sInstance->mPanelMediaSettingsGeneral-> + initValues( sInstance->mPanelMediaSettingsGeneral, media_settings ); + + sInstance->mPanelMediaSettingsSecurity-> + initValues( sInstance->mPanelMediaSettingsSecurity, media_settings ); + + sInstance->mPanelMediaSettingsPermissions-> + initValues( sInstance->mPanelMediaSettingsPermissions, media_settings ); + +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLFloaterMediaSettings::commitFields() +{ + if (hasFocus()) + { + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + if (cur_focus->acceptsTextInput()) + { + cur_focus->onCommit(); + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +//static +void LLFloaterMediaSettings::clearValues() +{ + // clean up all panels before updating + sInstance->mPanelMediaSettingsGeneral->clearValues(sInstance->mPanelMediaSettingsGeneral); + sInstance->mPanelMediaSettingsSecurity->clearValues(sInstance->mPanelMediaSettingsSecurity); + sInstance->mPanelMediaSettingsPermissions->clearValues(sInstance->mPanelMediaSettingsPermissions); +} + + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterMediaSettings::onBtnOK( void* userdata ) +{ + sInstance->commitFields(); + + sInstance->apply(); + + sInstance->closeFloater(); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterMediaSettings::onBtnApply( void* userdata ) +{ + sInstance->commitFields(); + + sInstance->apply(); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterMediaSettings::onBtnCancel( void* userdata ) +{ + sInstance->closeFloater(); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterMediaSettings::onTabChanged(void* user_data, bool from_click) +{ + LLTabContainer* self = (LLTabContainer*)user_data; + gSavedSettings.setS32("LastMediaSettingsTab", self->getCurrentPanelIndex()); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLFloaterMediaSettings::enableOkApplyBtns( bool enable ) +{ + setCtrlsEnabled( enable ); + childSetEnabled( "OK", enable ); + childSetEnabled( "Apply", enable ); +} diff --git a/indra/newview/llfloatermediasettings.h b/indra/newview/llfloatermediasettings.h new file mode 100644 index 0000000000..b95c590346 --- /dev/null +++ b/indra/newview/llfloatermediasettings.h @@ -0,0 +1,81 @@ +/** + * @file llfloatermediasettings.cpp + * @brief Tabbed dialog for media settings - class definition + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERMEDIASETTINGS_H +#define LL_LLFLOATERMEDIASETTINGS_H + +#include "llfloater.h" +#include "lltabcontainer.h" + +class LLPanelMediaSettingsGeneral; +class LLPanelMediaSettingsSecurity; +class LLPanelMediaSettingsPermissions; + +class LLFloaterMediaSettings : + public LLFloater +{ +public: + LLFloaterMediaSettings(const LLSD& key); + ~LLFloaterMediaSettings(); + + virtual BOOL postBuild(); + static LLFloaterMediaSettings* getInstance(); + static void apply(); + static void initValues( const LLSD& media_settings ); + static void clearValues(); + void enableOkApplyBtns( bool enable ); + LLPanelMediaSettingsSecurity* getPanelSecurity(){return mPanelMediaSettingsSecurity;}; + +protected: + LLButton *mOKBtn; + LLButton *mCancelBtn; + LLButton *mApplyBtn; + + LLTabContainer *mTabContainer; + LLPanelMediaSettingsGeneral* mPanelMediaSettingsGeneral; + LLPanelMediaSettingsSecurity* mPanelMediaSettingsSecurity; + LLPanelMediaSettingsPermissions* mPanelMediaSettingsPermissions; + + void onClose(); + static void onBtnOK(void*); + static void onBtnCancel(void*); + static void onBtnApply(void*); + static void onTabChanged(void* user_data, bool from_click); + void commitFields(); + + static LLFloaterMediaSettings* sInstance; + +private: + bool mWaitingToClose; +}; + +#endif // LL_LLFLOATERMEDIASETTINGS_H diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp index fbc0ff3cf5..938370b732 100644 --- a/indra/newview/llfloaterpostcard.cpp +++ b/indra/newview/llfloaterpostcard.cpp @@ -106,7 +106,7 @@ BOOL LLFloaterPostcard::postBuild() childSetValue("name_form", LLSD(name_string)); // For the first time a user focusess to .the msg box, all text will be selected. - getChild<LLUICtrl>("msg_form")->setFocusChangedCallback(onMsgFormFocusRecieved, this); + getChild<LLUICtrl>("msg_form")->setFocusChangedCallback(boost::bind(onMsgFormFocusRecieved, _1, this)); childSetFocus("to_form", TRUE); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 761b5c9219..57c043a1e0 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -195,8 +195,8 @@ void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator); viewer_media_t get_web_media() { - viewer_media_t media_source = LLViewerMedia::newMediaImpl("", LLUUID::null, 0, 0, 0, 0, "text/html"); - + viewer_media_t media_source = LLViewerMedia::newMediaImpl(LLUUID::null); + media_source->initializeMedia("text/html"); return media_source; } diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 4d154c4cd3..3dcdc2f56e 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -1,6 +1,6 @@ /** * @file llfloaterreporter.cpp - * @brief Bug and abuse reports. + * @brief Abuse reports. * * $LicenseInfo:firstyear=2002&license=viewergpl$ * @@ -220,8 +220,7 @@ LLFloaterReporter::~LLFloaterReporter() void LLFloaterReporter::draw() { // this is set by a static callback sometime after the dialog is created. - // Only disable screenshot for abuse reports to estate owners - bug reports always - // allow screenshots to be taken. + // Only disable screenshot for abuse reports to estate owners if ( mEmailToEstateOwner ) { childSetValue("screen_check", FALSE ); @@ -479,15 +478,6 @@ void LLFloaterReporter::showFromMenu(EReportType report_type) if (f) { f->setReportType(report_type); - - if (report_type == BUG_REPORT) - { - LLNotifications::instance().add("HelpReportBug"); - } - else - { - // popup for abuse reports is triggered elsewhere - } } } @@ -528,14 +518,7 @@ bool LLFloaterReporter::validateReport() U8 category = (U8)category_sd.asInteger(); if (category == 0) { - if ( mReportType != BUG_REPORT ) - { - LLNotifications::instance().add("HelpReportAbuseSelectCategory"); - } - else - { - LLNotifications::instance().add("HelpReportBugSelectCategory"); - } + LLNotifications::instance().add("HelpReportAbuseSelectCategory"); return false; } @@ -561,27 +544,13 @@ bool LLFloaterReporter::validateReport() if ( childGetText("summary_edit").empty() ) { - if ( mReportType != BUG_REPORT ) - { - LLNotifications::instance().add("HelpReportAbuseSummaryEmpty"); - } - else - { - LLNotifications::instance().add("HelpReportBugSummaryEmpty"); - } + LLNotifications::instance().add("HelpReportAbuseSummaryEmpty"); return false; }; if ( childGetText("details_edit") == mDefaultSummary ) { - if ( mReportType != BUG_REPORT ) - { - LLNotifications::instance().add("HelpReportAbuseDetailsEmpty"); - } - else - { - LLNotifications::instance().add("HelpReportBugDetailsEmpty"); - } + LLNotifications::instance().add("HelpReportAbuseDetailsEmpty"); return false; }; return true; diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h index f363b9531e..7e8f05e3fc 100644 --- a/indra/newview/llfloaterreporter.h +++ b/indra/newview/llfloaterreporter.h @@ -1,7 +1,7 @@ /** * @file llfloaterreporter.h * @author Andrew Meadows - * @brief Bug and abuse reports. + * @brief Abuse reports. * * $LicenseInfo:firstyear=2006&license=viewergpl$ * @@ -48,7 +48,7 @@ class LLMeanCollisionData; struct LLResourceData; // these flags are used to label info requests to the server -const U32 BUG_REPORT_REQUEST = 0x01 << 0; +//const U32 BUG_REPORT_REQUEST = 0x01 << 0; // DEPRECATED const U32 COMPLAINT_REPORT_REQUEST = 0x01 << 1; const U32 OBJECT_PAY_REQUEST = 0x01 << 2; @@ -73,7 +73,7 @@ enum EReportType { NULL_REPORT = 0, // don't use this value anywhere UNKNOWN_REPORT = 1, - BUG_REPORT = 2, + //BUG_REPORT = 2, // DEPRECATED COMPLAINT_REPORT = 3, CS_REQUEST_REPORT = 4 }; diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index f334344279..7dc29379e4 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -44,9 +44,11 @@ #include "llcombobox.h" #include "lldraghandle.h" #include "llfloaterbuildoptions.h" +#include "llfloatermediasettings.h" #include "llfloateropenobject.h" #include "llfloaterreg.h" #include "llfocusmgr.h" +#include "llmediaentry.h" #include "llmenugl.h" #include "llpanelcontents.h" #include "llpanelface.h" @@ -97,7 +99,7 @@ const std::string PANEL_NAMES[LLFloaterTools::PANEL_COUNT] = }; // Local prototypes -void commit_select_component(LLUICtrl *ctrl, void *data); +void commit_select_component(void *data); void click_show_more(void*); void click_popup_info(void*); void click_popup_done(void*); @@ -105,15 +107,14 @@ void click_popup_minimize(void*); void click_popup_rotate_left(void*); void click_popup_rotate_reset(void*); void click_popup_rotate_right(void*); -void commit_slider_dozer_size(LLUICtrl *, void*); -void commit_slider_dozer_force(LLUICtrl *, void*); +void commit_slider_dozer_force(LLUICtrl *); void click_apply_to_selection(void*); -void commit_radio_group_focus(LLUICtrl* ctrl, void* data); -void commit_radio_group_move(LLUICtrl* ctrl, void* data); -void commit_radio_group_edit(LLUICtrl* ctrl, void* data); -void commit_radio_group_land(LLUICtrl* ctrl, void* data); -void commit_grid_mode(LLUICtrl *, void*); -void commit_slider_zoom(LLUICtrl *, void*); +void commit_radio_group_focus(LLUICtrl* ctrl); +void commit_radio_group_move(LLUICtrl* ctrl); +void commit_radio_group_edit(LLUICtrl* ctrl); +void commit_radio_group_land(LLUICtrl* ctrl); +void commit_grid_mode(LLUICtrl *); +void commit_slider_zoom(LLUICtrl *ctrl); //static @@ -210,43 +211,28 @@ BOOL LLFloaterTools::postBuild() getDragHandle()->setEnabled( !gSavedSettings.getBOOL("ToolboxAutoMove") ); LLRect rect; - mBtnFocus = getChild<LLButton>("button focus");//btn; - childSetAction("button focus",LLFloaterTools::setEditTool, (void*)LLToolCamera::getInstance()); - mBtnMove = getChild<LLButton>("button move"); - childSetAction("button move",LLFloaterTools::setEditTool, (void*)LLToolGrab::getInstance()); - mBtnEdit = getChild<LLButton>("button edit"); - childSetAction("button edit",LLFloaterTools::setEditTool, (void*)LLToolCompTranslate::getInstance()); - mBtnCreate = getChild<LLButton>("button create"); - childSetAction("button create",LLFloaterTools::setEditTool, (void*)LLToolCompCreate::getInstance()); - mBtnLand = getChild<LLButton>("button land" ); - childSetAction("button land",LLFloaterTools::setEditTool, (void*)LLToolSelectLand::getInstance()); - mTextStatus = getChild<LLTextBox>("text status"); - - childSetCommitCallback("slider zoom",commit_slider_zoom,this); - - mRadioGroupFocus = getChild<LLRadioGroup>("focus_radio_group"); - childSetCommitCallback("focus_radio_group", commit_radio_group_focus, this); - - mRadioGroupMove = getChild<LLRadioGroup>("move_radio_group"); - childSetCommitCallback("move_radio_group", commit_radio_group_move, this); - - mRadioGroupEdit = getChild<LLRadioGroup>("edit_radio_group"); - childSetCommitCallback("edit_radio_group", commit_radio_group_edit, this); - - mCheckSelectIndividual = getChild<LLCheckBoxCtrl>("checkbox edit linked parts"); + mBtnFocus = getChild<LLButton>("button focus");//btn; + mBtnMove = getChild<LLButton>("button move"); + mBtnEdit = getChild<LLButton>("button edit"); + mBtnCreate = getChild<LLButton>("button create"); + mBtnLand = getChild<LLButton>("button land" ); + mTextStatus = getChild<LLTextBox>("text status"); + mRadioGroupFocus = getChild<LLRadioGroup>("focus_radio_group"); + mRadioGroupMove = getChild<LLRadioGroup>("move_radio_group"); + mRadioGroupEdit = getChild<LLRadioGroup>("edit_radio_group"); + mBtnGridOptions = getChild<LLButton>("Options..."); + + mCheckSelectIndividual = getChild<LLCheckBoxCtrl>("checkbox edit linked parts"); childSetValue("checkbox edit linked parts",(BOOL)gSavedSettings.getBOOL("EditLinkedParts")); - childSetCommitCallback("checkbox edit linked parts",commit_select_component,this); - mCheckSnapToGrid = getChild<LLCheckBoxCtrl>("checkbox snap to grid"); + mCheckSnapToGrid = getChild<LLCheckBoxCtrl>("checkbox snap to grid"); childSetValue("checkbox snap to grid",(BOOL)gSavedSettings.getBOOL("SnapEnabled")); - mBtnGridOptions = getChild<LLButton>("Options..."); - childSetAction("Options...",onClickGridOptions, this); - mCheckStretchUniform = getChild<LLCheckBoxCtrl>("checkbox uniform"); + mCheckStretchUniform = getChild<LLCheckBoxCtrl>("checkbox uniform"); childSetValue("checkbox uniform",(BOOL)gSavedSettings.getBOOL("ScaleUniform")); - mCheckStretchTexture = getChild<LLCheckBoxCtrl>("checkbox stretch textures"); + mCheckStretchTexture = getChild<LLCheckBoxCtrl>("checkbox stretch textures"); childSetValue("checkbox stretch textures",(BOOL)gSavedSettings.getBOOL("ScaleStretchTextures")); - mTextGridMode = getChild<LLTextBox>("text ruler mode"); - mComboGridMode = getChild<LLComboBox>("combobox grid mode"); - childSetCommitCallback("combobox grid mode",commit_grid_mode, this); + mTextGridMode = getChild<LLTextBox>("text ruler mode"); + mComboGridMode = getChild<LLComboBox>("combobox grid mode"); + // // Create Buttons // @@ -271,18 +257,11 @@ BOOL LLFloaterTools::postBuild() mCheckCopyRotates = getChild<LLCheckBoxCtrl>("checkbox copy rotates"); childSetValue("checkbox copy rotates",(BOOL)gSavedSettings.getBOOL("CreateToolCopyRotates")); - mRadioGroupLand = getChild<LLRadioGroup>("land_radio_group"); - childSetCommitCallback("land_radio_group", commit_radio_group_land, this); - - mBtnApplyToSelection = getChild<LLButton>("button apply to selection"); - childSetAction("button apply to selection",click_apply_to_selection, (void*)0); - - mSliderDozerSize = getChild<LLSlider>("slider brush size"); - childSetCommitCallback("slider brush size", commit_slider_dozer_size, (void*)0); + mRadioGroupLand = getChild<LLRadioGroup>("land_radio_group"); + mBtnApplyToSelection = getChild<LLButton>("button apply to selection"); + mSliderDozerSize = getChild<LLSlider>("slider brush size"); childSetValue( "slider brush size", gSavedSettings.getF32("LandBrushSize")); - - mSliderDozerForce = getChild<LLSlider>("slider force"); - childSetCommitCallback("slider force",commit_slider_dozer_force, (void*)0); + mSliderDozerForce = getChild<LLSlider>("slider force"); // the setting stores the actual force multiplier, but the slider is logarithmic, so we convert here childSetValue( "slider force", log10(gSavedSettings.getF32("LandBrushForce"))); @@ -369,6 +348,22 @@ LLFloaterTools::LLFloaterTools(const LLSD& key) mFactoryMap["land info panel"] = LLCallbackMap(createPanelLandInfo, this);//LLPanelLandInfo //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_tools.xml",FALSE); + mCommitCallbackRegistrar.add("BuildTool.setTool", boost::bind(&LLFloaterTools::setTool,this, _2)); + mCommitCallbackRegistrar.add("BuildTool.commitZoom", boost::bind(&commit_slider_zoom, _1)); + mCommitCallbackRegistrar.add("BuildTool.commitRadioFocus", boost::bind(&commit_radio_group_focus, _1)); + mCommitCallbackRegistrar.add("BuildTool.commitRadioMove", boost::bind(&commit_radio_group_move,_1)); + mCommitCallbackRegistrar.add("BuildTool.commitRadioEdit", boost::bind(&commit_radio_group_edit,_1)); + + mCommitCallbackRegistrar.add("BuildTool.selectComponent", boost::bind(&commit_select_component, this)); + mCommitCallbackRegistrar.add("BuildTool.gridOptions", boost::bind(&LLFloaterTools::onClickGridOptions,this)); + mCommitCallbackRegistrar.add("BuildTool.applyToSelection", boost::bind(&click_apply_to_selection, this)); + mCommitCallbackRegistrar.add("BuildTool.gridMode", boost::bind(&commit_grid_mode,_1)); + mCommitCallbackRegistrar.add("BuildTool.commitRadioLand", boost::bind(&commit_radio_group_land,_1)); + mCommitCallbackRegistrar.add("BuildTool.LandBrushForce", boost::bind(&commit_slider_dozer_force,_1)); + mCommitCallbackRegistrar.add("BuildTool.AddMedia", boost::bind(&LLFloaterTools::onClickBtnAddMedia,this)); + mCommitCallbackRegistrar.add("BuildTool.DeleteMedia", boost::bind(&LLFloaterTools::onClickBtnDeleteMedia,this)); + mCommitCallbackRegistrar.add("BuildTool.EditMedia", boost::bind(&LLFloaterTools::onClickBtnEditMedia,this)); + } LLFloaterTools::~LLFloaterTools() @@ -427,6 +422,7 @@ void LLFloaterTools::refresh() mPanelObject->refresh(); mPanelVolume->refresh(); mPanelFace->refresh(); + refreshMedia(); mPanelContents->refresh(); mPanelLandInfo->refresh(); } @@ -756,6 +752,7 @@ void LLFloaterTools::onClose() LLToolMgr::getInstance()->getCurrentToolset()->selectFirstTool(); //gMenuBarView->setItemVisible("BuildTools", FALSE); + LLFloaterReg::hideInstance("media_settings"); } void click_popup_info(void*) @@ -767,7 +764,7 @@ void click_popup_done(void*) handle_reset_view(); } -void commit_radio_group_move(LLUICtrl* ctrl, void* data) +void commit_radio_group_move(LLUICtrl* ctrl) { LLRadioGroup* group = (LLRadioGroup*)ctrl; std::string selected = group->getValue().asString(); @@ -788,7 +785,7 @@ void commit_radio_group_move(LLUICtrl* ctrl, void* data) } } -void commit_radio_group_focus(LLUICtrl* ctrl, void* data) +void commit_radio_group_focus(LLUICtrl* ctrl) { LLRadioGroup* group = (LLRadioGroup*)ctrl; std::string selected = group->getValue().asString(); @@ -812,7 +809,7 @@ void commit_radio_group_focus(LLUICtrl* ctrl, void* data) } } -void commit_slider_zoom(LLUICtrl *ctrl, void*) +void commit_slider_zoom(LLUICtrl *ctrl) { // renormalize value, since max "volume" level is 0.5 for some reason F32 zoom_level = (F32)ctrl->getValue().asReal() * 2.f; // / 0.5f; @@ -837,26 +834,19 @@ void click_popup_rotate_right(void*) dialog_refresh_all(); } - -void commit_slider_dozer_size(LLUICtrl *ctrl, void*) -{ - F32 size = (F32)ctrl->getValue().asReal(); - gSavedSettings.setF32("LandBrushSize", size); -} - -void commit_slider_dozer_force(LLUICtrl *ctrl, void*) +void commit_slider_dozer_force(LLUICtrl *ctrl) { // the slider is logarithmic, so we exponentiate to get the actual force multiplier F32 dozer_force = pow(10.f, (F32)ctrl->getValue().asReal()); gSavedSettings.setF32("LandBrushForce", dozer_force); } -void click_apply_to_selection(void* user) +void click_apply_to_selection(void*) { LLToolBrushLand::getInstance()->modifyLandInSelectionGlobal(); } -void commit_radio_group_edit(LLUICtrl *ctrl, void *data) +void commit_radio_group_edit(LLUICtrl *ctrl) { S32 show_owners = gSavedSettings.getBOOL("ShowParcelOwners"); @@ -881,7 +871,7 @@ void commit_radio_group_edit(LLUICtrl *ctrl, void *data) gSavedSettings.setBOOL("ShowParcelOwners", show_owners); } -void commit_radio_group_land(LLUICtrl* ctrl, void* data) +void commit_radio_group_land(LLUICtrl* ctrl) { LLRadioGroup* group = (LLRadioGroup*)ctrl; std::string selected = group->getValue().asString(); @@ -909,7 +899,7 @@ void commit_radio_group_land(LLUICtrl* ctrl, void* data) } } -void commit_select_component(LLUICtrl *ctrl, void *data) +void commit_select_component(void *data) { LLFloaterTools* floaterp = (LLFloaterTools*)data; @@ -933,7 +923,7 @@ void commit_select_component(LLUICtrl *ctrl, void *data) } } -void commit_grid_mode(LLUICtrl *ctrl, void *data) +void commit_grid_mode(LLUICtrl *ctrl) { LLComboBox* combo = (LLComboBox*)ctrl; @@ -948,10 +938,9 @@ void LLFloaterTools::setObjectType( LLPCode pcode ) gFocusMgr.setMouseCapture(NULL); } -// static -void LLFloaterTools::onClickGridOptions(void* data) + +void LLFloaterTools::onClickGridOptions() { - //LLFloaterTools* floaterp = (LLFloaterTools*)data; LLFloaterReg::showInstance("build_options"); // RN: this makes grid options dependent on build tools window //floaterp->addDependentFloater(LLFloaterBuildOptions::getInstance(), FALSE); @@ -964,8 +953,558 @@ void LLFloaterTools::setEditTool(void* tool_pointer) LLToolMgr::getInstance()->getCurrentToolset()->selectTool( tool ); } +void LLFloaterTools::setTool(const LLSD& user_data) +{ + std::string control_name = user_data.asString(); + if(control_name == "Focus") + LLToolMgr::getInstance()->getCurrentToolset()->selectTool((LLTool *) LLToolCamera::getInstance() ); + else if (control_name == "Move" ) + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *)LLToolGrab::getInstance() ); + else if (control_name == "Edit" ) + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *) LLToolCompTranslate::getInstance()); + else if (control_name == "Create" ) + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *) LLToolCompCreate::getInstance()); + else if (control_name == "Land" ) + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *) LLToolSelectLand::getInstance()); + else + llwarns<<" no parameter name "<<control_name<<" found!! No Tool selected!!"<< llendl; +} + void LLFloaterTools::onFocusReceived() { LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); LLFloater::onFocusReceived(); } + +// Media stuff +void LLFloaterTools::refreshMedia() +{ + getMediaState(); + LLFloaterMediaSettings::getInstance(); + LLFloaterMediaSettings::initValues(mMediaSettings ); +} + + + +void LLFloaterTools::getMediaState() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + if( !objectp ) + { + childSetEnabled("media_tex", FALSE); + childSetEnabled("add_media", FALSE); + childSetEnabled("delete_media", FALSE); + childSetEnabled("edit_media", FALSE); + updateMediaSettings(); + return; + } + + bool editable = gAgent.isGodlike() || (objectp->permModify() && objectp->getPCode() == LL_PCODE_VOLUME); + + // Media settings + U8 has_media = (U8)0; + struct media_functor : public LLSelectedTEGetFunctor<U8> + { + U8 get(LLViewerObject* object, S32 face) + { + return (object->getTE(face)->getMediaTexGen()); + } + } func; + bool identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, has_media ); + + // update UI depending on whether "object" (prim or face) has media + // and whether or not you are allowed to edit it. + bool bool_has_media = (has_media & LLTextureEntry::MF_HAS_MEDIA); + childSetEnabled("media_tex", bool_has_media & editable); + childSetEnabled( "edit_media", bool_has_media & editable ); + childSetEnabled( "delete_media", bool_has_media & editable ); + childSetEnabled( "add_media", ( ! bool_has_media ) & editable ); + + // load values for media settings + updateMediaSettings(); + + // if identical is set, all faces are same + if ( identical ) + { + // TODO: display a list of all media on the face - use 'identical' flag + }; +} + + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to add media to a prim or prim face +void LLFloaterTools::onClickBtnAddMedia() +{ + // check for the edit tool and now many faces are selected + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + if((tool != LLToolFace::getInstance()) || LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected()) + { + LLNotifications::instance().add("MultipleFacesSelected",LLSD(), LLSD(), multipleFacesSelectedConfirm); + + } + else + { + onClickBtnEditMedia(); + } + +} + +// static +bool LLFloaterTools::multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + switch( option ) + { + case 0: // "Yes" + gFloaterTools->onClickBtnEditMedia(); + break; + case 1: // "No" + default: + break; + } + return false; +} + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to edit existing media settings on a prim or prim face +// TODO: test if there is media on the item and only allow editing if present +void LLFloaterTools::onClickBtnEditMedia() +{ + refreshMedia(); + LLFloaterReg::showInstance("media_settings"); +} + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to delete media from a prim or prim face +void LLFloaterTools::onClickBtnDeleteMedia() +{ + LLNotifications::instance().add("DeleteMedia", LLSD(), LLSD(), deleteMediaConfirm); +} + + +// static +bool LLFloaterTools::deleteMediaConfirm(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + switch( option ) + { + case 0: // "Yes" + LLSelectMgr::getInstance()->selectionSetMedia( 0 ); + if(LLFloaterReg::instanceVisible("media_settings")) + { + LLFloaterReg::hideInstance("media_settings"); + } + break; + + case 1: // "No" + default: + break; + } + return false; +} + +////////////////////////////////////////////////////////////////////////////// +// +void LLFloaterTools::updateMediaSettings() +{ + bool identical( false ); + std::string base_key( "" ); + std::string value_str( "" ); + int value_int = 0; + bool value_bool = false; + LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection(); + // TODO: (CP) refactor this using something clever or boost or both !! + + LLMediaEntry default_media_data; + + // controls + U8 value_u8 = default_media_data.getControls(); + struct functor_getter_controls : public LLSelectedTEGetFunctor< U8 > + { + U8 get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getControls(); + LLMediaEntry default_media_data; + return default_media_data.getControls(); + }; + + } func_controls; + identical = selected_objects->getSelectedTEValue( &func_controls, value_u8 ); + base_key = std::string( LLMediaEntry::CONTROLS_KEY ); + mMediaSettings[ base_key ] = value_u8; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // First click (formerly left click) + value_bool = default_media_data.getFirstClickInteract(); + struct functor_getter_first_click : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getFirstClickInteract(); + LLMediaEntry default_media_data; + return default_media_data.getFirstClickInteract(); + }; + + } func_first_click; + identical = selected_objects->getSelectedTEValue( &func_first_click, value_bool ); + base_key = std::string( LLMediaEntry::FIRST_CLICK_INTERACT_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Home URL + value_str = default_media_data.getHomeURL(); + struct functor_getter_home_url : public LLSelectedTEGetFunctor< std::string > + { + std::string get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getHomeURL(); + LLMediaEntry default_media_data; + return default_media_data.getHomeURL(); + }; + + } func_home_url; + identical = selected_objects->getSelectedTEValue( &func_home_url, value_str ); + base_key = std::string( LLMediaEntry::HOME_URL_KEY ); + mMediaSettings[ base_key ] = value_str; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + llwarns<<"Angela debug : home url string == "<<value_str<<llendl; + + // Current URL + value_str = default_media_data.getCurrentURL(); + struct functor_getter_current_url : public LLSelectedTEGetFunctor< std::string > + { + std::string get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getCurrentURL(); + LLMediaEntry default_media_data; + return default_media_data.getCurrentURL(); + }; + + } func_current_url; + identical = selected_objects->getSelectedTEValue( &func_current_url, value_str ); + base_key = std::string( LLMediaEntry::CURRENT_URL_KEY ); + mMediaSettings[ base_key ] = value_str; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Auto zoom + value_bool = default_media_data.getAutoZoom(); + struct functor_getter_auto_zoom : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getAutoZoom(); + LLMediaEntry default_media_data; + return default_media_data.getAutoZoom(); + }; + + } func_auto_zoom; + identical = selected_objects->getSelectedTEValue( &func_auto_zoom, value_bool ); + base_key = std::string( LLMediaEntry::AUTO_ZOOM_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Auto play + value_bool = default_media_data.getAutoPlay(); + struct functor_getter_auto_play : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getAutoPlay(); + LLMediaEntry default_media_data; + return default_media_data.getAutoPlay(); + }; + + } func_auto_play; + identical = selected_objects->getSelectedTEValue( &func_auto_play, value_bool ); + base_key = std::string( LLMediaEntry::AUTO_PLAY_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Auto scale + value_bool = default_media_data.getAutoScale(); + struct functor_getter_auto_scale : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getAutoScale(); + LLMediaEntry default_media_data; + return default_media_data.getAutoScale();; + }; + + } func_auto_scale; + identical = selected_objects->getSelectedTEValue( &func_auto_scale, value_bool ); + base_key = std::string( LLMediaEntry::AUTO_SCALE_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Auto loop + value_bool = default_media_data.getAutoLoop(); + struct functor_getter_auto_loop : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getAutoLoop(); + LLMediaEntry default_media_data; + return default_media_data.getAutoLoop(); + }; + + } func_auto_loop; + identical = selected_objects->getSelectedTEValue( &func_auto_loop, value_bool ); + base_key = std::string( LLMediaEntry::AUTO_LOOP_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // width pixels (if not auto scaled) + value_int = default_media_data.getWidthPixels(); + struct functor_getter_width_pixels : public LLSelectedTEGetFunctor< int > + { + int get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getWidthPixels(); + LLMediaEntry default_media_data; + return default_media_data.getWidthPixels(); + }; + + } func_width_pixels; + identical = selected_objects->getSelectedTEValue( &func_width_pixels, value_int ); + base_key = std::string( LLMediaEntry::WIDTH_PIXELS_KEY ); + mMediaSettings[ base_key ] = value_int; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // height pixels (if not auto scaled) + value_int = default_media_data.getHeightPixels(); + struct functor_getter_height_pixels : public LLSelectedTEGetFunctor< int > + { + int get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getHeightPixels(); + LLMediaEntry default_media_data; + return default_media_data.getHeightPixels(); + }; + + } func_height_pixels; + identical = selected_objects->getSelectedTEValue( &func_height_pixels, value_int ); + base_key = std::string( LLMediaEntry::HEIGHT_PIXELS_KEY ); + mMediaSettings[ base_key ] = value_int; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Enable Alt image + value_bool = default_media_data.getAltImageEnable(); + struct functor_getter_enable_alt_image : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getAltImageEnable(); + LLMediaEntry default_media_data; + return default_media_data.getAltImageEnable(); + }; + + } func_enable_alt_image; + identical = selected_objects->getSelectedTEValue( &func_enable_alt_image, value_bool ); + base_key = std::string( LLMediaEntry::ALT_IMAGE_ENABLE_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - owner interact + value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_OWNER ); + struct functor_getter_perms_owner_interact : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_OWNER)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_OWNER ); + }; + + } func_perms_owner_interact; + identical = selected_objects->getSelectedTEValue( &func_perms_owner_interact, value_bool ); + base_key = std::string( LLPanelContents::PERMS_OWNER_INTERACT_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - owner control + value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_OWNER ); + struct functor_getter_perms_owner_control : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_OWNER)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_OWNER ); + }; + + } func_perms_owner_control; + identical = selected_objects ->getSelectedTEValue( &func_perms_owner_control, value_bool ); + base_key = std::string( LLPanelContents::PERMS_OWNER_CONTROL_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - group interact + value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_GROUP ); + struct functor_getter_perms_group_interact : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_GROUP)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_GROUP ); + }; + + } func_perms_group_interact; + identical = selected_objects->getSelectedTEValue( &func_perms_group_interact, value_bool ); + base_key = std::string( LLPanelContents::PERMS_GROUP_INTERACT_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - group control + value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_GROUP ); + struct functor_getter_perms_group_control : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_GROUP)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_GROUP ); + }; + + } func_perms_group_control; + identical = selected_objects->getSelectedTEValue( &func_perms_group_control, value_bool ); + base_key = std::string( LLPanelContents::PERMS_GROUP_CONTROL_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - anyone interact + value_bool = 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_ANYONE ); + struct functor_getter_perms_anyone_interact : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_ANYONE)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsInteract() & LLMediaEntry::PERM_ANYONE ); + }; + + } func_perms_anyone_interact; + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func_perms_anyone_interact, value_bool ); + base_key = std::string( LLPanelContents::PERMS_ANYONE_INTERACT_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // Perms - anyone control + value_bool = 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_ANYONE ); + struct functor_getter_perms_anyone_control : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_ANYONE)); + LLMediaEntry default_media_data; + return 0 != ( default_media_data.getPermsControl() & LLMediaEntry::PERM_ANYONE ); + }; + + } func_perms_anyone_control; + identical = selected_objects->getSelectedTEValue( &func_perms_anyone_control, value_bool ); + base_key = std::string( LLPanelContents::PERMS_ANYONE_CONTROL_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // security - whitelist enable + value_bool = default_media_data.getWhiteListEnable(); + struct functor_getter_whitelist_enable : public LLSelectedTEGetFunctor< bool > + { + bool get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getWhiteListEnable(); + LLMediaEntry default_media_data; + return default_media_data.getWhiteListEnable(); + }; + + } func_whitelist_enable; + identical = selected_objects->getSelectedTEValue( &func_whitelist_enable, value_bool ); + base_key = std::string( LLMediaEntry::WHITELIST_ENABLE_KEY ); + mMediaSettings[ base_key ] = value_bool; + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; + + // security - whitelist URLs + std::vector<std::string> value_vector_str = default_media_data.getWhiteList(); + struct functor_getter_whitelist_urls : public LLSelectedTEGetFunctor< std::vector<std::string> > + { + std::vector<std::string> get( LLViewerObject* object, S32 face ) + { + if ( object ) + if ( object->getTE(face) ) + if ( object->getTE(face)->getMediaData() ) + return object->getTE(face)->getMediaData()->getWhiteList(); + LLMediaEntry default_media_data; + return default_media_data.getWhiteList(); + }; + + } func_whitelist_urls; + identical = selected_objects->getSelectedTEValue( &func_whitelist_urls, value_vector_str ); + base_key = std::string( LLMediaEntry::WHITELIST_KEY ); + mMediaSettings[ base_key ].clear(); + std::vector< std::string >::iterator iter = value_vector_str.begin(); + while( iter != value_vector_str.end() ) + { + std::string white_list_url = *iter; + mMediaSettings[ base_key ].append( white_list_url ); + ++iter; + }; + + mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; +} + diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index 1b9f1d31ec..008c9677ed 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -100,13 +100,24 @@ public: void setStatusText(const std::string& text); static void setEditTool(void* data); + void setTool(const LLSD& user_data); void saveLastTool(); + void onClickBtnDeleteMedia(); + void onClickBtnAddMedia(); + void onClickBtnEditMedia(); + + private: void onClose(); void refresh(); - + void refreshMedia(); + void getMediaState(); + void updateMediaSettings(); + void getMeidaState(); + static bool deleteMediaConfirm(const LLSD& notification, const LLSD& response); + static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response); static void setObjectType( LLPCode pcode ); - static void onClickGridOptions(void* data); + void onClickGridOptions(); public: LLButton *mBtnFocus; @@ -175,6 +186,10 @@ private: BOOL mDirty; std::map<std::string, std::string> mStatusText; + +protected: + LLSD mMediaSettings; + }; extern LLFloaterTools *gFloaterTools; diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index 1e975cd447..2b01a56373 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -35,6 +35,7 @@ #include "llfloaterurlentry.h" #include "llpanellandmedia.h" +#include "llpanelface.h" // project includes #include "llcombobox.h" @@ -145,13 +146,23 @@ void LLFloaterURLEntry::buildURLHistory() void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_type) { - LLPanelLandMedia* panel_media = (LLPanelLandMedia*)mPanelLandMediaHandle.get(); + LLPanelLandMedia* panel_media = dynamic_cast<LLPanelLandMedia*>(mPanelLandMediaHandle.get()); if (panel_media) { // status is ignored for now -- error = "none/none" panel_media->setMediaType(mime_type); panel_media->setMediaURL(mMediaURLEdit->getValue().asString()); } + else + { + LLPanelFace* panel_face = dynamic_cast<LLPanelFace*>(mPanelLandMediaHandle.get()); + if(panel_face) + { + panel_face->setMediaType(mime_type); + panel_face->setMediaURL(mMediaURLEdit->getValue().asString()); + } + + } // Decrement the cursor getWindow()->decBusyCount(); childSetVisible("loading_label", false); @@ -159,29 +170,18 @@ void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_ } // static -LLHandle<LLFloater> LLFloaterURLEntry::show(LLHandle<LLPanel> parent) +LLHandle<LLFloater> LLFloaterURLEntry::show(LLHandle<LLPanel> parent, const std::string media_url) { - if (sInstance) - { - sInstance->openFloater(); - } - else + if (!sInstance) { sInstance = new LLFloaterURLEntry(parent); } - sInstance->updateFromLandMediaPanel(); + sInstance->openFloater(); + sInstance->addURLToCombobox(media_url); return sInstance->getHandle(); } -void LLFloaterURLEntry::updateFromLandMediaPanel() -{ - LLPanelLandMedia* panel_media = (LLPanelLandMedia*)mPanelLandMediaHandle.get(); - if (panel_media) - { - std::string media_url = panel_media->getMediaURL(); - addURLToCombobox(media_url); - } -} + bool LLFloaterURLEntry::addURLToCombobox(const std::string& media_url) { diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index 0aeca823b8..6dd9c8453c 100644 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -44,10 +44,8 @@ class LLFloaterURLEntry : public LLFloater public: // Can only be shown by LLPanelLandMedia, and pushes data back into // that panel via the handle. - static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle); + static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle, const std::string media_url); /*virtual*/ BOOL postBuild(); - void updateFromLandMediaPanel(); - void headerFetchComplete(U32 status, const std::string& mime_type); bool addURLToCombobox(const std::string& media_url); diff --git a/indra/newview/llfloaterwhitelistentry.cpp b/indra/newview/llfloaterwhitelistentry.cpp new file mode 100644 index 0000000000..551a5191fc --- /dev/null +++ b/indra/newview/llfloaterwhitelistentry.cpp @@ -0,0 +1,97 @@ +/** + * @file llfloaterwhitelistentry.cpp + * @brief LLFloaterWhistListEntry class implementation + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterreg.h" +#include "llfloatermediasettings.h" +#include "llfloaterwhitelistentry.h" +#include "llpanelmediasettingssecurity.h" +#include "lluictrlfactory.h" +#include "llwindow.h" +#include "llviewerwindow.h" +#include "lllineeditor.h" + + +/////////////////////////////////////////////////////////////////////////////// +// +LLFloaterWhiteListEntry::LLFloaterWhiteListEntry( const LLSD& key ) : + LLFloater(key) +{ +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_whitelist_entry.xml"); +} + +/////////////////////////////////////////////////////////////////////////////// +// +LLFloaterWhiteListEntry::~LLFloaterWhiteListEntry() +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// +BOOL LLFloaterWhiteListEntry::postBuild() +{ + mWhiteListEdit = getChild<LLLineEditor>("whitelist_entry"); + + childSetAction("cancel_btn", onBtnCancel, this); + childSetAction("ok_btn", onBtnOK, this); + + setDefaultBtn("ok_btn"); + + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterWhiteListEntry::onBtnOK( void* userdata ) +{ + LLFloaterWhiteListEntry *self =(LLFloaterWhiteListEntry *)userdata; + + LLPanelMediaSettingsSecurity* panel = LLFloaterReg::getTypedInstance<LLFloaterMediaSettings>("media_settings")->getPanelSecurity(); + if ( panel ) + { + std::string white_list_item = self->mWhiteListEdit->getText(); + + panel->addWhiteListItem( white_list_item ); + }; + + self->closeFloater(); +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLFloaterWhiteListEntry::onBtnCancel( void* userdata ) +{ + LLFloaterWhiteListEntry *self =(LLFloaterWhiteListEntry *)userdata; + + self->closeFloater(); +} diff --git a/indra/newview/llfloaterwhitelistentry.h b/indra/newview/llfloaterwhitelistentry.h new file mode 100644 index 0000000000..8ab5fb78b9 --- /dev/null +++ b/indra/newview/llfloaterwhitelistentry.h @@ -0,0 +1,56 @@ +/** + * @file llfloaterwhitelistentry.h + * @brief LLFloaterWhiteListEntry class definition + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERWHITELISTENTRY_H +#define LL_LLFLOATERWHITELISTENTRY_H + +#include "llfloater.h" + +class LLLineEditor; + +class LLFloaterWhiteListEntry : + public LLFloater +{ + public: + LLFloaterWhiteListEntry(const LLSD& key); + ~LLFloaterWhiteListEntry(); + + BOOL postBuild(); + + private: + LLLineEditor* mWhiteListEdit; + + static void onBtnOK(void*); + static void onBtnCancel(void*); +}; + +#endif // LL_LLFLOATERWHITELISTENTRY_H diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 2a29566120..d149c8bbb5 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1318,7 +1318,7 @@ void LLFolderView::startRenamingSelectedItem( void ) mRenamer->setVisible( TRUE ); // set focus will fail unless item is visible mRenamer->setFocus( TRUE ); - mRenamer->setTopLostCallback(onRenamerLost); + mRenamer->setTopLostCallback(boost::bind(onRenamerLost, _1)); gFocusMgr.setTopCtrl( mRenamer ); } } @@ -2147,7 +2147,7 @@ void LLFolderView::updateRenamerPosition() ///---------------------------------------------------------------------------- //static -void LLFolderView::onRenamerLost( LLFocusableElement* renamer, void* user_data) +void LLFolderView::onRenamerLost( LLFocusableElement* renamer) { LLUICtrl* uictrl = dynamic_cast<LLUICtrl*>(renamer); if (uictrl) diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index a05dec3193..69c0c5b132 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -279,7 +279,7 @@ protected: LLScrollContainer* mScrollContainer; // NULL if this is not a child of a scroll container. void commitRename( const LLSD& data ); - static void onRenamerLost( LLFocusableElement* renamer, void* user_data); + static void onRenamerLost( LLFocusableElement* renamer); void finishRenamingItem( void ); void closeRenamer( void ); diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index d3b013237b..905857f393 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -73,7 +73,11 @@ LLGroupList::Params::Params() LLGroupList::LLGroupList(const Params& p) : LLFlatListView(p) + , mDirty(true) // to force initial update { + // Listen for agent group changes. + gAgent.addListener(this, "new group"); + mShowIcons = gSavedSettings.getBOOL("GroupListShowIcons"); setCommitOnSelectionChange(true); // TODO: implement context menu @@ -84,17 +88,41 @@ LLGroupList::LLGroupList(const Params& p) setComparator(&GROUP_COMPARATOR); } +LLGroupList::~LLGroupList() +{ + gAgent.removeListener(this); +} + +// virtual +void LLGroupList::draw() +{ + if (mDirty) + refresh(); + + LLFlatListView::draw(); +} + +void LLGroupList::setNameFilter(const std::string& filter) +{ + if (mNameFilter != filter) + { + mNameFilter = filter; + setDirty(); + } +} + static bool findInsensitive(std::string haystack, const std::string& needle_upper) { LLStringUtil::toUpper(haystack); return haystack.find(needle_upper) != std::string::npos; } -BOOL LLGroupList::update(const std::string& name_filter) +void LLGroupList::refresh() { const LLUUID& highlight_id = gAgent.getGroupID(); S32 count = gAgent.mGroups.count(); LLUUID id; + bool have_filter = !mNameFilter.empty(); clear(); @@ -102,7 +130,7 @@ BOOL LLGroupList::update(const std::string& name_filter) { id = gAgent.mGroups.get(i).mID; const LLGroupData& group_data = gAgent.mGroups.get(i); - if (name_filter != LLStringUtil::null && !findInsensitive(group_data.mName, name_filter)) + if (have_filter && !findInsensitive(group_data.mName, mNameFilter)) continue; addNewItem(id, group_data.mName, group_data.mInsigniaID, highlight_id == id, ADD_BOTTOM); } @@ -113,13 +141,14 @@ BOOL LLGroupList::update(const std::string& name_filter) // add "none" to list at top { std::string loc_none = LLTrans::getString("GroupsNone"); - if (name_filter == LLStringUtil::null || findInsensitive(loc_none, name_filter)) + if (have_filter || findInsensitive(loc_none, mNameFilter)) addNewItem(LLUUID::null, loc_none, LLUUID::null, highlight_id.isNull(), ADD_TOP); } selectItemByUUID(highlight_id); - return TRUE; + setDirty(false); + onCommit(); } void LLGroupList::toggleIcons() @@ -158,6 +187,18 @@ void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LL // setCommentVisible(false); } +// virtual +bool LLGroupList::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) +{ + // Why is "new group" sufficient? + if (event->desc() == "new group") + { + setDirty(); + return true; + } + + return false; +} /************************************************************************/ /* LLGroupListItem implementation */ diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h index 7708b58de6..9c3ab88901 100644 --- a/indra/newview/llgrouplist.h +++ b/indra/newview/llgrouplist.h @@ -33,10 +33,19 @@ #ifndef LL_LLGROUPLIST_H #define LL_LLGROUPLIST_H +#include "llevent.h" #include "llflatlistview.h" #include "llpanel.h" +#include "llpointer.h" -class LLGroupList: public LLFlatListView +/** + * Auto-updating list of agent groups. + * + * Can use optional group name filter. + * + * @see setNameFilter() + */ +class LLGroupList: public LLFlatListView, public LLOldEvents::LLSimpleListener { LOG_CLASS(LLGroupList); public: @@ -46,14 +55,23 @@ public: }; LLGroupList(const Params& p); - BOOL update(const std::string& name_filter = LLStringUtil::null); + virtual ~LLGroupList(); + + virtual void draw(); // from LLView + + void setNameFilter(const std::string& filter); void toggleIcons(); bool getIconsVisible() const { return mShowIcons; } - + private: + void setDirty(bool val = true) { mDirty = val; } + void refresh(); void addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, BOOL is_bold, EAddPosition pos = ADD_BOTTOM); + bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata); // called on agent group list changes bool mShowIcons; + bool mDirty; + std::string mNameFilter; }; class LLButton; diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 29102feb64..d0be581f6d 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -48,6 +48,7 @@ #include "lltrans.h" #include "llviewertexteditor.h" #include "llviewerwindow.h" +#include "lltransientfloatermgr.h" @@ -62,33 +63,44 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id) mInputEditor(NULL), mPositioned(false) { - LLIMModel::LLIMSession* session = get_if_there(LLIMModel::instance().sSessionsMap, mSessionID, (LLIMModel::LLIMSession*)NULL); - if(session) + EInstantMessage type = LLIMModel::getInstance()->getType(session_id); + if(IM_COUNT != type) { - mDialog = session->mType; - } + mDialog = type; - if (mDialog == IM_NOTHING_SPECIAL) - { - mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelIMControl, this); - } - else - { - mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelGroupControl, this); + if (IM_NOTHING_SPECIAL == mDialog || IM_SESSION_P2P_INVITE == mDialog) + { + mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelIMControl, this); + } + else + { + mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelGroupControl, this); + } } -// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_im_session.xml"); - - gFocusMgr.addFocusChangeCallback(boost::bind(&LLIMFloater::focusChangeCallback, this)); mCloseSignal.connect(boost::bind(&LLIMFloater::onClose, this)); + + LLTransientFloaterMgr::getInstance()->registerTransientFloater(this); } void LLIMFloater::onClose() { LLIMModel::instance().sendLeaveSession(mSessionID, mOtherParticipantUUID); + + //*TODO - move to the IMModel::sendLeaveSession() for the integrity (IB) gIMMgr->removeSession(mSessionID); } +void LLIMFloater::setMinimized(BOOL minimize) +{ + if(!isDocked()) + { + setVisible(!minimize); + } + + LLFloater::setMinimized(minimize); +} + /* static */ void LLIMFloater::newIMCallback(const LLSD& data){ @@ -152,16 +164,17 @@ void LLIMFloater::sendMsg() LLIMFloater::~LLIMFloater() { + LLTransientFloaterMgr::getInstance()->unregisterTransientFloater(this); } //virtual BOOL LLIMFloater::postBuild() { - LLIMModel::LLIMSession* session = get_if_there(LLIMModel::instance().sSessionsMap, mSessionID, (LLIMModel::LLIMSession*)NULL); - if(session) + const LLUUID& other_party_id = LLIMModel::getInstance()->getOtherParticipantID(mSessionID); + if (other_party_id.notNull()) { - mOtherParticipantUUID = session->mOtherParticipantID; - mControlPanel->setID(session->mOtherParticipantID); + mOtherParticipantUUID = other_party_id; + mControlPanel->setID(mOtherParticipantUUID); } LLButton* slide_left = getChild<LLButton>("slide_left_btn"); @@ -177,8 +190,8 @@ BOOL LLIMFloater::postBuild() // enable line history support for instant message bar mInputEditor->setEnableLineHistory(TRUE); - mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this ); - mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this ); + mInputEditor->setFocusReceivedCallback( boost::bind(onInputEditorFocusReceived, _1, this) ); + mInputEditor->setFocusLostCallback( boost::bind(onInputEditorFocusLost, _1, this) ); mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this ); mInputEditor->setCommitOnFocusLost( FALSE ); mInputEditor->setRevertOnEsc( FALSE ); @@ -216,17 +229,6 @@ void* LLIMFloater::createPanelGroupControl(void* userdata) return self->mControlPanel; } - - -void LLIMFloater::focusChangeCallback() -{ - // hide docked floater if user clicked inside in-world area - if (isDocked() && gFocusMgr.getKeyboardFocus() == NULL) - { - setVisible(false); - } -} - void LLIMFloater::onSlide() { LLPanel* im_control_panel = getChild<LLPanel>("panel_im_control_panel"); @@ -271,13 +273,13 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id) } floater->setDockControl(new LLDockControl(chiclet, floater, floater->getDockTongue(), - LLDockControl::TOP, boost::bind(&LLIMFloater::getEnabledRect, floater, _1))); + LLDockControl::TOP, boost::bind(&LLIMFloater::getAllowedRect, floater, _1))); } return floater; } -void LLIMFloater::getEnabledRect(LLRect& rect) +void LLIMFloater::getAllowedRect(LLRect& rect) { rect = gViewerWindow->getWorldViewRect(); } @@ -285,8 +287,10 @@ void LLIMFloater::getEnabledRect(LLRect& rect) void LLIMFloater::setDocked(bool docked, bool pop_on_undock) { // update notification channel state - LLNotificationsUI::LLScreenChannel* channel = LLNotificationsUI::LLChannelManager::getInstance()-> - findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))); + LLNotificationsUI::LLScreenChannel* channel = dynamic_cast<LLNotificationsUI::LLScreenChannel*> + (LLNotificationsUI::LLChannelManager::getInstance()-> + findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); + LLDockableFloater::setDocked(docked, pop_on_undock); // update notification channel state @@ -298,8 +302,9 @@ void LLIMFloater::setDocked(bool docked, bool pop_on_undock) void LLIMFloater::setVisible(BOOL visible) { - LLNotificationsUI::LLScreenChannel* channel = LLNotificationsUI::LLChannelManager::getInstance()-> - findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))); + LLNotificationsUI::LLScreenChannel* channel = dynamic_cast<LLNotificationsUI::LLScreenChannel*> + (LLNotificationsUI::LLChannelManager::getInstance()-> + findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); LLDockableFloater::setVisible(visible); // update notification channel state diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index 276f38e829..a183212f04 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -57,6 +57,8 @@ public: // LLFloater overrides /*virtual*/ void setDocked(bool docked, bool pop_on_undock = true); + // override LLFloater's minimization according to EXT-1216 + /*virtual*/ void setMinimized(BOOL minimize); // Make IM conversion visible and update the message history static LLIMFloater* show(const LLUUID& session_id); @@ -90,8 +92,8 @@ private: void onSlide(); static void* createPanelIMControl(void* userdata); static void* createPanelGroupControl(void* userdata); - void focusChangeCallback(); - void getEnabledRect(LLRect& rect); + // gets a rect that bounds possible positions for the LLIMFloater on a screen (EXT-1111) + void getAllowedRect(LLRect& rect); LLPanelChatControlPanel* mControlPanel; LLUUID mSessionID; diff --git a/indra/newview/llimhandler.cpp b/indra/newview/llimhandler.cpp index 46067c081f..74971f3fd8 100644 --- a/indra/newview/llimhandler.cpp +++ b/indra/newview/llimhandler.cpp @@ -109,7 +109,9 @@ bool LLIMHandler::processNotification(const LLSD& notify) p.panel = im_box; p.can_be_stored = false; p.on_delete_toast = boost::bind(&LLIMHandler::onDeleteToast, this, _1); - mChannel->addToast(p); + LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel); + if(channel) + channel->addToast(p); // send a signal to the counter manager; mNewNotificationSignal(); diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index de4faf72f5..abd3cd4def 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -940,7 +940,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, mHistoryEditor(NULL), mSessionUUID(session_id), mSessionLabel(session_label), - mVoiceChannel(NULL), mSessionInitialized(FALSE), mSessionStartMsgPos(0), mOtherParticipantUUID(other_participant_id), @@ -956,7 +955,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, mTextIMPossible(TRUE), mProfileButtonEnabled(TRUE), mCallBackEnabled(TRUE), - mSpeakers(NULL), mSpeakerPanel(NULL), mFirstKeystrokeTimer(), mLastKeystrokeTimer() @@ -967,7 +965,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, case IM_SESSION_GROUP_START: mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); xml_filename = "floater_instant_message_group.xml"; - mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel); break; case IM_SESSION_INVITE: mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); @@ -979,16 +976,13 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, { xml_filename = "floater_instant_message_ad_hoc.xml"; } - mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel); break; case IM_SESSION_P2P_INVITE: xml_filename = "floater_instant_message.xml"; - mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mSessionLabel, mOtherParticipantUUID); break; case IM_SESSION_CONFERENCE_START: mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); xml_filename = "floater_instant_message_ad_hoc.xml"; - mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel); break; // just received text from another user case IM_NOTHING_SPECIAL: @@ -998,8 +992,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionUUID); mProfileButtonEnabled = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionUUID); mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionUUID); - - mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mSessionLabel, mOtherParticipantUUID); break; default: llwarns << "Unknown session type" << llendl; @@ -1007,10 +999,6 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, break; } - mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); - // All participants will be added to the list of people we've recently interacted with. - mSpeakers->addListener(&LLRecentPeople::instance(), "add"); - LLUICtrlFactory::getInstance()->buildFloater(this, xml_filename, NULL); setTitle(mSessionLabel); @@ -1058,38 +1046,8 @@ LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, LLFloaterIMPanel::~LLFloaterIMPanel() { - delete mSpeakers; - mSpeakers = NULL; - - // End the text IM session if necessary - if(gVoiceClient && mOtherParticipantUUID.notNull()) - { - switch(mDialog) - { - case IM_NOTHING_SPECIAL: - case IM_SESSION_P2P_INVITE: - gVoiceClient->endUserIMSession(mOtherParticipantUUID); - break; - - default: - // Appease the compiler - break; - } - } - - //kicks you out of the voice channel if it is currently active - - // HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point). - mVoiceChannel->deactivate(); - - delete mVoiceChannel; - mVoiceChannel = NULL; - //delete focus lost callback - if(mInputEditor) - { - mInputEditor->setFocusLostCallback( NULL ); - } + mFocusCallbackConnection.disconnect(); } BOOL LLFloaterIMPanel::postBuild() @@ -1099,8 +1057,8 @@ BOOL LLFloaterIMPanel::postBuild() mVisibleSignal.connect(boost::bind(&LLFloaterIMPanel::onVisibilityChange, this, _2)); mInputEditor = getChild<LLLineEditor>("chat_editor"); - mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this ); - mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this ); + mInputEditor->setFocusReceivedCallback( boost::bind(onInputEditorFocusReceived, _1, this) ); + mFocusCallbackConnection = mInputEditor->setFocusLostCallback( boost::bind(onInputEditorFocusLost, _1, this)); mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this ); mInputEditor->setCommitCallback( onCommitChat, this ); mInputEditor->setCommitOnFocusLost( FALSE ); @@ -1155,7 +1113,8 @@ BOOL LLFloaterIMPanel::postBuild() void* LLFloaterIMPanel::createSpeakersPanel(void* data) { LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)data; - floaterp->mSpeakerPanel = new LLPanelActiveSpeakers(floaterp->mSpeakers, TRUE); + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(floaterp->mSessionUUID); + floaterp->mSpeakerPanel = new LLPanelActiveSpeakers(speaker_mgr, TRUE); return floaterp->mSpeakerPanel; } @@ -1201,12 +1160,14 @@ void LLFloaterIMPanel::draw() && mCallBackEnabled; // hide/show start call and end call buttons - childSetVisible("end_call_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); - childSetVisible("start_call_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->getState() < LLVoiceChannel::STATE_CALL_STARTED); + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionUUID); + childSetVisible("end_call_btn", LLVoiceClient::voiceEnabled() && voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); + childSetVisible("start_call_btn", LLVoiceClient::voiceEnabled() && voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED); childSetEnabled("start_call_btn", enable_connect); childSetEnabled("send_btn", !childGetValue("chat_editor").asString().empty()); - LLPointer<LLSpeaker> self_speaker = mSpeakers->findSpeaker(gAgent.getID()); + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionUUID); + LLPointer<LLSpeaker> self_speaker = speaker_mgr->findSpeaker(gAgent.getID()); if(!mTextIMPossible) { mInputEditor->setEnabled(FALSE); @@ -1230,7 +1191,7 @@ void LLFloaterIMPanel::draw() } // show speakers window when voice first connects - if (mShowSpeakersOnConnect && mVoiceChannel->isActive()) + if (mShowSpeakersOnConnect && voice_channel->isActive()) { childSetVisible("active_speakers_panel", TRUE); mShowSpeakersOnConnect = FALSE; @@ -1266,11 +1227,11 @@ void LLFloaterIMPanel::draw() else { // refresh volume and mute checkbox - childSetVisible("speaker_volume", LLVoiceClient::voiceEnabled() && mVoiceChannel->isActive()); + childSetVisible("speaker_volume", LLVoiceClient::voiceEnabled() && voice_channel->isActive()); childSetValue("speaker_volume", gVoiceClient->getUserVolume(mOtherParticipantUUID)); childSetValue("mute_btn", LLMuteList::getInstance()->isMuted(mOtherParticipantUUID, LLMute::flagVoiceChat)); - childSetVisible("mute_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->isActive()); + childSetVisible("mute_btn", LLVoiceClient::voiceEnabled() && voice_channel->isActive()); } LLFloater::draw(); } @@ -1406,12 +1367,6 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4 { mNumUnreadMessages++; } - - if (source != LLUUID::null) - { - mSpeakers->speakerChatted(source); - mSpeakers->setSpeakerTyping(source, FALSE); - } } @@ -1592,7 +1547,7 @@ void LLFloaterIMPanel::onClickStartCall(void* userdata) { LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - self->mVoiceChannel->activate(); + LLIMModel::getInstance()->getVoiceChannel(self->mSessionUUID)->activate(); } // static @@ -1600,7 +1555,7 @@ void LLFloaterIMPanel::onClickEndCall(void* userdata) { LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - self->getVoiceChannel()->deactivate(); + LLIMModel::getInstance()->getVoiceChannel(self->mSessionUUID)->deactivate(); } // static @@ -1674,7 +1629,8 @@ void LLFloaterIMPanel::onVisibilityChange(const LLSD& new_visibility) mNumUnreadMessages = 0; } - if (new_visibility.asBoolean() && mVoiceChannel->getState() == LLVoiceChannel::STATE_CONNECTED) + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionUUID); + if (new_visibility.asBoolean() && voice_channel->getState() == LLVoiceChannel::STATE_CONNECTED) LLFloaterReg::showInstance("voice_call", mSessionUUID); else LLFloaterReg::hideInstance("voice_call", mSessionUUID); @@ -1726,11 +1682,6 @@ void LLFloaterIMPanel::sendMsg() mSentTypingState = TRUE; } -void LLFloaterIMPanel::updateSpeakersList(const LLSD& speaker_updates) -{ - mSpeakers->updateSpeakers(speaker_updates); -} - void LLFloaterIMPanel::processSessionUpdate(const LLSD& session_update) { if ( @@ -1754,15 +1705,9 @@ void LLFloaterIMPanel::processSessionUpdate(const LLSD& session_update) } } -void LLFloaterIMPanel::setSpeakers(const LLSD& speaker_list) -{ - mSpeakers->setSpeakers(speaker_list); -} - void LLFloaterIMPanel::sessionInitReplyReceived(const LLUUID& session_id) { mSessionUUID = session_id; - mVoiceChannel->updateSessionID(session_id); mSessionInitialized = TRUE; //we assume the history editor hasn't moved at all since @@ -1793,6 +1738,7 @@ void LLFloaterIMPanel::requestAutoConnect() void LLFloaterIMPanel::setTyping(BOOL typing) { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionUUID); if (typing) { // Every time you type something, reset this timer @@ -1807,7 +1753,7 @@ void LLFloaterIMPanel::setTyping(BOOL typing) mSentTypingState = FALSE; } - mSpeakers->setSpeakerTyping(gAgent.getID(), TRUE); + speaker_mgr->setSpeakerTyping(gAgent.getID(), TRUE); } else { @@ -1817,7 +1763,7 @@ void LLFloaterIMPanel::setTyping(BOOL typing) sendTypingState(FALSE); mSentTypingState = TRUE; } - mSpeakers->setSpeakerTyping(gAgent.getID(), FALSE); + speaker_mgr->setSpeakerTyping(gAgent.getID(), FALSE); } mTyping = typing; @@ -1877,7 +1823,7 @@ void LLFloaterIMPanel::removeTypingIndicator(const LLIMInfo* im_info) mHistoryEditor->removeTextFromEnd(chars_to_remove); if (im_info) { - mSpeakers->setSpeakerTyping(im_info->mFromID, FALSE); + LLIMModel::getInstance()->getSpeakerManager(mSessionUUID)->setSpeakerTyping(im_info->mFromID, FALSE); } } } diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index dbf5e1cb6a..fb9b28ad16 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -33,6 +33,7 @@ #ifndef LL_IMPANEL_H #define LL_IMPANEL_H +#include "llimview.h" //for LLIMModel #include "lldockablefloater.h" #include "lllogchat.h" #include "lluuid.h" @@ -245,11 +246,7 @@ public: const LLUUID& getSessionID() const { return mSessionUUID; } const LLUUID& getOtherParticipantID() const { return mOtherParticipantUUID; } - LLIMSpeakerMgr* getSpeakerManager() const { return mSpeakers; } - void updateSpeakersList(const LLSD& speaker_updates); void processSessionUpdate(const LLSD& update); - void setSpeakers(const LLSD& speaker_list); - LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } EInstantMessage getDialogType() const { return mDialog; } void setDialogType(EInstantMessage dialog) { mDialog = dialog; } @@ -305,7 +302,6 @@ private: LLUUID mSessionUUID; std::string mSessionLabel; - LLVoiceChannel* mVoiceChannel; BOOL mSessionInitialized; LLSD mQueuedMsgsForInit; @@ -346,7 +342,6 @@ private: BOOL mProfileButtonEnabled; BOOL mCallBackEnabled; - LLIMSpeakerMgr* mSpeakers; LLPanelActiveSpeakers* mSpeakerPanel; // Optimization: Don't send "User is typing..." until the @@ -357,6 +352,8 @@ private: // Timer to detect when user has stopped typing. LLFrameTimer mLastKeystrokeTimer; + boost::signals2::connection mFocusCallbackConnection; + void disableWhileSessionStarting(); }; diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 3cf78f957b..556eb5ffd7 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -114,10 +114,84 @@ void toast_callback(const LLSD& msg){ LLIMModel::LLIMModel() { - addChangedCallback(toast_callback); addChangedCallback(LLIMFloater::newIMCallback); + addChangedCallback(toast_callback); +} + + +LLIMModel::LLIMSession::LLIMSession( const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id ) +: mSessionID(session_id), + mName(name), + mType(type), + mNumUnread(0), + mOtherParticipantID(other_participant_id), + mVoiceChannel(NULL), + mSpeakers(NULL) +{ + if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type) + { + mVoiceChannel = new LLVoiceChannelP2P(session_id, name, other_participant_id); + } + else + { + mVoiceChannel = new LLVoiceChannelGroup(session_id, name); + } + mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); + + // All participants will be added to the list of people we've recently interacted with. + mSpeakers->addListener(&LLRecentPeople::instance(), "add"); +} + +LLIMModel::LLIMSession::~LLIMSession() +{ + delete mSpeakers; + mSpeakers = NULL; + + // End the text IM session if necessary + if(gVoiceClient && mOtherParticipantID.notNull()) + { + switch(mType) + { + case IM_NOTHING_SPECIAL: + case IM_SESSION_P2P_INVITE: + gVoiceClient->endUserIMSession(mOtherParticipantID); + break; + + default: + // Appease the linux compiler + break; + } + } + + // HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point). + mVoiceChannel->deactivate(); + + delete mVoiceChannel; + mVoiceChannel = NULL; } +LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const +{ + return get_if_there(LLIMModel::instance().sSessionsMap, session_id, + (LLIMModel::LLIMSession*) NULL); +} + +void LLIMModel::updateSessionID(const LLUUID& old_session_id, const LLUUID& new_session_id) +{ + if (new_session_id == old_session_id) return; + + LLIMSession* session = findIMSession(old_session_id); + if (session) + { + session->mSessionID = new_session_id; + session->mVoiceChannel->updateSessionID(new_session_id); + + //*TODO set session initialized flag here? (IB) + + sSessionsMap.erase(old_session_id); + sSessionsMap[new_session_id] = session; + } +} void LLIMModel::testMessages() { @@ -153,7 +227,7 @@ bool LLIMModel::newSession(LLUUID session_id, std::string name, EInstantMessage return false; } - LLIMSession* session = new LLIMSession(name, type, other_participant_id); + LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id); sSessionsMap[session_id] = session; LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, name, other_participant_id); @@ -170,12 +244,12 @@ bool LLIMModel::clearSession(LLUUID session_id) return true; } +//*TODO remake it, instead of returing the list pass it as as parameter (IB) std::list<LLSD> LLIMModel::getMessages(LLUUID session_id, int start_index) { std::list<LLSD> return_list; - LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); - + LLIMSession* session = findIMSession(session_id); if (!session) { llwarns << "session " << session_id << "does not exist " << llendl; @@ -202,13 +276,14 @@ std::list<LLSD> LLIMModel::getMessages(LLUUID session_id, int start_index) mChangedSignal(arg); // TODO: in the future is there a more efficient way to return these + //of course there is - return as parameter (IB) return return_list; } bool LLIMModel::addToHistory(LLUUID session_id, std::string from, std::string utf8_text) { - LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); + LLIMSession* session = findIMSession(session_id); if (!session) { @@ -231,7 +306,7 @@ bool LLIMModel::addToHistory(LLUUID session_id, std::string from, std::string ut bool LLIMModel::addMessage(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text) { - LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); + LLIMSession* session = findIMSession(session_id); if (!session) { @@ -260,9 +335,9 @@ bool LLIMModel::addMessage(LLUUID session_id, std::string from, LLUUID from_id, } -const std::string& LLIMModel::getName(LLUUID session_id) +const std::string& LLIMModel::getName(const LLUUID& session_id) const { - LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); + LLIMSession* session = findIMSession(session_id); if (!session) { @@ -273,6 +348,66 @@ const std::string& LLIMModel::getName(LLUUID session_id) return session->mName; } +const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return -1; + } + + return session->mNumUnread; +} + +const LLUUID& LLIMModel::getOtherParticipantID(const LLUUID& session_id) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return LLUUID::null; + } + + return session->mOtherParticipantID; +} + +EInstantMessage LLIMModel::getType(const LLUUID& session_id) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return IM_COUNT; + } + + return session->mType; +} + +LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return NULL; + } + + return session->mVoiceChannel; +} + +LLIMSpeakerMgr* LLIMModel::getSpeakerManager( const LLUUID& session_id ) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return NULL; + } + + return session->mSpeakers; +} + // TODO get rid of other participant ID void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing) @@ -316,7 +451,7 @@ void LLIMModel::sendLeaveSession(LLUUID session_id, LLUUID other_participant_id) } - +//*TODO update list of messages in a LLIMSession (IB) void LLIMModel::sendMessage(const std::string& utf8_text, const LLUUID& im_session_id, const LLUUID& other_participant_id, @@ -415,9 +550,16 @@ void LLIMModel::sendMessage(const std::string& utf8_text, LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(im_session_id); if (floater) floater->addHistoryLine(history_echo, LLUIColorTable::instance().getColor("IMChatColor"), true, gAgent.getID()); + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); + if (speaker_mgr) + { + speaker_mgr->speakerChatted(gAgentID); + speaker_mgr->setSpeakerTyping(gAgentID, FALSE); + } } // Add the recipient to the recent people list. + //*TODO should be deleted, because speaker manager updates through callback the recent list LLRecentPeople::instance().add(other_participant_id); } @@ -633,10 +775,8 @@ public: { if ( gIMMgr) { - LLFloaterIMPanel* floaterp = - gIMMgr->findFloaterBySession(mSessionID); - - if (floaterp) + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) { //we've accepted our invitation //and received a list of agents that were @@ -650,15 +790,20 @@ public: //but unfortunately, our base that we are receiving here //may not be the most up to date. It was accurate at //some point in time though. - floaterp->setSpeakers(content); + speaker_mgr->setSpeakers(content); //we now have our base of users in the session //that was accurate at some point, but maybe not now //so now we apply all of the udpates we've received //in case of race conditions - floaterp->updateSpeakersList( - gIMMgr->getPendingAgentListUpdates(mSessionID)); + speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(mSessionID)); + } + + LLFloaterIMPanel* floaterp = + gIMMgr->findFloaterBySession(mSessionID); + if (floaterp) + { if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE ) { floaterp->requestAutoConnect(); @@ -1104,6 +1249,12 @@ void LLIMMgr::addMessage( //no session ID...compute new one new_session_id = computeSessionID(dialog, other_participant_id); } + + if (!LLIMModel::getInstance()->findIMSession(new_session_id)) + { + LLIMModel::instance().newSession(session_id, session_name, dialog, other_participant_id); + } + floater = findFloaterBySession(new_session_id); if (!floater) { @@ -1169,6 +1320,14 @@ void LLIMMgr::addMessage( else { floater->addHistoryLine(msg, color, true, other_participant_id, from); // Insert linked name to front of message + + //*TODO consider moving that speaker management stuff into model (IB) + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(new_session_id); + if (speaker_mgr) + { + speaker_mgr->speakerChatted(gAgentID); + speaker_mgr->setSpeakerTyping(gAgentID, FALSE); + } } LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg); @@ -1273,11 +1432,10 @@ LLUUID LLIMMgr::addP2PSession(const std::string& name, { LLUUID session_id = addSession(name, IM_NOTHING_SPECIAL, other_participant_id); - LLFloaterIMPanel* floater = findFloaterBySession(session_id); - if(floater) + LLVoiceChannelP2P* voice_channel = (LLVoiceChannelP2P*) LLIMModel::getInstance()->getSpeakerManager(session_id); + if (voice_channel) { - LLVoiceChannelP2P* voice_channelp = (LLVoiceChannelP2P*)floater->getVoiceChannel(); - voice_channelp->setSessionHandle(voice_session_handle, caller_uri); + voice_channel->setSessionHandle(voice_session_handle, caller_uri); } return session_id; @@ -1312,6 +1470,11 @@ LLUUID LLIMMgr::addSession( LLUUID session_id = computeSessionID(dialog,other_participant_id); + if (!LLIMModel::getInstance()->findIMSession(session_id)) + { + LLIMModel::instance().newSession(session_id, name, dialog, other_participant_id); + } + LLFloaterIMPanel* floater = findFloaterBySession(session_id); if(!floater) { @@ -1335,17 +1498,10 @@ LLUUID LLIMMgr::addSession( noteMutedUsers(floater, ids); } } - else - { - // *TODO: Remove this? Otherwise old communicate window opens on - // second initiation of IM session from People panel? - // floater->openFloater(); - } - //mTabContainer->selectTabPanel(panel); floater->setInputFocus(TRUE); LLIMFloater::show(session_id); - notifyObserverSessionAdded(floater->getSessionID(), name, other_participant_id); - return floater->getSessionID(); + + return session_id; } // This removes the panel referenced by the uuid, and then restores @@ -1705,7 +1861,6 @@ LLFloaterIMPanel* LLIMMgr::createFloater( LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END; LLFloaterChatterBox::getInstance()->addFloater(floater, FALSE, i_pt); mFloaters.insert(floater->getHandle()); - LLIMModel::instance().newSession(session_id, session_label, dialog, other_participant_id); return floater; } @@ -1825,24 +1980,25 @@ public: gIMMgr->updateFloaterSessionID( temp_session_id, session_id); + + LLIMModel::getInstance()->updateSessionID(temp_session_id, session_id); + + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) + { + speaker_mgr->setSpeakers(body); + speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(session_id)); + } + LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id); if (floaterp) { - floaterp->setSpeakers(body); - - //apply updates we've possibly received previously - floaterp->updateSpeakersList( - gIMMgr->getPendingAgentListUpdates(session_id)); - if ( body.has("session_info") ) { floaterp->processSessionUpdate(body["session_info"]); } - - //aply updates we've possibly received previously - floaterp->updateSpeakersList( - gIMMgr->getPendingAgentListUpdates(session_id)); } + gIMMgr->clearPendingAgentListUpdates(session_id); } else @@ -1932,15 +2088,15 @@ public: const LLSD& context, const LLSD& input) const { - LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(input["body"]["session_id"].asUUID()); - if (floaterp) + const LLUUID& session_id = input["body"]["session_id"].asUUID(); + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) { - floaterp->updateSpeakersList( - input["body"]); + speaker_mgr->updateSpeakers(input["body"]); } else { - //we don't have a floater yet..something went wrong + //we don't have a speaker manager yet..something went wrong //we are probably receiving an update here before //a start or an acceptance of an invitation. Race condition. gIMMgr->addPendingAgentListUpdates( diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 219af0705d..9a94d01bb2 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -34,6 +34,8 @@ #define LL_LLIMVIEW_H #include "lldarray.h" +#include "llfloateractivespeakers.h" //for LLIMSpeakerMgr +#include "llimpanel.h" //for voice channels #include "llmodaldialog.h" #include "llinstantmessage.h" #include "lluuid.h" @@ -50,21 +52,40 @@ public: struct LLIMSession { - LLIMSession(std::string name, EInstantMessage type, LLUUID other_participant_id) - :mName(name), mType(type), mNumUnread(0), mOtherParticipantID(other_participant_id) {} - + LLIMSession(const LLUUID& session_id, const std::string& name, + const EInstantMessage& type, const LLUUID& other_participant_id); + virtual ~LLIMSession(); + + LLUUID mSessionID; std::string mName; EInstantMessage mType; LLUUID mOtherParticipantID; S32 mNumUnread; std::list<LLSD> mMsgs; + + LLVoiceChannel* mVoiceChannel; + LLIMSpeakerMgr* mSpeakers; }; LLIMModel(); + //*TODO make it non-static as LLIMMOdel is a singleton (IB) static std::map<LLUUID, LLIMSession*> sSessionsMap; //mapping session_id to session + boost::signals2::signal<void(const LLSD&)> mChangedSignal; + + /** + * Find an IM Session corresponding to session_id + * Returns NULL if the session does not exist + */ + LLIMSession* findIMSession(const LLUUID& session_id) const; + + /** + * Rebind session data to a new session id. + */ + void updateSessionID(const LLUUID& old_session_id, const LLUUID& new_session_id); + boost::signals2::connection addChangedCallback( boost::function<void (const LLSD& data)> cb ); bool newSession(LLUUID session_id, std::string name, EInstantMessage type, LLUUID other_participant_id); @@ -72,10 +93,42 @@ public: std::list<LLSD> getMessages(LLUUID session_id, int start_index = 0); bool addMessage(LLUUID session_id, std::string from, LLUUID other_participant_id, std::string utf8_text); bool addToHistory(LLUUID session_id, std::string from, std::string utf8_text); - //used to get the name of the session, for use as the title - //currently just the other avatar name - const std::string& getName(LLUUID session_id); - + //used to get the name of the session, for use as the title + //currently just the other avatar name + const std::string& getName(const LLUUID& session_id) const; + + /** + * Get number of unread messages in a session with session_id + * Returns -1 if the session with session_id doesn't exist + */ + const S32 getNumUnread(const LLUUID& session_id) const; + + /** + * Get uuid of other participant in a session with session_id + * Returns LLUUID::null if the session doesn't exist + * + * *TODO what to do with other participants in ad-hoc and group chats? + */ + const LLUUID& getOtherParticipantID(const LLUUID& session_id) const; + + /** + * Get type of a session specified by session_id + * Returns EInstantMessage::IM_COUNT if the session does not exist + */ + EInstantMessage getType(const LLUUID& session_id) const; + + /** + * Get voice channel for the session specified by session_id + * Returns NULL if the session does not exist + */ + LLVoiceChannel* getVoiceChannel(const LLUUID& session_id) const; + + /** + * Get im speaker manager for the session specified by session_id + * Returns NULL if the session does not exist + */ + LLIMSpeakerMgr* getSpeakerManager(const LLUUID& session_id) const; + static void sendLeaveSession(LLUUID session_id, LLUUID other_participant_id); static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id, const std::vector<LLUUID>& ids, EInstantMessage dialog); diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp index 2ad83c76b5..0542199fc1 100644 --- a/indra/newview/lllandmarkactions.cpp +++ b/indra/newview/lllandmarkactions.cpp @@ -53,10 +53,15 @@ #include "llagentui.h" -class LLFetchlLandmarkByAgentPos : public LLInventoryCollectFunctor +class LLFetchlLandmarkByPos : public LLInventoryCollectFunctor { - +private: + LLVector3d mPos; public: + LLFetchlLandmarkByPos(const LLVector3d& pos) : + mPos(pos) + {} + /*virtual*/ bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) { if (!item || item->getType() != LLAssetType::AT_LANDMARK) @@ -69,11 +74,10 @@ public: LLVector3d landmark_global_pos; if (!landmark->getGlobalPos(landmark_global_pos)) return false; - LLVector3d a_pos = gAgent.getPositionGlobal(); //we have to round off each coordinates to compare positions properly - return llround(a_pos.mdV[VX]) == llround(landmark_global_pos.mdV[VX]) - && llround(a_pos.mdV[VY]) == llround(landmark_global_pos.mdV[VY]) - && llround(a_pos.mdV[VZ]) == llround(landmark_global_pos.mdV[VZ]); + return llround(mPos.mdV[VX]) == llround(landmark_global_pos.mdV[VX]) + && llround(mPos.mdV[VY]) == llround(landmark_global_pos.mdV[VY]) + && llround(mPos.mdV[VZ]) == llround(landmark_global_pos.mdV[VZ]); } }; @@ -147,12 +151,12 @@ bool LLLandmarkActions::landmarkAlreadyExists() } -LLViewerInventoryItem* LLLandmarkActions::findLandmarkForAgentPos() +LLViewerInventoryItem* LLLandmarkActions::findLandmarkForGlobalPos(const LLVector3d &pos) { // Determine whether there are landmarks pointing to the current parcel. LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; - LLFetchlLandmarkByAgentPos is_current_pos_landmark; + LLFetchlLandmarkByPos is_current_pos_landmark(pos); gInventory.collectDescendentsIf(gInventory.getRootFolderID(), cats, items, @@ -167,6 +171,11 @@ LLViewerInventoryItem* LLLandmarkActions::findLandmarkForAgentPos() return items[0]; } +LLViewerInventoryItem* LLLandmarkActions::findLandmarkForAgentPos() +{ + return findLandmarkForGlobalPos(gAgent.getPositionGlobal()); +} + bool LLLandmarkActions::canCreateLandmarkHere() { LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); diff --git a/indra/newview/lllandmarkactions.h b/indra/newview/lllandmarkactions.h index ce3ed76090..ab8cc4d6a5 100644 --- a/indra/newview/lllandmarkactions.h +++ b/indra/newview/lllandmarkactions.h @@ -53,6 +53,14 @@ public: static bool landmarkAlreadyExists(); /** + * @brief Searches landmark for global position. + * @return Returns landmark or NULL. + * + * *TODO: dzaporozhan: There can be many landmarks for single parcel. + */ + static LLViewerInventoryItem* findLandmarkForGlobalPos(const LLVector3d &pos); + + /** * @brief Searches landmark for agent global position. * @return Returns landmark or NULL. * @@ -60,6 +68,7 @@ public: */ static LLViewerInventoryItem* findLandmarkForAgentPos(); + /** * @brief Checks whether agent has rights to create landmark for current parcel. */ diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 9d14a3fbdc..68dc3854db 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -190,7 +190,6 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) params.max_length_bytes(p.max_chars); params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2)); params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); - params.focus_lost_callback(NULL); params.handle_edit_keys_directly(true); params.commit_on_focus_lost(false); params.follows.flags(FOLLOWS_ALL); @@ -657,8 +656,9 @@ void LLLocationInputCtrl::changeLocationPresentation() { //change location presentation only if user does not select anything and //human-readable region name is being displayed - if(mTextEntry && !mTextEntry->hasSelection() && - !LLSLURL::isSLURL(mTextEntry->getText())) + std::string text = mTextEntry->getText(); + LLStringUtil::trim(text); + if(mTextEntry && !mTextEntry->hasSelection() && !LLSLURL::isSLURL(text)) { //needs unescaped one mTextEntry->setText(LLAgentUI::buildSLURL(false)); diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 09a7edaa43..b996c15a7d 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -36,7 +36,6 @@ #include "llmediactrl.h" // viewer includes -#include "llfloaterhtml.h" #include "llfloaterworldmap.h" #include "lluictrlfactory.h" #include "llurldispatcher.h" @@ -44,6 +43,7 @@ #include "llviewborder.h" #include "llviewercontrol.h" #include "llviewermedia.h" +#include "llviewertexture.h" #include "llviewerwindow.h" #include "llnotifications.h" #include "llweb.h" @@ -64,6 +64,9 @@ LLMediaCtrl::Params::Params() border_visible("border_visible", true), ignore_ui_scale("ignore_ui_scale", true), hide_loading("hide_loading", false), + decouple_texture_size("decouple_texture_size", false), + texture_width("texture_width", 1024), + texture_height("texture_height", 1024), caret_color("caret_color") {} @@ -83,10 +86,12 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : mMediaSource( 0 ), mTakeFocusOnClick( true ), mCurrentNavUrl( "" ), - mLastSetCursor( UI_CURSOR_ARROW ), mStretchToFill( true ), mMaintainAspectRatio ( true ), - mHideLoading (false) + mHideLoading (false), + mDecoupleTextureSize ( false ), + mTextureWidth ( 1024 ), + mTextureHeight ( 1024 ) { { LLColor4 color = p.caret_color().get(); @@ -100,24 +105,29 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : setBorderVisible(p.border_visible()); mHideLoading = p.hide_loading(); + + setDecoupleTextureSize(p.decouple_texture_size()); + + setTextureSize(p.texture_width(), p.texture_height()); - S32 screen_width = mIgnoreUIScale ? - llround((F32)getRect().getWidth() * LLUI::sGLScaleFactor.mV[VX]) : getRect().getWidth(); - S32 screen_height = mIgnoreUIScale ? - llround((F32)getRect().getHeight() * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight(); + if(!getDecoupleTextureSize()) + { + S32 screen_width = mIgnoreUIScale ? + llround((F32)getRect().getWidth() * LLUI::sGLScaleFactor.mV[VX]) : getRect().getWidth(); + S32 screen_height = mIgnoreUIScale ? + llround((F32)getRect().getHeight() * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight(); + + setTextureSize(screen_width, screen_height); + } mMediaTextureID.generate(); - mMediaSource = LLViewerMedia::newMediaImpl(mHomePageUrl, mMediaTextureID, screen_width, screen_height, false, false, "text/html"); - if ( !mMediaSource ) + + // We don't need to create the media source up front anymore unless we have a non-empty home URL to navigate to. + if(!mHomePageUrl.empty()) { - llwarns << "media source create failed " << llendl; - // return; + navigateHome(); } - - mMediaSource->setVisible( getVisible() ); - - mMediaSource->addObserver( this ); - + // FIXME: How do we create a bevel now? // LLRect border_rect( 0, getRect().getHeight() + 2, getRect().getWidth() + 2, 0 ); // mBorder = new LLViewBorder( std::string("web control border"), border_rect, LLViewBorder::BEVEL_IN ); @@ -180,9 +190,10 @@ BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask ) convertInputCoords(x, y); if (mMediaSource) + { mMediaSource->mouseMove(x, y); - - gViewerWindow->setCursor(mLastSetCursor); + gViewerWindow->setCursor(mMediaSource->getLastSetCursor()); + } return TRUE; } @@ -390,19 +401,19 @@ void LLMediaCtrl::onVisibilityChange ( const LLSD& new_visibility ) // void LLMediaCtrl::reshape( S32 width, S32 height, BOOL called_from_parent ) { - S32 screen_width = mIgnoreUIScale ? llround((F32)width * LLUI::sGLScaleFactor.mV[VX]) : width; - S32 screen_height = mIgnoreUIScale ? llround((F32)height * LLUI::sGLScaleFactor.mV[VY]) : height; - -// llinfos << "reshape called with width = " << width << ", height = " << height << llendl; - - // when floater is minimized, these sizes are negative - if ( screen_height > 0 && screen_width > 0 ) + if(!getDecoupleTextureSize()) { - mMediaSource->setSize(screen_width, screen_height); - mForceUpdate = true; - } + S32 screen_width = mIgnoreUIScale ? llround((F32)width * LLUI::sGLScaleFactor.mV[VX]) : width; + S32 screen_height = mIgnoreUIScale ? llround((F32)height * LLUI::sGLScaleFactor.mV[VY]) : height; - LLPanel::reshape( width, height, called_from_parent ); + // when floater is minimized, these sizes are negative + if ( screen_height > 0 && screen_width > 0 ) + { + setTextureSize(screen_width, screen_height); + } + } + + LLUICtrl::reshape( width, height, called_from_parent ); } //////////////////////////////////////////////////////////////////////////////// @@ -476,9 +487,10 @@ void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type) return; } - if (mMediaSource) + if (ensureMediaSourceExists()) { mCurrentNavUrl = url_in; + mMediaSource->setSize(mTextureWidth, mTextureHeight); mMediaSource->navigateTo(url_in, mime_type, mime_type.empty()); } } @@ -514,9 +526,10 @@ void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::str return; } } - if (mMediaSource) + if (ensureMediaSourceExists()) { mCurrentNavUrl = expanded_filename; + mMediaSource->setSize(mTextureWidth, mTextureHeight); mMediaSource->navigateTo(expanded_filename, "text/html", false); } @@ -526,11 +539,11 @@ void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::str // void LLMediaCtrl::navigateHome() { - if( mHomePageUrl.length() ) + if (ensureMediaSourceExists()) { - if (mMediaSource) - mMediaSource->navigateTo(mHomePageUrl); - }; + mMediaSource->setSize(mTextureWidth, mTextureHeight); + mMediaSource->navigateHome(); + } } //////////////////////////////////////////////////////////////////////////////// @@ -538,6 +551,10 @@ void LLMediaCtrl::navigateHome() void LLMediaCtrl::setHomePageUrl( const std::string urlIn ) { mHomePageUrl = urlIn; + if (mMediaSource) + { + mMediaSource->setHomeURL(mHomePageUrl); + } } //////////////////////////////////////////////////////////////////////////////// @@ -547,6 +564,21 @@ bool LLMediaCtrl::setCaretColor(unsigned int red, unsigned int green, unsigned i //NOOP return false; } + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::setTextureSize(S32 width, S32 height) +{ + mTextureWidth = width; + mTextureHeight = height; + + if(mMediaSource) + { + mMediaSource->setSize(mTextureWidth, mTextureHeight); + mForceUpdate = true; + } +} + //////////////////////////////////////////////////////////////////////////////// // std::string LLMediaCtrl::getHomePageUrl() @@ -556,6 +588,38 @@ std::string LLMediaCtrl::getHomePageUrl() //////////////////////////////////////////////////////////////////////////////// // +bool LLMediaCtrl::ensureMediaSourceExists() +{ + if(mMediaSource.isNull()) + { + // If we don't already have a media source, try to create one. + mMediaSource = LLViewerMedia::newMediaImpl(mMediaTextureID, mTextureWidth, mTextureHeight); + if ( mMediaSource ) + { + mMediaSource->setUsedInUI(true); + mMediaSource->setHomeURL(mHomePageUrl); + mMediaSource->setVisible( getVisible() ); + mMediaSource->addObserver( this ); + } + else + { + llwarns << "media source create failed " << llendl; + // return; + } + } + + return !mMediaSource.isNull(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::unloadMediaSource() +{ + mMediaSource = NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +// LLPluginClassMedia* LLMediaCtrl::getMediaPlugin() { return mMediaSource.isNull() ? NULL : mMediaSource->getMediaPlugin(); @@ -575,13 +639,17 @@ void LLMediaCtrl::draw() { return; } + + if(!media_plugin || (!media_plugin->textureValid())) + { + // Don't try to draw without a valid texture + return; + } LLViewerMediaTexture* media_texture = LLViewerTextureManager::findMediaTexture(mMediaTextureID); if (!media_texture ) - { return; - } if ( gRestoreGL == 1 ) { @@ -659,7 +727,7 @@ void LLMediaCtrl::draw() width = llmin(media_plugin->getWidth(), r.getWidth()); height = llmin(media_plugin->getHeight(), r.getHeight()); } - + x_offset = (r.getWidth() - width) / 2; y_offset = (r.getHeight() - height) / 2; @@ -775,24 +843,9 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) case MEDIA_EVENT_CURSOR_CHANGED: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << LL_ENDL; - - std::string cursor = self->getCursorName(); - - if(cursor == "arrow") - mLastSetCursor = UI_CURSOR_ARROW; - else if(cursor == "ibeam") - mLastSetCursor = UI_CURSOR_IBEAM; - else if(cursor == "splith") - mLastSetCursor = UI_CURSOR_SIZEWE; - else if(cursor == "splitv") - mLastSetCursor = UI_CURSOR_SIZENS; - else if(cursor == "hand") - mLastSetCursor = UI_CURSOR_HAND; - else // for anything else, default to the arrow - mLastSetCursor = UI_CURSOR_ARROW; - }; + } break; - + case MEDIA_EVENT_NAVIGATE_BEGIN: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN, url is " << self->getNavigateURI() << LL_ENDL; @@ -898,15 +951,7 @@ void LLMediaCtrl::onClickLinkHref( LLPluginClassMedia* self ) if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 || LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 ) { - // If we spawn a new LLFloaterHTML, assume we want it to - // follow this LLMediaCtrl's trust for whether or - // not to open secondlife:///app/ links. JC. -// const bool open_links_externally = false; -// LLFloaterHtml::getInstance()->show( -// event_in.mStringPayload, -// "Second Life Browser", -// open_links_externally, -// mTrusted); + llwarns << "Dead, unimplemented path that we used to send to the built-in browser long ago." << llendl; } } } diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index a19b3ad67b..5ea03f1e6c 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -37,7 +37,6 @@ #include "lluictrl.h" #include "llframetimer.h" -#include "lldynamictexture.h" class LLViewBorder; class LLUICtrlFactory; @@ -50,7 +49,6 @@ class LLMediaCtrl : public LLViewerMediaEventEmitter { LOG_CLASS(LLMediaCtrl); - public: struct Params : public LLInitParam::Block<Params, LLPanel::Params> { @@ -58,7 +56,11 @@ public: Optional<bool> border_visible, ignore_ui_scale, - hide_loading; + hide_loading, + decouple_texture_size; + + Optional<S32> texture_width, + texture_height; Optional<LLUIColor> caret_color; @@ -127,9 +129,17 @@ public: void setForceUpdate(bool force_update) { mForceUpdate = force_update; } bool getForceUpdate() { return mForceUpdate; } + bool ensureMediaSourceExists(); + void unloadMediaSource(); + LLPluginClassMedia* getMediaPlugin(); bool setCaretColor( unsigned int red, unsigned int green, unsigned int blue ); + + void setDecoupleTextureSize(bool decouple) { mDecoupleTextureSize = decouple; } + bool getDecoupleTextureSize() { return mDecoupleTextureSize; } + + void setTextureSize(S32 width, S32 height); // over-rides @@ -173,10 +183,12 @@ public: bool mAlwaysRefresh; viewer_media_t mMediaSource; bool mTakeFocusOnClick; - ECursorType mLastSetCursor; bool mStretchToFill; bool mMaintainAspectRatio; bool mHideLoading; + bool mDecoupleTextureSize; + S32 mTextureWidth; + S32 mTextureHeight; }; #endif // LL_LLMediaCtrl_H diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index b1db51dd26..19fee20740 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -317,6 +317,7 @@ void LLNavigationBar::onTeleportHistoryMenuItemClicked(const LLSD& userdata) void LLNavigationBar::onLocationSelection() { std::string typed_location = mCmbLocation->getSimple(); + LLStringUtil::trim(typed_location); // Will not teleport to empty location. if (typed_location.empty()) diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index b53bb586f3..8430937933 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -65,6 +65,7 @@ LLNearbyChat::LLNearbyChat(const LLSD& key) : mChatCaptionPanel(NULL), mChatHistoryEditor(NULL) { + m_isDirty = false; } LLNearbyChat::~LLNearbyChat() @@ -181,7 +182,7 @@ LLColor4 nearbychat_get_text_color(const LLChat& chat) return text_color; } -void nearbychat_add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4& color) +void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& color) { std::string line = chat.mText; @@ -194,25 +195,28 @@ void nearbychat_add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, cons bool prepend_newline = true; if (gSavedSettings.getBOOL("ChatShowTimestamps")) { - edit->appendTime(prepend_newline); + mChatHistoryEditor->appendTime(prepend_newline); prepend_newline = false; } // If the msg is from an agent (not yourself though), // extract out the sender name and replace it with the hotlinked name. + + std::string str_URL = chat.mURL; + if (chat.mSourceType == CHAT_SOURCE_AGENT && chat.mFromID != LLUUID::null) { - chat.mURL = llformat("secondlife:///app/agent/%s/about",chat.mFromID.asString().c_str()); + str_URL = llformat("secondlife:///app/agent/%s/about",chat.mFromID.asString().c_str()); } // If the chat line has an associated url, link it up to the name. - if (!chat.mURL.empty() + if (!str_URL.empty() && (line.length() > chat.mFromName.length() && line.find(chat.mFromName,0) == 0)) { std::string start_line = line.substr(0, chat.mFromName.length() + 1); line = line.substr(chat.mFromName.length() + 1); - edit->appendStyledText(start_line, false, prepend_newline, LLStyleMap::instance().lookup(chat.mFromID,chat.mURL)); + mChatHistoryEditor->appendStyledText(start_line, false, prepend_newline, LLStyleMap::instance().lookup(chat.mFromID,str_URL)); prepend_newline = false; } @@ -225,11 +229,9 @@ void nearbychat_add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, cons else if (2 == font_size) font_name = "sansserifbig"; - edit->appendColoredText(line, false, prepend_newline, color, font_name); + mChatHistoryEditor->appendColoredText(line, false, prepend_newline, color, font_name); } - - void LLNearbyChat::addMessage(const LLChat& chat) { LLColor4 color = nearbychat_get_text_color(chat); @@ -254,7 +256,7 @@ void LLNearbyChat::addMessage(const LLChat& chat) mChatHistoryEditor->setParseHighlights(TRUE); if (!chat.mMuted) - nearbychat_add_timestamped_line(mChatHistoryEditor, chat, color); + add_timestamped_line(chat, color); } void LLNearbyChat::onNearbySpeakers() @@ -482,9 +484,16 @@ BOOL LLNearbyChat::handleRightMouseDown(S32 x, S32 y, MASK mask) void LLNearbyChat::onOpen(const LLSD& key ) { - LLNotificationsUI::LLScreenChannel* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); + LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); if(chat_channel) { chat_channel->removeToastsFromChannel(); } } + +void LLNearbyChat::draw () +{ + LLFloater::draw(); +} + + diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h index efa2e479e6..599e6b6859 100644 --- a/indra/newview/llnearbychat.h +++ b/indra/newview/llnearbychat.h @@ -76,7 +76,10 @@ public: virtual void onOpen (const LLSD& key); + virtual void draw (); + private: + void add_timestamped_line(const LLChat& chat, const LLColor4& color); void pinn_panel(); void float_panel(); @@ -86,10 +89,11 @@ private: S32 mStart_X; S32 mStart_Y; - //LLResizeBar* mResizeBar[RESIZE_BAR_COUNT]; LLHandle<LLView> mPopupMenuHandle; LLPanel* mChatCaptionPanel; LLViewerTextEditor* mChatHistoryEditor; + + bool m_isDirty; }; #endif diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp index cec4b9f7c7..1d8789fde0 100644 --- a/indra/newview/llnearbychatbar.cpp +++ b/indra/newview/llnearbychatbar.cpp @@ -190,7 +190,7 @@ BOOL LLNearbyChatBar::postBuild() mChatBox->setCommitCallback(boost::bind(&LLNearbyChatBar::onChatBoxCommit, this)); mChatBox->setKeystrokeCallback(&onChatBoxKeystroke, this); - mChatBox->setFocusLostCallback(&onChatBoxFocusLost, this); + mChatBox->setFocusLostCallback(boost::bind(&onChatBoxFocusLost, _1, this)); mChatBox->setIgnoreArrowKeys(TRUE); mChatBox->setCommitOnFocusLost( FALSE ); diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp index 7eb5d91e53..eb42e83994 100644 --- a/indra/newview/llnearbychathandler.cpp +++ b/indra/newview/llnearbychathandler.cpp @@ -41,30 +41,227 @@ #include "llviewercontrol.h" #include "llfloaterreg.h"//for LLFloaterReg::getTypedInstance +#include "llviewerwindow.h"//for screen channel position //add LLNearbyChatHandler to LLNotificationsUI namespace -namespace LLNotificationsUI{ +using namespace LLNotificationsUI; +//----------------------------------------------------------------------------------------------- +//LLNearbyChatScreenChannel +//----------------------------------------------------------------------------------------------- +LLToastPanelBase* createToastPanel() +{ + LLNearbyChatToastPanel* item = LLNearbyChatToastPanel::createInstance(); + static S32 chat_item_width = 304; + item->setWidth(chat_item_width); + return item; +} + + +class LLNearbyChatScreenChannel: public LLScreenChannelBase +{ +public: + LLNearbyChatScreenChannel(const LLUUID& id):LLScreenChannelBase(id) { mActiveMessages = 0;}; + void init (S32 channel_left, S32 channel_right); + + void addNotification (LLSD& notification); + void arrangeToasts (); + void showToastsBottom (); + + typedef boost::function<LLToastPanelBase* (void )> create_toast_panel_callback_t; + void setCreatePanelCallback(create_toast_panel_callback_t value) { m_create_toast_panel_callback_t = value;} + + void onToastDestroyed (LLToast* toast); + void onToastFade (LLToast* toast); + + // hide all toasts from screen, but not remove them from a channel + virtual void hideToastsFromScreen() + { + }; + // removes all toasts from a channel + virtual void removeToastsFromChannel() + { + for(std::vector<LLToast*>::iterator it = m_active_toasts.begin(); it != m_active_toasts.end(); ++it) + { + LLToast* toast = (*it); + toast->setVisible(FALSE); + toast->stopTimer(); + m_toast_pool.push_back(toast); + + } + m_active_toasts.clear(); + }; + +protected: + void createOverflowToast(S32 bottom, F32 timer); + + create_toast_panel_callback_t m_create_toast_panel_callback_t; + + bool createPoolToast(); + + std::vector<LLToast*> m_active_toasts; + std::list<LLToast*> m_toast_pool; + + S32 mActiveMessages; +}; + +void LLNearbyChatScreenChannel::init(S32 channel_left, S32 channel_right) +{ + S32 channel_top = gViewerWindow->getWorldViewRect().getHeight(); + S32 channel_bottom = gViewerWindow->getWorldViewRect().mBottom; + setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom)); + setVisible(TRUE); +} + + +void LLNearbyChatScreenChannel::createOverflowToast(S32 bottom, F32 timer) +{ + //we don't need overflow toast in nearby chat +} + +void LLNearbyChatScreenChannel::onToastDestroyed(LLToast* toast) +{ +} + +void LLNearbyChatScreenChannel::onToastFade(LLToast* toast) +{ + //fade mean we put toast to toast pool + if(!toast) + return; + m_toast_pool.push_back(toast); + + std::vector<LLToast*>::iterator pos = std::find(m_active_toasts.begin(),m_active_toasts.end(),toast); + if(pos!=m_active_toasts.end()) + m_active_toasts.erase(pos); + + arrangeToasts(); +} + + +bool LLNearbyChatScreenChannel::createPoolToast() +{ + LLToastPanelBase* panel= m_create_toast_panel_callback_t(); + if(!panel) + return false; + + LLToast::Params p; + p.panel = panel; + + LLToast* toast = new LLToast(p); + + + toast->setOnFadeCallback(boost::bind(&LLNearbyChatScreenChannel::onToastFade, this, _1)); + toast->setOnToastDestroyedCallback(boost::bind(&LLNearbyChatScreenChannel::onToastDestroyed, this, _1)); + + m_toast_pool.push_back(toast); + return true; +} + +void LLNearbyChatScreenChannel::addNotification(LLSD& notification) +{ + //look in pool. if there is any message + + + if(m_toast_pool.empty()) + { + //"pool" is empty - create one more panel + if(!createPoolToast())//created toast will go to pool. so next call will find it + return; + addNotification(notification); + return; + } + + //take 1st element from pool, (re)initialize it, put it in active toasts + + LLToast* toast = m_toast_pool.back(); + + m_toast_pool.pop_back(); + + + LLToastPanelBase* panel = dynamic_cast<LLToastPanelBase*>(toast->getPanel()); + if(!panel) + return; + panel->init(notification); + + toast->reshapeToPanel(); + toast->resetTimer(); + + m_active_toasts.insert(m_active_toasts.begin(),toast); + + arrangeToasts(); +} + +void LLNearbyChatScreenChannel::arrangeToasts() +{ + if(m_active_toasts.size() == 0 || mIsHovering) + return; + + hideToastsFromScreen(); + + showToastsBottom(); +} + +void LLNearbyChatScreenChannel::showToastsBottom() +{ + LLRect rect = getRect(); + + LLRect toast_rect; + S32 bottom = getRect().mBottom; + + for(std::vector<LLToast*>::iterator it = m_active_toasts.begin(); it != m_active_toasts.end(); ++it) + { + LLToast* toast = (*it); + toast_rect = toast->getRect(); + toast_rect.setLeftTopAndSize(getRect().mLeft, bottom + toast_rect.getHeight()+gSavedSettings.getS32("ToastMargin"), toast_rect.getWidth() ,toast_rect.getHeight()); + + toast->setRect(toast_rect); + + if(toast->getRect().mTop > getRect().getHeight()) + { + while(it!=m_active_toasts.end()) + { + (*it)->setVisible(FALSE); + (*it)->stopTimer(); + m_toast_pool.push_back(*it); + it=m_active_toasts.erase(it); + } + break; + } + toast->setVisible(TRUE); + bottom = toast->getRect().mTop; + } +} + + +//----------------------------------------------------------------------------------------------- +//LLNearbyChatHandler +//----------------------------------------------------------------------------------------------- LLNearbyChatHandler::LLNearbyChatHandler(e_notification_type type, const LLSD& id) { mType = type; - LLChannelManager::Params p; - p.id = LLUUID(gSavedSettings.getString("NearByChatChannelUUID")); // Getting a Channel for our notifications - mChannel = LLChannelManager::getInstance()->getChannel(p); + LLNearbyChatScreenChannel* channel = new LLNearbyChatScreenChannel(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); + + LLNearbyChatScreenChannel::create_toast_panel_callback_t callback = createToastPanel; + + channel->setCreatePanelCallback(callback); + + mChannel = LLChannelManager::getInstance()->addChannel(channel); mChannel->setOverflowFormatString("You have %d unread nearby chat messages"); } + LLNearbyChatHandler::~LLNearbyChatHandler() { } + void LLNearbyChatHandler::initChannel() { LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); S32 channel_right_bound = nearby_chat->getRect().mRight; - S32 channel_width = nearby_chat->getRect().mRight - 16; //HACK: 16 - ? + S32 channel_width = nearby_chat->getRect().mRight; mChannel->init(channel_right_bound - channel_width, channel_right_bound); } @@ -77,41 +274,42 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg) if(chat_msg.mText.empty()) return;//don't process empty messages - + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); nearby_chat->addMessage(chat_msg); if(nearby_chat->getVisible()) return;//no need in toast if chat is visible - + // arrange a channel on a screen if(!mChannel->getVisible()) { initChannel(); } - + LLUUID id; id.generate(); - LLChatItemCtrl* item = LLChatItemCtrl::createInstance(); - - item->setMessage(chat_msg); - //static S32 chat_item_width = nearby_chat->getRect().getWidth() - 16; - static S32 chat_item_width = 304; - item->setWidth(chat_item_width); - item->setHeaderVisibility((EShowItemHeader)gSavedSettings.getS32("nearbychat_showicons_and_names")); + LLNearbyChatScreenChannel* channel = dynamic_cast<LLNearbyChatScreenChannel*>(mChannel); - item->setVisible(true); - LLToast::Params p; - p.notif_id = id; - p.panel = item; - p.on_delete_toast = boost::bind(&LLNearbyChatHandler::onDeleteToast, this, _1); - mChannel->addToast(p); + if(channel) + { + LLSD notification; + notification["id"] = id; + notification["message"] = chat_msg.mText; + notification["from"] = chat_msg.mFromName; + notification["from_id"] = chat_msg.mFromID; + notification["time"] = chat_msg.mTime; + notification["source"] = (S32)chat_msg.mSourceType; + + channel->addNotification(notification); + } + } void LLNearbyChatHandler::onDeleteToast(LLToast* toast) { } -} + diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp index 3893eaa0d4..1be03cef0b 100644 --- a/indra/newview/llnotificationalerthandler.cpp +++ b/indra/newview/llnotificationalerthandler.cpp @@ -55,7 +55,7 @@ LLAlertHandler::LLAlertHandler(e_notification_type type, const LLSD& id) : mIsMo // Getting a Channel for our notifications mChannel = LLChannelManager::getInstance()->getChannel(p); - mChannel->setShowToasts(true); + mChannel->setCanStoreToasts(false); } //-------------------------------------------------------------------------- @@ -100,16 +100,23 @@ bool LLAlertHandler::processNotification(const LLSD& notify) p.can_fade = false; p.is_modal = mIsModal; p.on_delete_toast = boost::bind(&LLAlertHandler::onDeleteToast, this, _1); - mChannel->addToast(p); + + LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel); + if(channel) + channel->addToast(p); } else if (notify["sigtype"].asString() == "change") { LLToastAlertPanel* alert_dialog = new LLToastAlertPanel(notification, mIsModal); - mChannel->modifyToastByNotificationID(notification->getID(), (LLToastPanel*)alert_dialog); + LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel); + if(channel) + channel->modifyToastByNotificationID(notification->getID(), (LLToastPanel*)alert_dialog); } else { - mChannel->killToastByNotificationID(notification->getID()); + LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel); + if(channel) + channel->killToastByNotificationID(notification->getID()); } return true; } diff --git a/indra/newview/llnotificationgrouphandler.cpp b/indra/newview/llnotificationgrouphandler.cpp index c488d37ea5..ffa92b543c 100644 --- a/indra/newview/llnotificationgrouphandler.cpp +++ b/indra/newview/llnotificationgrouphandler.cpp @@ -89,7 +89,10 @@ bool LLGroupHandler::processNotification(const LLSD& notify) p.notification = notification; p.panel = notify_box; p.on_delete_toast = boost::bind(&LLGroupHandler::onDeleteToast, this, _1); - mChannel->addToast(p); + + LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel); + if(channel) + channel->addToast(p); // send a signal to the counter manager mNewNotificationSignal(); diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index 90ff5fbaac..cd4e640ec4 100644 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -104,8 +104,8 @@ protected: // at the moment, when a handlers creates a channel. virtual void initChannel()=0; - LLScreenChannel* mChannel; - e_notification_type mType; + LLScreenChannelBase* mChannel; + e_notification_type mType; }; diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp index 72855ac0fd..070af432d6 100644 --- a/indra/newview/llnotificationscripthandler.cpp +++ b/indra/newview/llnotificationscripthandler.cpp @@ -48,7 +48,11 @@ LLScriptHandler::LLScriptHandler(e_notification_type type, const LLSD& id) // Getting a Channel for our notifications mChannel = LLChannelManager::getInstance()->createNotificationChannel(); mChannel->setControlHovering(true); - mChannel->setOnRejectToastCallback(boost::bind(&LLScriptHandler::onRejectToast, this, _1)); + + LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel); + if(channel) + channel->setOnRejectToastCallback(boost::bind(&LLScriptHandler::onRejectToast, this, _1)); + } //-------------------------------------------------------------------------- @@ -92,7 +96,10 @@ bool LLScriptHandler::processNotification(const LLSD& notify) p.notification = notification; p.panel = notify_box; p.on_delete_toast = boost::bind(&LLScriptHandler::onDeleteToast, this, _1); - mChannel->addToast(p); + + LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel); + if(channel) + channel->addToast(p); // send a signal to the counter manager mNewNotificationSignal(); diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp index 740acb6365..5186a93569 100644 --- a/indra/newview/llnotificationtiphandler.cpp +++ b/indra/newview/llnotificationtiphandler.cpp @@ -93,8 +93,9 @@ bool LLTipHandler::processNotification(const LLSD& notify) p.is_tip = true; p.can_be_stored = false; - mChannel->addToast(p); - + LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel); + if(channel) + channel->addToast(p); } else if (notify["sigtype"].asString() == "delete") { diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp index 6e1dc6940e..d9cdf2e04f 100644 --- a/indra/newview/lloutputmonitorctrl.cpp +++ b/indra/newview/lloutputmonitorctrl.cpp @@ -129,7 +129,7 @@ void LLOutputMonitorCtrl::draw() const F32 LEVEL_1 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL * 2.f / 3.f; const F32 LEVEL_2 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL; - if (mIsParentVisible && getVisible() && mAutoUpdate && !mIsMuted && mSpeakerId.notNull()) + if (getVisible() && mAutoUpdate && !mIsMuted && mSpeakerId.notNull()) { setPower(gVoiceClient->getCurrentPower(mSpeakerId)); setIsTalking(gVoiceClient->getIsSpeaking(mSpeakerId)); @@ -220,12 +220,6 @@ void LLOutputMonitorCtrl::draw() gl_rect_2d(0, monh, monw, 0, sColorBound, FALSE); } -void LLOutputMonitorCtrl::handleVisibilityChange(BOOL new_visibility) -{ - mIsParentVisible = new_visibility; - LLView::handleVisibilityChange(new_visibility); -} - void LLOutputMonitorCtrl::setSpeakerId(const LLUUID& speaker_id) { if (speaker_id.isNull()) return; diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h index 0e213c4326..7a7b8bc3a1 100644 --- a/indra/newview/lloutputmonitorctrl.h +++ b/indra/newview/lloutputmonitorctrl.h @@ -72,8 +72,6 @@ public: // llview overrides virtual void draw(); - void handleVisibilityChange(BOOL new_visibility); - void setPower(F32 val); F32 getPower(F32 val) const { return mPower; } @@ -104,8 +102,6 @@ private: F32 mPower; bool mIsMuted; bool mIsTalking; - /** Stores flag whether parent is visible. If not it will not update indicator*/ - bool mIsParentVisible; LLPointer<LLUIImage> mImageMute; LLPointer<LLUIImage> mImageOff; LLPointer<LLUIImage> mImageOn; diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 649697e091..7ccff73080 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -313,7 +313,7 @@ void LLPanelProfileTab::scrollToTop() { LLScrollContainer* scrollContainer = findChild<LLScrollContainer>("profile_scroll"); if (scrollContainer) - scrollContainer->goToTop(); + scrollContainer->goToTop(); } ////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index ee5d265220..7eaee92778 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -238,13 +238,13 @@ BOOL LLPanelClassified::postBuild() mNameEditor = getChild<LLLineEditor>("given_name_editor"); mNameEditor->setMaxTextLength(DB_PARCEL_NAME_LEN); mNameEditor->setCommitOnFocusLost(TRUE); - mNameEditor->setFocusReceivedCallback(focusReceived, this); + mNameEditor->setFocusReceivedCallback(boost::bind(focusReceived, _1, this)); mNameEditor->setCommitCallback(onCommitAny, this); mNameEditor->setPrevalidate( LLLineEditor::prevalidateASCII ); mDescEditor = getChild<LLTextEditor>("desc_editor"); mDescEditor->setCommitOnFocusLost(TRUE); - mDescEditor->setFocusReceivedCallback(focusReceived, this); + mDescEditor->setFocusReceivedCallback(boost::bind(focusReceived, _1, this)); mDescEditor->setCommitCallback(onCommitAny, this); mLocationEditor = getChild<LLLineEditor>("location_editor"); diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index 5da646497b..ea528a1df8 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -72,6 +72,13 @@ // // Globals // +const char* LLPanelContents::TENTATIVE_SUFFIX = "_tentative"; +const char* LLPanelContents::PERMS_OWNER_INTERACT_KEY = "perms_owner_interact"; +const char* LLPanelContents::PERMS_OWNER_CONTROL_KEY = "perms_owner_control"; +const char* LLPanelContents::PERMS_GROUP_INTERACT_KEY = "perms_group_interact"; +const char* LLPanelContents::PERMS_GROUP_CONTROL_KEY = "perms_group_control"; +const char* LLPanelContents::PERMS_ANYONE_INTERACT_KEY = "perms_anyone_interact"; +const char* LLPanelContents::PERMS_ANYONE_CONTROL_KEY = "perms_anyone_control"; BOOL LLPanelContents::postBuild() { @@ -83,7 +90,7 @@ BOOL LLPanelContents::postBuild() childSetAction("button permissions",&LLPanelContents::onClickPermissions, this); mPanelInventory = getChild<LLPanelInventory>("contents_inventory"); - + return TRUE; } @@ -112,7 +119,7 @@ void LLPanelContents::getState(LLViewerObject *objectp ) LLSelectMgr::getInstance()->selectGetGroup(group_id); // sets group_id as a side effect SL-23488 // BUG? Check for all objects being editable? - BOOL editable = gAgent.isGodlike() + bool editable = gAgent.isGodlike() || (objectp->permModify() && ( objectp->permYouOwner() || ( !group_id.isNull() && gAgent.isInGroup(group_id) ))); // solves SL-23488 BOOL all_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ); @@ -123,8 +130,8 @@ void LLPanelContents::getState(LLViewerObject *objectp ) all_volume && ((LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1) || (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1))); -} +} void LLPanelContents::refresh() { @@ -135,7 +142,7 @@ void LLPanelContents::refresh() if (mPanelInventory) { mPanelInventory->refresh(); - } + } } diff --git a/indra/newview/llpanelcontents.h b/indra/newview/llpanelcontents.h index de1914bff9..bab980b524 100644 --- a/indra/newview/llpanelcontents.h +++ b/indra/newview/llpanelcontents.h @@ -51,11 +51,23 @@ public: void refresh(); - static void onClickNewScript( void* userdata); - static void onClickPermissions( void* userdata); + + static void onClickNewScript(void*); + static void onClickPermissions(void*); + + // Key suffix for "tentative" fields + static const char* TENTATIVE_SUFFIX; + + // These aren't fields in LLMediaEntry, so we have to define them ourselves for checkbox control + static const char* PERMS_OWNER_INTERACT_KEY; + static const char* PERMS_OWNER_CONTROL_KEY; + static const char* PERMS_GROUP_INTERACT_KEY; + static const char* PERMS_GROUP_CONTROL_KEY; + static const char* PERMS_ANYONE_INTERACT_KEY; + static const char* PERMS_ANYONE_CONTROL_KEY; protected: - void getState(LLViewerObject *object); + void getState(LLViewerObject *object); public: LLPanelInventory* mPanelInventory; diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 08a50d4b6e..c61b987b1c 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -49,6 +49,7 @@ #include "llcombobox.h" #include "lldrawpoolbump.h" #include "lllineeditor.h" +#include "llmediaentry.h" #include "llresmgr.h" #include "llselectmgr.h" #include "llspinctrl.h" @@ -61,6 +62,7 @@ #include "llviewermedia.h" #include "llviewerobject.h" #include "llviewerstats.h" +#include "llvovolume.h" #include "lluictrlfactory.h" #include "llpluginclassmedia.h" @@ -70,6 +72,18 @@ BOOL LLPanelFace::postBuild() { + childSetCommitCallback("combobox shininess",&LLPanelFace::onCommitShiny,this); + childSetCommitCallback("combobox bumpiness",&LLPanelFace::onCommitBump,this); + childSetCommitCallback("TexScaleU",&LLPanelFace::onCommitTextureInfo, this); + childSetCommitCallback("checkbox flip s",&LLPanelFace::onCommitTextureInfo, this); + childSetCommitCallback("TexScaleV",&LLPanelFace::onCommitTextureInfo, this); + childSetCommitCallback("checkbox flip t",&LLPanelFace::onCommitTextureInfo, this); + childSetCommitCallback("TexRot",&LLPanelFace::onCommitTextureInfo, this); + childSetAction("button apply",&LLPanelFace::onClickApply,this); + childSetCommitCallback("TexOffsetU",LLPanelFace::onCommitTextureInfo, this); + childSetCommitCallback("TexOffsetV",LLPanelFace::onCommitTextureInfo, this); + childSetAction("button align",&LLPanelFace::onClickAutoFix,this); + LLRect rect = this->getRect(); LLTextureCtrl* mTextureCtrl; LLColorSwatchCtrl* mColorSwatch; @@ -91,7 +105,7 @@ BOOL LLPanelFace::postBuild() mTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitTexture, this, _2) ); mTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelTexture, this, _2) ); mTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectTexture, this, _2) ); - mTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, _2)); + mTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2)); mTextureCtrl->setFollowsTop(); mTextureCtrl->setFollowsLeft(); // Don't allow (no copy) or (no transfer) textures to be selected during immediate mode @@ -161,17 +175,6 @@ BOOL LLPanelFace::postBuild() mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this); } - childSetCommitCallback("combobox shininess",&LLPanelFace::onCommitShiny,this); - childSetCommitCallback("combobox bumpiness",&LLPanelFace::onCommitBump,this); - childSetCommitCallback("TexScaleU",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("checkbox flip s",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("TexScaleV",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("checkbox flip t",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("TexRot",&LLPanelFace::onCommitTextureInfo, this); - childSetAction("button apply",&onClickApply,this); - childSetCommitCallback("TexOffsetU",LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("TexOffsetV",LLPanelFace::onCommitTextureInfo, this); - childSetAction("button align",onClickAutoFix,this); clearCtrls(); @@ -382,10 +385,8 @@ void LLPanelFace::getState() BOOL editable = objectp->permModify(); // only turn on auto-adjust button if there is a media renderer and the media is loaded - childSetEnabled("textbox autofix",FALSE); - //mLabelTexAutoFix->setEnabled ( FALSE ); - childSetEnabled("button align",FALSE); - //mBtnAutoFix->setEnabled ( FALSE ); + childSetEnabled("textbox autofix", editable); + childSetEnabled("button align", editable); //if ( LLMediaEngine::getInstance()->getMediaRenderer () ) // if ( LLMediaEngine::getInstance()->getMediaRenderer ()->isLoaded () ) @@ -785,6 +786,9 @@ void LLPanelFace::getState() childSetEnabled("button align",FALSE); childSetEnabled("button apply",FALSE); + childSetEnabled("has media", FALSE); + childSetEnabled("media info set", FALSE); + } } @@ -862,7 +866,7 @@ void LLPanelFace::onCommitGlow(LLUICtrl* ctrl, void* userdata) } // static -BOOL LLPanelFace::onDragTexture(LLInventoryItem* item) +BOOL LLPanelFace::onDragTexture(LLUICtrl*, LLInventoryItem* item) { BOOL accept = TRUE; for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); @@ -917,15 +921,25 @@ void LLPanelFace::onClickApply(void* userdata) LLSelectMgr::getInstance()->selectionTexScaleAutofit( repeats_per_meter ); } -// commit the fit media texture to prim button - struct LLPanelFaceSetMediaFunctor : public LLSelectedTEFunctor { virtual bool apply(LLViewerObject* object, S32 te) { - // TODO: the media impl pointer should actually be stored by the texture - viewer_media_t pMediaImpl = LLViewerMedia::getMediaImplFromTextureID(object->getTE ( te )->getID()); - // only do this if it's a media texture + viewer_media_t pMediaImpl; + + const LLTextureEntry* tep = object->getTE(te); + const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL; + if ( mep ) + { + pMediaImpl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + } + + if ( pMediaImpl.isNull()) + { + // If we didn't find face media for this face, check whether this face is showing parcel media. + pMediaImpl = LLViewerMedia::getMediaImplFromTextureID(tep->getID()); + } + if ( pMediaImpl.notNull()) { LLPluginClassMedia *media = pMediaImpl->getMediaPlugin(); @@ -957,3 +971,14 @@ void LLPanelFace::onClickAutoFix(void* userdata) LLPanelFaceSendFunctor sendfunc; LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc); } + + + +// TODO: I don't know who put these in or what these are for??? +void LLPanelFace::setMediaURL(const std::string& url) +{ +} +void LLPanelFace::setMediaType(const std::string& mime_type) +{ +} + diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 9600129696..6a8704ce14 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -47,6 +47,7 @@ class LLTextBox; class LLTextureCtrl; class LLUICtrl; class LLViewerObject; +class LLFloater; class LLPanelFace : public LLPanel { @@ -56,6 +57,8 @@ public: virtual ~LLPanelFace(); void refresh(); + void setMediaURL(const std::string& url); + void setMediaType(const std::string& mime_type); protected: void getState(); @@ -69,9 +72,10 @@ protected: void sendShiny(); // applies and sends shininess void sendFullbright(); // applies and sends full bright void sendGlow(); + void sendMedia(); // this function is to return TRUE if the drag should succeed. - static BOOL onDragTexture(LLInventoryItem* item); + static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item); void onCommitTexture(const LLSD& data); void onCancelTexture(const LLSD& data); @@ -87,10 +91,11 @@ protected: static void onCommitShiny( LLUICtrl* ctrl, void* userdata); static void onCommitFullbright( LLUICtrl* ctrl, void* userdata); static void onCommitGlow( LLUICtrl* ctrl, void *userdata); - + static void onClickApply(void*); static void onClickAutoFix(void*); static F32 valueGlow(LLViewerObject* object, S32 face); + }; #endif diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 490c845c94..2b584910a3 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -195,7 +195,7 @@ BOOL LLPanelGroup::postBuild() if(panel_land) mTabs.push_back(panel_land); if(panel_general) - panel_general->setupCtrls(this); + panel_general->setupCtrls(this); return TRUE; } @@ -206,8 +206,8 @@ void LLPanelGroup::reposButton(const std::string& name) if(!button) return; LLRect btn_rect = button->getRect(); - btn_rect.setLeftTopAndSize( btn_rect.mLeft, btn_rect.getHeight() + 2, btn_rect.getWidth(), btn_rect.getHeight()); - button->setRect(btn_rect); + btn_rect.setLeftTopAndSize( btn_rect.mLeft, btn_rect.getHeight() + 2, btn_rect.getWidth(), btn_rect.getHeight()); + button->setRect(btn_rect); } void LLPanelGroup::reshape(S32 width, S32 height, BOOL called_from_parent ) @@ -235,7 +235,14 @@ void LLPanelGroup::onBtnCreate() if(!panel_general) return; std::string apply_mesg; - panel_general->apply(apply_mesg);//yes yes you need to call apply to create... + if(panel_general->apply(apply_mesg))//yes yes you need to call apply to create... + return; + if ( !apply_mesg.empty() ) + { + LLSD args; + args["MESSAGE"] = apply_mesg; + LLNotifications::instance().add("GenericAlert", args); + } } void LLPanelGroup::onBtnRefresh(void* user_data) diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index d63fd141b0..2e1d971995 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -99,8 +99,8 @@ BOOL LLPanelGroupGeneral::postBuild() if(mEditCharter) { mEditCharter->setCommitCallback(onCommitAny, this); - mEditCharter->setFocusReceivedCallback(onFocusEdit, this); - mEditCharter->setFocusChangedCallback(onFocusEdit, this); + mEditCharter->setFocusReceivedCallback(boost::bind(onFocusEdit, _1, this)); + mEditCharter->setFocusChangedCallback(boost::bind(onFocusEdit, _1, this)); } @@ -835,6 +835,7 @@ void LLPanelGroupGeneral::reset() { std::string empty_str = ""; mEditCharter->setText(empty_str); + mGroupNameEditor->setText(empty_str); } { @@ -850,6 +851,7 @@ void LLPanelGroupGeneral::reset() { mComboMature->setEnabled(true); mComboMature->setVisible( !gAgent.isTeen() ); + mComboMature->selectFirstItem(); } diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 378a09e315..99bb760b61 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1730,7 +1730,7 @@ BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root) mRoleDescription->setCommitOnFocusLost(TRUE); mRoleDescription->setCommitCallback(onDescriptionCommit, this); - mRoleDescription->setFocusReceivedCallback(onDescriptionFocus, this); + mRoleDescription->setFocusReceivedCallback(boost::bind(onDescriptionFocus, _1, this)); setFooterEnabled(FALSE); diff --git a/indra/newview/llpanellandmedia.cpp b/indra/newview/llpanellandmedia.cpp index 994bf7e3f9..42ad9820a8 100644 --- a/indra/newview/llpanellandmedia.cpp +++ b/indra/newview/llpanellandmedia.cpp @@ -122,9 +122,6 @@ BOOL LLPanelLandMedia::postBuild() mSetURLButton = getChild<LLButton>("set_media_url"); childSetAction("set_media_url", onSetBtn, this); - mResetURLButton = getChild<LLButton>("reset_media_url"); - childSetAction("reset_media_url", onResetBtn, this); - return TRUE; } @@ -215,13 +212,7 @@ void LLPanelLandMedia::refresh() mMediaTextureCtrl->setEnabled( can_change_media ); mSetURLButton->setEnabled( can_change_media ); - mResetURLButton->setEnabled( can_change_media ); - LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mURLEntryFloater.get(); - if (floater_url_entry) - { - floater_url_entry->updateFromLandMediaPanel(); - } } } @@ -341,7 +332,7 @@ void LLPanelLandMedia::onCommitAny(LLUICtrl*, void *userdata) void LLPanelLandMedia::onSetBtn(void *userdata) { LLPanelLandMedia *self = (LLPanelLandMedia *)userdata; - self->mURLEntryFloater = LLFloaterURLEntry::show( self->getHandle() ); + self->mURLEntryFloater = LLFloaterURLEntry::show( self->getHandle(), self->getMediaURL() ); LLFloater* parent_floater = gFloaterView->getParentFloater(self); if (parent_floater) { diff --git a/indra/newview/llpanellandmedia.h b/indra/newview/llpanellandmedia.h index 5ad1f9758d..3deea29d17 100644 --- a/indra/newview/llpanellandmedia.h +++ b/indra/newview/llpanellandmedia.h @@ -63,8 +63,6 @@ private: LLLineEditor* mMediaDescEdit; LLComboBox* mMediaTypeCombo; LLButton* mSetURLButton; - LLButton* mResetURLButton; - LLSpinCtrl* mMediaResetCtrl; LLSpinCtrl* mMediaHeightCtrl; LLSpinCtrl* mMediaWidthCtrl; LLTextBox* mMediaResetCtrlLabel; @@ -74,13 +72,6 @@ private: LLCheckBoxCtrl* mMediaLoopCheck; LLCheckBoxCtrl* mMediaUrlCheck; LLHandle<LLFloater> mURLEntryFloater; - LLCheckBoxCtrl* mMediaNavigateAllowCheck; - LLCheckBoxCtrl* mMediaURLFilterCheck; - LLLineEditor* mMediaURLFilterDomainEdit; - LLButton* mMediaURLFilterAddButton; - LLButton* mMediaURLFilterRemoveButton; - LLScrollListCtrl* mURLFilterList; - LLRadioGroup* mRadioNavigateControl; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 150fd399c6..a7f66f3293 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -57,6 +57,7 @@ #include "lluiconstants.h" #include "llurlsimstring.h" #include "llviewerbuild.h" +#include "llviewerhelp.h" #include "llviewertexturelist.h" #include "llviewermenu.h" // for handle_preferences() #include "llviewernetwork.h" @@ -69,7 +70,7 @@ #include "llmediactrl.h" #include "llrootview.h" -#include "llfloatermediabrowser.h" + #include "llfloatertos.h" #include "lltrans.h" #include "llglheaders.h" @@ -229,7 +230,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo"); server_choice_combo->setCommitCallback(onSelectServer, NULL); - server_choice_combo->setFocusLostCallback(onServerComboLostFocus); + server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1)); childSetAction("connect_btn", onClickConnect, this); @@ -412,8 +413,8 @@ BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask) if ( KEY_F1 == key ) { - llinfos << "Spawning HTML help window" << llendl; - gViewerHtmlHelp.show(); + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(vhelp->getTopicFromFocus()); return TRUE; } @@ -973,7 +974,7 @@ void LLPanelLogin::onSelectServer(LLUICtrl*, void*) loadLoginPage(); } -void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*) +void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe) { if (!sInstance) return; diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index ffcf6a9b70..5692b8d345 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -94,7 +94,7 @@ private: static void onClickForgotPassword(void*); static void onPassKey(LLLineEditor* caller, void* user_data); static void onSelectServer(LLUICtrl*, void*); - static void onServerComboLostFocus(LLFocusableElement*, void*); + static void onServerComboLostFocus(LLFocusableElement*); private: LLPointer<LLUIImage> mLogoImage; diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp new file mode 100644 index 0000000000..be40d6fb5f --- /dev/null +++ b/indra/newview/llpanelmediasettingsgeneral.cpp @@ -0,0 +1,409 @@ +/** + * @file llpanelmediasettingsgeneral.cpp + * @brief LLPanelMediaSettingsGeneral class implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelmediasettingsgeneral.h" +#include "llcombobox.h" +#include "llcheckboxctrl.h" +#include "llspinctrl.h" +#include "lluictrlfactory.h" +#include "llviewerwindow.h" +#include "llsdutil.h" +#include "llselectmgr.h" +#include "llbutton.h" +#include "lltexturectrl.h" +#include "llurl.h" +#include "llwindow.h" +#include "llmediaentry.h" +#include "llmediactrl.h" +#include "llpanelcontents.h" +#include "llpluginclassmedia.h" +#include "llfloatermediasettings.h" + +//////////////////////////////////////////////////////////////////////////////// +// +LLPanelMediaSettingsGeneral::LLPanelMediaSettingsGeneral() : + mControls( NULL ), + mAutoLoop( NULL ), + mFirstClick( NULL ), + mAutoZoom( NULL ), + mAutoPlay( NULL ), + mAutoScale( NULL ), + mWidthPixels( NULL ), + mHeightPixels( NULL ), + mHomeURL( NULL ), + mCurrentURL( NULL ), + mAltImageEnable( NULL ), + mParent( NULL ) +{ + // build dialog from XML + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_general.xml"); + mCommitCallbackRegistrar.add("Media.ResetCurrentUrl", boost::bind(&LLPanelMediaSettingsGeneral::onBtnResetCurrentUrl, this)); +// mCommitCallbackRegistrar.add("Media.CommitHomeURL", boost::bind(&LLPanelMediaSettingsGeneral::onCommitHomeURL, this)); + +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLPanelMediaSettingsGeneral::postBuild() +{ + // connect member vars with UI widgets + mAltImageEnable = getChild< LLCheckBoxCtrl >( LLMediaEntry::ALT_IMAGE_ENABLE_KEY ); + mAutoLoop = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_LOOP_KEY ); + mAutoPlay = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_PLAY_KEY ); + mAutoScale = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_SCALE_KEY ); + mAutoZoom = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_ZOOM_KEY ); + mControls = getChild< LLComboBox >( LLMediaEntry::CONTROLS_KEY ); + mCurrentURL = getChild< LLLineEditor >( LLMediaEntry::CURRENT_URL_KEY ); + mFirstClick = getChild< LLCheckBoxCtrl >( LLMediaEntry::FIRST_CLICK_INTERACT_KEY ); + mHeightPixels = getChild< LLSpinCtrl >( LLMediaEntry::HEIGHT_PIXELS_KEY ); + mHomeURL = getChild< LLLineEditor >( LLMediaEntry::HOME_URL_KEY ); + mWidthPixels = getChild< LLSpinCtrl >( LLMediaEntry::WIDTH_PIXELS_KEY ); + mPreviewMedia = getChild<LLMediaCtrl>("preview_media"); + + // watch commit action for HOME URL + childSetCommitCallback( LLMediaEntry::HOME_URL_KEY, onCommitHomeURL, this); + + // interrogates controls and updates widgets as required + updateMediaPreview(); + updateCurrentURL(); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +LLPanelMediaSettingsGeneral::~LLPanelMediaSettingsGeneral() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::draw() +{ + // housekeeping + LLPanel::draw(); + + // enable/disable pixel values image entry based on auto scale checkbox + if ( mAutoScale->getValue().asBoolean() == false ) + { + childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, true ); + childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, true ); + } + else + { + childSetEnabled( LLMediaEntry::WIDTH_PIXELS_KEY, false ); + childSetEnabled( LLMediaEntry::HEIGHT_PIXELS_KEY, false ); + }; + + // enable/disable UI based on type of media + bool reset_button_is_active = true; + if( mPreviewMedia ) + { + LLPluginClassMedia* media_plugin = mPreviewMedia->getMediaPlugin(); + if( media_plugin ) + { + // some controls are only appropriate for time or browser type plugins + // so we selectively enable/disable them - need to do it in draw + // because the information from plugins arrives assynchronously + bool show_time_controls = media_plugin->pluginSupportsMediaTime(); + if ( show_time_controls ) + { + childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, false ); + reset_button_is_active = false; + childSetEnabled( "current_url_label", false ); + childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, true ); + } + else + { + childSetEnabled( LLMediaEntry::CURRENT_URL_KEY, true ); + reset_button_is_active = true; + childSetEnabled( "current_url_label", true ); + childSetEnabled( LLMediaEntry::AUTO_LOOP_KEY, false ); + }; + }; + }; + + // current URL can change over time. + updateCurrentURL(); + + // enable/disable RESRET button depending on permissions + // since this is the same as a navigate action + U32 owner_mask_on; + U32 owner_mask_off; + U32 valid_owner_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_OWNER, + &owner_mask_on, &owner_mask_off ); + U32 group_mask_on; + U32 group_mask_off; + U32 valid_group_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_GROUP, + &group_mask_on, &group_mask_off ); + U32 everyone_mask_on; + U32 everyone_mask_off; + S32 valid_everyone_perms = LLSelectMgr::getInstance()->selectGetPerm( PERM_EVERYONE, + &everyone_mask_on, &everyone_mask_off ); + + bool user_can_press_reset = false; + + // if perms we got back are valid + if ( valid_owner_perms && + valid_group_perms && + valid_everyone_perms ) + { + // if user is allowed to press the RESET button + if ( ( owner_mask_on & PERM_MODIFY ) || + ( group_mask_on & PERM_MODIFY ) || + ( group_mask_on & PERM_MODIFY ) ) + { + user_can_press_reset = true; + } + else + // user is NOT allowed to press the RESET button + { + user_can_press_reset = false; + }; + }; + + // several places modify this widget so we must collect states in one place + if ( reset_button_is_active ) + { + // user has perms to press reset button and it is active + if ( user_can_press_reset ) + { + childSetEnabled( "current_url_reset_btn", true ); + } + // user does not has perms to press reset button and it is active + else + { + childSetEnabled( "current_url_reset_btn", false ); + }; + } + else + // reset button is inactive so we just slam it to off - other states don't matter + { + childSetEnabled( "current_url_reset_btn", false ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::clearValues( void* userdata ) +{ + LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; + self->mAltImageEnable ->clear(); + self->mAutoLoop->clear(); + self->mAutoPlay->clear(); + self->mAutoScale->clear(); + self->mAutoZoom ->clear(); + self->mControls->clear(); + self->mCurrentURL->clear(); + self->mFirstClick->clear(); + self->mHeightPixels->clear(); + self->mHomeURL->clear(); + self->mWidthPixels->clear(); + self->mPreviewMedia->unloadMediaSource(); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_settings ) +{ + LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; + + //llinfos << "---------------" << llendl; + //llinfos << ll_pretty_print_sd(media_settings) << llendl; + //llinfos << "---------------" << llendl; + + std::string base_key( "" ); + std::string tentative_key( "" ); + + struct + { + std::string key_name; + LLUICtrl* ctrl_ptr; + std::string ctrl_type; + + } data_set [] = + { + { LLMediaEntry::AUTO_LOOP_KEY, self->mAutoLoop, "LLCheckBoxCtrl" }, + { LLMediaEntry::AUTO_PLAY_KEY, self->mAutoPlay, "LLCheckBoxCtrl" }, + { LLMediaEntry::AUTO_SCALE_KEY, self->mAutoScale, "LLCheckBoxCtrl" }, + { LLMediaEntry::AUTO_ZOOM_KEY, self->mAutoZoom, "LLCheckBoxCtrl" }, + { LLMediaEntry::CONTROLS_KEY, self->mControls, "LLComboBox" }, + { LLMediaEntry::CURRENT_URL_KEY, self->mCurrentURL, "LLLineEditor" }, + { LLMediaEntry::HEIGHT_PIXELS_KEY, self->mHeightPixels, "LLSpinCtrl" }, + { LLMediaEntry::HOME_URL_KEY, self->mHomeURL, "LLLineEditor" }, + { LLMediaEntry::FIRST_CLICK_INTERACT_KEY, self->mFirstClick, "LLCheckBoxCtrl" }, + { LLMediaEntry::WIDTH_PIXELS_KEY, self->mWidthPixels, "LLSpinCtrl" }, + { LLMediaEntry::ALT_IMAGE_ENABLE_KEY, self->mAltImageEnable, "LLCheckBoxCtrl" }, + { "", NULL , "" } + }; + + for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) + { + base_key = std::string( data_set[ i ].key_name ); + tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); + // TODO: CP - I bet there is a better way to do this using Boost + if ( media_settings[ base_key ].isDefined() ) + { + if ( data_set[ i ].ctrl_type == "LLLineEditor" ) + { + static_cast< LLLineEditor* >( data_set[ i ].ctrl_ptr )-> + setText( media_settings[ base_key ].asString() ); + } + else + if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) + static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( media_settings[ base_key ].asBoolean() ); + else + if ( data_set[ i ].ctrl_type == "LLComboBox" ) + static_cast< LLComboBox* >( data_set[ i ].ctrl_ptr )-> + setCurrentByIndex( media_settings[ base_key ].asInteger() ); + else + if ( data_set[ i ].ctrl_type == "LLSpinCtrl" ) + static_cast< LLSpinCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( media_settings[ base_key ].asInteger() ); + + data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); + }; + }; + + // interrogates controls and updates widgets as required + self->updateMediaPreview(); + self->updateCurrentURL(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Helper to set media control to media URL as required +void LLPanelMediaSettingsGeneral::updateMediaPreview() +{ + if ( mHomeURL->getValue().asString().length() > 0 ) + { + mPreviewMedia->navigateTo( mHomeURL->getValue().asString() ); + } + else + // new home URL will be empty if media is deleted but + // we still need to clean out the preview. + { + mPreviewMedia->unloadMediaSource(); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// Helper to set current URL +void LLPanelMediaSettingsGeneral::updateCurrentURL() +{ + if( mPreviewMedia ) + { + LLPluginClassMedia* media_plugin = mPreviewMedia->getMediaPlugin(); + if( media_plugin ) + { + // get current URL from plugin and display + std::string current_location = media_plugin->getLocation(); + if ( current_location.length() ) + { + childSetText( "current_url", current_location ); + } + else + // current location may be empty so we need to clear it + { + const std::string empty_string( "" ); + childSetText( "current_url", empty_string ); + }; + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// + +void LLPanelMediaSettingsGeneral::onClose() +{ + if(mPreviewMedia) + { + mPreviewMedia->unloadMediaSource(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::onCommitHomeURL( LLUICtrl* ctrl, void *userdata ) +{ + LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata; + self->updateMediaPreview(); +} + + +//////////////////////////////////////////////////////////////////////////////// +void LLPanelMediaSettingsGeneral::onBtnResetCurrentUrl() +{ + // TODO: reset home URL but need to consider permissions too + //LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsGeneral::apply( void* userdata ) +{ + LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; + + // build LLSD Fragment + LLSD media_data_general; + self->getValues(media_data_general); + + // this merges contents of LLSD passed in with what's there so this is ok + LLSelectMgr::getInstance()->selectionSetMediaData( media_data_general ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsGeneral::getValues( LLSD &fill_me_in ) +{ + fill_me_in[LLMediaEntry::ALT_IMAGE_ENABLE_KEY] = mAltImageEnable->getValue(); + fill_me_in[LLMediaEntry::AUTO_LOOP_KEY] = mAutoLoop->getValue(); + fill_me_in[LLMediaEntry::AUTO_PLAY_KEY] = mAutoPlay->getValue(); + fill_me_in[LLMediaEntry::AUTO_SCALE_KEY] = mAutoScale->getValue(); + fill_me_in[LLMediaEntry::AUTO_ZOOM_KEY] = mAutoZoom->getValue(); + fill_me_in[LLMediaEntry::CONTROLS_KEY] = mControls->getCurrentIndex(); + // XXX Don't send current URL! + //fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue(); + fill_me_in[LLMediaEntry::HEIGHT_PIXELS_KEY] = mHeightPixels->getValue(); + fill_me_in[LLMediaEntry::HOME_URL_KEY] = mHomeURL->getValue(); + fill_me_in[LLMediaEntry::FIRST_CLICK_INTERACT_KEY] = mFirstClick->getValue(); + fill_me_in[LLMediaEntry::WIDTH_PIXELS_KEY] = mWidthPixels->getValue(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsGeneral::setParent( LLFloaterMediaSettings* parent ) +{ + mParent = parent; +}; diff --git a/indra/newview/llpanelmediasettingsgeneral.h b/indra/newview/llpanelmediasettingsgeneral.h new file mode 100644 index 0000000000..24678a3a07 --- /dev/null +++ b/indra/newview/llpanelmediasettingsgeneral.h @@ -0,0 +1,89 @@ +/** + * @file llpanelmediasettingsgeneral.h + * @brief LLPanelMediaSettingsGeneral class definition + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELMEDIAMEDIASETTINGSGENERAL_H +#define LL_LLPANELMEDIAMEDIASETTINGSGENERAL_H + +#include "llpanel.h" + +class LLButton; +class LLCheckBoxCtrl; +class LLComboBox; +class LLLineEditor; +class LLSpinCtrl; +class LLTextureCtrl; +class LLMediaCtrl; +class LLFloaterMediaSettings; + +class LLPanelMediaSettingsGeneral : public LLPanel +{ +public: + BOOL postBuild(); + virtual void draw(); + static void apply(void*); + void getValues(LLSD &fill_me_in); + + LLPanelMediaSettingsGeneral(); + ~LLPanelMediaSettingsGeneral(); + + void setParent( LLFloaterMediaSettings* parent ); + static void initValues( void* userdata, const LLSD& media_settings ); + static void clearValues( void* userdata ); + + void updateMediaPreview(); + void updateCurrentURL(); + + void onClose(); + +protected: + LLFloaterMediaSettings* mParent; + +private: + void onBtnResetCurrentUrl(); + static void onCommitHomeURL(LLUICtrl* ctrl, void *userdata ); + + LLComboBox* mControls; + LLCheckBoxCtrl* mAutoLoop; + LLCheckBoxCtrl* mFirstClick; + LLTextureCtrl* mMediaPreview; + LLCheckBoxCtrl* mAutoZoom; + LLCheckBoxCtrl* mAutoPlay; + LLCheckBoxCtrl* mAutoScale; + LLSpinCtrl* mWidthPixels; + LLSpinCtrl* mHeightPixels; + LLLineEditor* mHomeURL; + LLLineEditor* mCurrentURL; + LLCheckBoxCtrl* mAltImageEnable; + LLMediaCtrl* mPreviewMedia; +}; + +#endif // LL_LLPANELMEDIAMEDIASETTINGSGENERAL_H diff --git a/indra/newview/llpanelmediasettingspermissions.cpp b/indra/newview/llpanelmediasettingspermissions.cpp new file mode 100644 index 0000000000..d6a2677f4b --- /dev/null +++ b/indra/newview/llpanelmediasettingspermissions.cpp @@ -0,0 +1,223 @@ +/** + * @file llpanelmediasettingspermissions.cpp + * @brief LLPanelMediaSettingsPermissions class implementation + * + * note that "permissions" tab is really "Controls" tab - refs to 'perms' and + * 'permissions' not changed to 'controls' since we don't want to change + * shared files in server code and keeping everything the same seemed best. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelmediasettingspermissions.h" +#include "llpanelcontents.h" +#include "llcombobox.h" +#include "llcheckboxctrl.h" +#include "llspinctrl.h" +#include "llurlhistory.h" +#include "lluictrlfactory.h" +#include "llwindow.h" +#include "llviewerwindow.h" +#include "llsdutil.h" +#include "llselectmgr.h" +#include "llmediaentry.h" +#include "llnamebox.h" + +//////////////////////////////////////////////////////////////////////////////// +// +LLPanelMediaSettingsPermissions::LLPanelMediaSettingsPermissions() : + mPermsOwnerInteract( 0 ), + mPermsOwnerControl( 0 ), + mPermsGroupName( 0 ), + mPermsGroupInteract( 0 ), + mPermsGroupControl( 0 ), + mPermsWorldInteract( 0 ), + mPermsWorldControl( 0 ) +{ + // build dialog from XML + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_permissions.xml"); +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLPanelMediaSettingsPermissions::postBuild() +{ + // connect member vars with UI widgets + mPermsOwnerInteract = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_OWNER_INTERACT_KEY ); + mPermsOwnerControl = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_OWNER_CONTROL_KEY ); + mPermsGroupInteract = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_GROUP_INTERACT_KEY ); + mPermsGroupControl = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_GROUP_CONTROL_KEY ); + mPermsWorldInteract = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_ANYONE_INTERACT_KEY ); + mPermsWorldControl = getChild< LLCheckBoxCtrl >( LLPanelContents::PERMS_ANYONE_CONTROL_KEY ); + + mPermsGroupName = getChild< LLNameBox >( "perms_group_name" ); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +LLPanelMediaSettingsPermissions::~LLPanelMediaSettingsPermissions() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void LLPanelMediaSettingsPermissions::draw() +{ + // housekeeping + LLPanel::draw(); + + childSetText("perms_group_name",LLStringUtil::null); + LLUUID group_id; + BOOL groups_identical = LLSelectMgr::getInstance()->selectGetGroup(group_id); + if (groups_identical) + { + if(mPermsGroupName) + { + mPermsGroupName->setNameID(group_id, true); + mPermsGroupName->setEnabled(true); + }; + } + else + { + if(mPermsGroupName) + { + mPermsGroupName->setNameID(LLUUID::null, TRUE); + mPermsGroupName->refresh(LLUUID::null, LLStringUtil::null, LLStringUtil::null, true); + mPermsGroupName->setEnabled(false); + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsPermissions::clearValues( void* userdata ) +{ + LLPanelMediaSettingsPermissions *self =(LLPanelMediaSettingsPermissions *)userdata; + self->mPermsOwnerInteract->clear(); + self->mPermsOwnerControl->clear(); + self->mPermsGroupInteract ->clear(); + self->mPermsGroupControl->clear(); + self->mPermsWorldInteract ->clear(); + self->mPermsWorldControl ->clear(); +// mPermsGroupName ->setValue(0); + +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsPermissions::initValues( void* userdata, const LLSD& media_settings ) +{ + LLPanelMediaSettingsPermissions *self =(LLPanelMediaSettingsPermissions *)userdata; + + std::string base_key( "" ); + std::string tentative_key( "" ); + + struct + { + std::string key_name; + LLUICtrl* ctrl_ptr; + std::string ctrl_type; + + } data_set [] = + { + { LLPanelContents::PERMS_OWNER_INTERACT_KEY, self->mPermsOwnerInteract, "LLCheckBoxCtrl" }, + { LLPanelContents::PERMS_OWNER_CONTROL_KEY, self->mPermsOwnerControl, "LLCheckBoxCtrl" }, + { LLPanelContents::PERMS_GROUP_INTERACT_KEY, self->mPermsGroupInteract, "LLCheckBoxCtrl" }, + { LLPanelContents::PERMS_GROUP_CONTROL_KEY, self->mPermsGroupControl, "LLCheckBoxCtrl" }, + { LLPanelContents::PERMS_ANYONE_INTERACT_KEY, self->mPermsWorldInteract, "LLCheckBoxCtrl" }, + { LLPanelContents::PERMS_ANYONE_CONTROL_KEY, self->mPermsWorldControl, "LLCheckBoxCtrl" }, + { "", NULL , "" } + }; + + for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) + { + base_key = std::string( data_set[ i ].key_name ); + tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); + + // TODO: CP - I bet there is a better way to do this using Boost + if ( media_settings[ base_key ].isDefined() ) + { + if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) + { + // the sense of the checkboxes changed and it made sense + // to just reverse their sense back again here and avoid + // changing server code. + static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( ! media_settings[ base_key ].asBoolean() ); + } + else + if ( data_set[ i ].ctrl_type == "LLComboBox" ) + static_cast< LLComboBox* >( data_set[ i ].ctrl_ptr )-> + setCurrentByIndex( media_settings[ base_key ].asInteger() ); + + data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsPermissions::apply( void* userdata ) +{ + LLPanelMediaSettingsPermissions *self =(LLPanelMediaSettingsPermissions *)userdata; + + // build LLSD Fragment + LLSD media_data_permissions; + self->getValues(media_data_permissions); + + // this merges contents of LLSD passed in with what's there so this is ok + LLSelectMgr::getInstance()->selectionSetMediaData( media_data_permissions ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsPermissions::getValues( LLSD &fill_me_in ) +{ + // *NOTE: For some reason, gcc does not like these symbol references in the + // expressions below (inside the static_casts). I have NO idea why :(. + // For some reason, assigning them to const temp vars here fixes the link + // error. Bizarre. + const U8 none = LLMediaEntry::PERM_NONE; + const U8 owner = LLMediaEntry::PERM_OWNER; + const U8 group = LLMediaEntry::PERM_GROUP; + const U8 anyone = LLMediaEntry::PERM_ANYONE; + const LLSD::Integer control = static_cast<LLSD::Integer>( + (mPermsOwnerControl->getValue() ? none : owner ) | + (mPermsGroupControl->getValue() ? none : group ) | + (mPermsWorldControl->getValue() ? none : anyone )); + const LLSD::Integer interact = static_cast<LLSD::Integer>( + (mPermsOwnerInteract->getValue() ? none : owner ) | + (mPermsGroupInteract->getValue() ? none : group ) | + (mPermsWorldInteract->getValue() ? none : anyone )); + fill_me_in[LLMediaEntry::PERMS_CONTROL_KEY] = control; + fill_me_in[LLMediaEntry::PERMS_INTERACT_KEY] = interact; +} diff --git a/indra/newview/llpanelmediasettingspermissions.h b/indra/newview/llpanelmediasettingspermissions.h new file mode 100644 index 0000000000..ce293e07b9 --- /dev/null +++ b/indra/newview/llpanelmediasettingspermissions.h @@ -0,0 +1,71 @@ +/** + * @file llpanelmediasettingspermissions.h + * @brief LLPanelMediaSettingsPermissions class definition + * + * note that "permissions" tab is really "Controls" tab - refs to 'perms' and + * 'permissions' not changed to 'controls' since we don't want to change + * shared files in server code and keeping everything the same seemed best. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELMEDIAMEDIASETTINGSPERMISSIONS_H +#define LL_LLPANELMEDIAMEDIASETTINGSPERMISSIONS_H + +#include "llpanel.h" +#include "lluuid.h" + +class LLComboBox; +class LLCheckBoxCtrl; +class LLNameBox; + +class LLPanelMediaSettingsPermissions : public LLPanel +{ + public: + BOOL postBuild(); + virtual void draw(); + static void apply(void*); + void getValues(LLSD &fill_me_in); + + LLPanelMediaSettingsPermissions(); + ~LLPanelMediaSettingsPermissions(); + + static void initValues( void* userdata, const LLSD& media_settings ); + static void clearValues( void* userdata ); + + private: + LLCheckBoxCtrl* mPermsOwnerInteract; + LLCheckBoxCtrl* mPermsOwnerControl; + LLNameBox* mPermsGroupName; + LLCheckBoxCtrl* mPermsGroupInteract; + LLCheckBoxCtrl* mPermsGroupControl; + LLCheckBoxCtrl* mPermsWorldInteract; + LLCheckBoxCtrl* mPermsWorldControl; +}; + +#endif // LL_LLPANELMEDIAMEDIASETTINGSPERMISSIONS_H diff --git a/indra/newview/llpanelmediasettingssecurity.cpp b/indra/newview/llpanelmediasettingssecurity.cpp new file mode 100644 index 0000000000..a4eee82aa9 --- /dev/null +++ b/indra/newview/llpanelmediasettingssecurity.cpp @@ -0,0 +1,233 @@ +/** + * @file llpanelmediasettingssecurity.cpp + * @brief LLPanelMediaSettingsSecurity class implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfloaterreg.h" +#include "llpanelmediasettingssecurity.h" +#include "llpanelcontents.h" +#include "llcheckboxctrl.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "lluictrlfactory.h" +#include "llwindow.h" +#include "llviewerwindow.h" +#include "llsdutil.h" +#include "llselectmgr.h" +#include "llmediaentry.h" +#include "llfloaterwhitelistentry.h" + +//////////////////////////////////////////////////////////////////////////////// +// +LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity() +{ + // build dialog from XML + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_security.xml"); + mCommitCallbackRegistrar.add("Media.whitelistAdd", boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this)); + mCommitCallbackRegistrar.add("Media.whitelistDelete", boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this)); +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLPanelMediaSettingsSecurity::postBuild() +{ + mEnableWhiteList = getChild< LLCheckBoxCtrl >( LLMediaEntry::WHITELIST_ENABLE_KEY ); + mWhiteListList = getChild< LLScrollListCtrl >( LLMediaEntry::WHITELIST_KEY ); + + childSetAction("whitelist_add", onBtnAdd, this); + childSetAction("whitelist_del", onBtnDel, this); + + setDefaultBtn("whitelist_add"); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +LLPanelMediaSettingsSecurity::~LLPanelMediaSettingsSecurity() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::draw() +{ + // housekeeping + LLPanel::draw(); + + // if list is empty, disable DEL button and checkbox to enable use of list + if ( mWhiteListList->isEmpty() ) + { + childSetEnabled( "whitelist_del", false ); + childSetEnabled( LLMediaEntry::WHITELIST_KEY, false ); + childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, false ); + } + else + { + childSetEnabled( "whitelist_del", true ); + childSetEnabled( LLMediaEntry::WHITELIST_KEY, true ); + childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, true ); + }; + + // if nothing is selected, disable DEL button + if ( mWhiteListList->getSelectedValue().asString().empty() ) + { + childSetEnabled( "whitelist_del", false ); + } + else + { + childSetEnabled( "whitelist_del", true ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings ) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + + std::string base_key( "" ); + std::string tentative_key( "" ); + + struct + { + std::string key_name; + LLUICtrl* ctrl_ptr; + std::string ctrl_type; + + } data_set [] = + { + { LLMediaEntry::WHITELIST_ENABLE_KEY, self->mEnableWhiteList, "LLCheckBoxCtrl" }, + { LLMediaEntry::WHITELIST_KEY, self->mWhiteListList, "LLScrollListCtrl" }, + { "", NULL , "" } + }; + + for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) + { + base_key = std::string( data_set[ i ].key_name ); + tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); + + // TODO: CP - I bet there is a better way to do this using Boost + if ( media_settings[ base_key ].isDefined() ) + { + if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) + { + static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( media_settings[ base_key ].asBoolean() ); + } + else + if ( data_set[ i ].ctrl_type == "LLScrollListCtrl" ) + { + // get control + LLScrollListCtrl* list = static_cast< LLScrollListCtrl* >( data_set[ i ].ctrl_ptr ); + list->deleteAllItems(); + + // points to list of white list URLs + LLSD url_list = media_settings[ base_key ]; + + // iterate over them and add to scroll list + LLSD::array_iterator iter = url_list.beginArray(); + while( iter != url_list.endArray() ) + { + // TODO: is iter guaranteed to be valid here? + std::string url = *iter; + list->addSimpleElement( url ); + ++iter; + }; + }; + + data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::clearValues( void* userdata ) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + self->mEnableWhiteList->clear(); + self->mWhiteListList->deleteAllItems(); +} +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::apply( void* userdata ) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + + // build LLSD Fragment + LLSD media_data_security; + self->getValues(media_data_security); + // this merges contents of LLSD passed in with what's there so this is ok + LLSelectMgr::getInstance()->selectionSetMediaData( media_data_security ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in ) +{ + fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = mEnableWhiteList->getValue(); + + // iterate over white list and extract items + std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData(); + std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin(); + fill_me_in[LLMediaEntry::WHITELIST_KEY].clear(); + while( iter != white_list_items.end() ) + { + std::string white_list_url = (*iter)->getValue().asString(); + fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( white_list_url ); + ++iter; + }; +} + + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::addWhiteListItem(const std::string& url) +{ + mWhiteListList->addSimpleElement( url ); +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::onBtnAdd( void* userdata ) +{ + LLFloaterReg::showInstance("whitelist_entry"); +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::onBtnDel( void* userdata ) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + + self->mWhiteListList->deleteSelectedItems(); +} diff --git a/indra/newview/llpanelmediasettingssecurity.h b/indra/newview/llpanelmediasettingssecurity.h new file mode 100644 index 0000000000..d77509897d --- /dev/null +++ b/indra/newview/llpanelmediasettingssecurity.h @@ -0,0 +1,64 @@ +/** + * @file llpanelmediasettingssecurity.h + * @brief LLPanelMediaSettingsSecurity class definition + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELMEDIAMEDIASETTINGSSECURITY_H +#define LL_LLPANELMEDIAMEDIASETTINGSSECURITY_H + +#include "llpanel.h" + +class LLCheckBoxCtrl; +class LLScrollListCtrl; + +class LLPanelMediaSettingsSecurity : public LLPanel +{ + public: + BOOL postBuild(); + virtual void draw(); + static void apply(void*); + void getValues(LLSD &fill_me_in); + + LLPanelMediaSettingsSecurity(); + ~LLPanelMediaSettingsSecurity(); + + static void initValues( void* userdata, const LLSD& media_settings ); + static void clearValues( void* userdata ); + void addWhiteListItem(const std::string& url); + + private: + LLCheckBoxCtrl* mEnableWhiteList; + LLScrollListCtrl* mWhiteListList; + + static void onBtnAdd(void*); + static void onBtnDel(void*); +}; + +#endif // LL_LLPANELMEDIAMEDIASETTINGSSECURITY_H diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 6a41b6feb9..b2a0a01005 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -60,11 +60,8 @@ #include "llvoiceclient.h" #include "llworld.h" -using namespace LLOldEvents; - #define FRIEND_LIST_UPDATE_TIMEOUT 0.5 #define NEARBY_LIST_UPDATE_INTERVAL 1 -#define RECENT_LIST_UPDATE_DELAY 1 static const std::string NEARBY_TAB_NAME = "nearby_panel"; static const std::string FRIENDS_TAB_NAME = "friends_panel"; @@ -102,7 +99,7 @@ static LLRegisterPanelClassWrapper<LLPanelPeople> t_people("panel_people"); class LLPanelPeople::Updater { public: - typedef boost::function<bool(U32)> callback_t; + typedef boost::function<void()> callback_t; Updater(callback_t cb) : mCallback(cb) { @@ -113,16 +110,6 @@ public: } /** - * Force the list updates. - * - * This may start repeated updates until all names are complete. - */ - virtual void forceUpdate() - { - updateList(); - } - - /** * Activate/deactivate updater. * * This may start/stop regular updates. @@ -130,9 +117,9 @@ public: virtual void setActive(bool) {} protected: - bool updateList(U32 mask = 0) + void updateList() { - return mCallback(mask); + mCallback(); } callback_t mCallback; @@ -147,6 +134,11 @@ public: { mEventTimer.stop(); } + + virtual BOOL tick() // from LLEventTimer + { + return FALSE; + } }; /** @@ -178,13 +170,6 @@ public: LLAvatarTracker::instance().removeObserver(this); } - /*virtual*/ void forceUpdate() - { - // Perform updates until all names are loaded. - if (!updateList(LLFriendObserver::ADD)) - changed(LLFriendObserver::ADD); - } - /*virtual*/ void changed(U32 mask) { // events can arrive quickly in bulk - we need not process EVERY one of them - @@ -198,12 +183,12 @@ public: /*virtual*/ BOOL tick() { - if (updateList(mMask)) - { - // Got all names, stop updates. - mEventTimer.stop(); - mMask = 0; - } + if (mMask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) + updateList(); + + // Stop updates. + mEventTimer.stop(); + mMask = 0; return FALSE; } @@ -329,68 +314,9 @@ class LLRecentListUpdater : public LLAvatarListUpdater, public boost::signals2:: public: LLRecentListUpdater(callback_t cb) - : LLAvatarListUpdater(cb, RECENT_LIST_UPDATE_DELAY) - { - LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::onRecentPeopleChanged, this)); - } - -private: - /*virtual*/ void forceUpdate() - { - onRecentPeopleChanged(); - } - - /*virtual*/ BOOL tick() - { - // Update the list until we get all the names. - if (updateList()) - { - // Got all names, stop updates. - mEventTimer.stop(); - } - - return FALSE; - } - - void onRecentPeopleChanged() - { - if (!updateList()) - { - // Some names are incomplete, schedule another update. - mEventTimer.start(); - } - } -}; - -/** - * Updates the group list on events from LLAgent. - */ -class LLGroupListUpdater : public LLPanelPeople::Updater, public LLSimpleListener -{ - LOG_CLASS(LLGroupListUpdater); - -public: - LLGroupListUpdater(callback_t cb) - : LLPanelPeople::Updater(cb) - { - gAgent.addListener(this, "new group"); - } - - ~LLGroupListUpdater() + : LLAvatarListUpdater(cb, 0) { - gAgent.removeListener(this); - } - - /*virtual*/ bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) - { - // Why is "new group" sufficient? - if (event->desc() == "new group") - { - updateList(); - return true; - } - - return false; + LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::updateList, this)); } }; @@ -404,12 +330,12 @@ LLPanelPeople::LLPanelPeople() mOnlineFriendList(NULL), mAllFriendList(NULL), mNearbyList(NULL), - mRecentList(NULL) + mRecentList(NULL), + mGroupList(NULL) { - mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::onFriendListUpdate,this, _1)); + mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this)); mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this)); mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this)); - mGroupListUpdater = new LLGroupListUpdater (boost::bind(&LLPanelPeople::updateGroupList, this)); } LLPanelPeople::~LLPanelPeople() @@ -417,7 +343,6 @@ LLPanelPeople::~LLPanelPeople() delete mNearbyListUpdater; delete mFriendListUpdater; delete mRecentListUpdater; - delete mGroupListUpdater; LLView::deleteViewByHandle(mGroupPlusMenuHandle); LLView::deleteViewByHandle(mNearbyViewSortMenuHandle); @@ -512,7 +437,7 @@ BOOL LLPanelPeople::postBuild() buttonSetAction("share_btn", boost::bind(&LLPanelPeople::onShareButtonClicked, this)); getChild<LLPanel>(NEARBY_TAB_NAME)->childSetAction("nearby_view_sort_btn",boost::bind(&LLPanelPeople::onNearbyViewSortButtonClicked, this)); - getChild<LLPanel>(RECENT_TAB_NAME)->childSetAction("recent_viewsort_btn",boost::bind(&LLPanelPeople::onRecentViewSortButtonClicked, this)); + getChild<LLPanel>(RECENT_TAB_NAME)->childSetAction("recent_viewsort_btn",boost::bind(&LLPanelPeople::onRecentViewSortButtonClicked, this)); getChild<LLPanel>(FRIENDS_TAB_NAME)->childSetAction("friends_viewsort_btn",boost::bind(&LLPanelPeople::onFriendsViewSortButtonClicked, this)); getChild<LLPanel>(GROUP_TAB_NAME)->childSetAction("groups_viewsort_btn",boost::bind(&LLPanelPeople::onGroupsViewSortButtonClicked, this)); @@ -547,137 +472,71 @@ BOOL LLPanelPeople::postBuild() if(recent_view_sort) mRecentViewSortMenuHandle = recent_view_sort->getHandle(); - - - // Perform initial update. - mFriendListUpdater->forceUpdate(); - mNearbyListUpdater->forceUpdate(); - mGroupListUpdater->forceUpdate(); - mRecentListUpdater->forceUpdate(); - // call this method in case some list is empty and buttons can be in inconsistent state updateButtons(); return TRUE; } -void LLPanelPeople::applyFilterToTab(const std::string& tab_name) -{ - if (tab_name == FRIENDS_TAB_NAME) // this tab has two lists - filterFriendList(); - else if (tab_name == NEARBY_TAB_NAME) - filterNearbyList(); - else if (tab_name == RECENT_TAB_NAME) - filterRecentList(); - else if (tab_name == GROUP_TAB_NAME) - updateGroupList(); -} - -bool LLPanelPeople::updateFriendList(U32 changed_mask) +void LLPanelPeople::updateFriendList() { - // Refresh names. - if (changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) - { - // get all buddies we know about - const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); - LLAvatarTracker::buddy_map_t all_buddies; - av_tracker.copyBuddyList(all_buddies); - - // *TODO: it's suboptimal to rebuild the whole lists on online status change. + if (!mOnlineFriendList || !mAllFriendList) + return; - // save them to the online and all friends vectors - mOnlineFriendVec.clear(); - mAllFriendVec.clear(); + // get all buddies we know about + const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); + LLAvatarTracker::buddy_map_t all_buddies; + av_tracker.copyBuddyList(all_buddies); - LLFriendCardsManager::folderid_buddies_map_t listMap; + // save them to the online and all friends vectors + LLAvatarList::uuid_vector_t& online_friendsp = mOnlineFriendList->getIDs(); + LLAvatarList::uuid_vector_t& all_friendsp = mAllFriendList->getIDs(); - // *NOTE: For now collectFriendsLists returns data only for Friends/All folder. EXT-694. - LLFriendCardsManager::instance().collectFriendsLists(listMap); - if (listMap.size() > 0) - { - lldebugs << "Friends Cards were found, count: " << listMap.begin()->second.size() << llendl; - mAllFriendVec = listMap.begin()->second; - } - else - { - lldebugs << "Friends Cards were not found" << llendl; - } + all_friendsp.clear(); + online_friendsp.clear(); - LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); - for (; buddy_it != all_buddies.end(); ++buddy_it) - { - LLUUID buddy_id = buddy_it->first; - if (av_tracker.isBuddyOnline(buddy_id)) - mOnlineFriendVec.push_back(buddy_id); - } + LLFriendCardsManager::folderid_buddies_map_t listMap; - return filterFriendList(); + // *NOTE: For now collectFriendsLists returns data only for Friends/All folder. EXT-694. + LLFriendCardsManager::instance().collectFriendsLists(listMap); + if (listMap.size() > 0) + { + lldebugs << "Friends Cards were found, count: " << listMap.begin()->second.size() << llendl; + all_friendsp = listMap.begin()->second; + } + else + { + lldebugs << "Friends Cards were not found" << llendl; } - return true; -} - -bool LLPanelPeople::updateNearbyList() -{ - LLWorld::getInstance()->getAvatars(&mNearbyVec, NULL, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); - filterNearbyList(); - - return true; -} - -bool LLPanelPeople::updateRecentList() -{ - LLRecentPeople::instance().get(mRecentVec); - filterRecentList(); - - return true; -} - -bool LLPanelPeople::updateGroupList() -{ - if (!mGroupList) - return true; // there's no point in further updates + LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); + for (; buddy_it != all_buddies.end(); ++buddy_it) + { + LLUUID buddy_id = buddy_it->first; + if (av_tracker.isBuddyOnline(buddy_id)) + online_friendsp.push_back(buddy_id); + } - bool have_names = mGroupList->update(mFilterSubString); - updateButtons(); - return have_names; + mOnlineFriendList->setDirty(); + mAllFriendList->setDirty(); } -bool LLPanelPeople::filterFriendList() +void LLPanelPeople::updateNearbyList() { - if (!mOnlineFriendList || !mAllFriendList) - return true; // there's no point in further updates - - // We must always update Friends list to clear the latest removed friend. - bool have_names = - mOnlineFriendList->update(mOnlineFriendVec, mFilterSubString) & - mAllFriendList->update(mAllFriendVec, mFilterSubString); - - - updateButtons(); - return have_names; -} + if (!mNearbyList) + return; -bool LLPanelPeople::filterNearbyList() -{ - bool have_names = mNearbyList->update(mNearbyVec, mFilterSubString); - updateButtons(); - return have_names; + LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), NULL, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); + mNearbyList->setDirty(); } -bool LLPanelPeople::filterRecentList() +void LLPanelPeople::updateRecentList() { if (!mRecentList) - return true; - - if (mRecentVec.size() > 0) - { - bool updated = mRecentList->update(mRecentVec, mFilterSubString); - updateButtons(); - return updated; - } + return; - return true; + LLRecentPeople::instance().get(mRecentList->getIDs()); + mRecentList->setDirty(); } void LLPanelPeople::buttonSetVisible(std::string btn_name, BOOL visible) @@ -846,16 +705,19 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string) LLStringUtil::toUpper(mFilterSubString); LLStringUtil::trimHead(mFilterSubString); - // Apply new filter to current tab. - applyFilterToTab(getActiveTabName()); + // Apply new filter. + mNearbyList->setNameFilter(mFilterSubString); + mOnlineFriendList->setNameFilter(mFilterSubString); + mAllFriendList->setNameFilter(mFilterSubString); + mRecentList->setNameFilter(mFilterSubString); + mGroupList->setNameFilter(mFilterSubString); } void LLPanelPeople::onTabSelected(const LLSD& param) { std::string tab_name = getChild<LLPanel>(param.asString())->getName(); mNearbyListUpdater->setActive(tab_name == NEARBY_TAB_NAME); - applyFilterToTab(tab_name); - // No need to call updateButtons() because applyFilterToTab() does that. + updateButtons(); if (GROUP_TAB_NAME == tab_name) mFilterEditor->setLabel(getString("groups_filter_label")); @@ -960,17 +822,6 @@ void LLPanelPeople::onAvatarPicked( LLAvatarActions::requestFriendshipDialog(ids[0], names[0]); } -bool LLPanelPeople::onFriendListUpdate(U32 changed_mask) -{ - bool have_names = updateFriendList(changed_mask); - - // Update online status in the Recent tab. - // *TODO: isn't it too much to update the whole list? -// updateRecentList(); // mantipov: seems online status should be supported by LLAvatarListItem itself. - - return have_names; -} - void LLPanelPeople::onGroupPlusButtonClicked() { LLMenuGL* plus_menu = (LLMenuGL*)mGroupPlusMenuHandle.get(); diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index 8cd3cc7feb..de27814388 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -58,15 +58,10 @@ public: private: // methods indirectly called by the updaters - bool updateFriendList(U32 changed_mask); - bool updateNearbyList(); - bool updateRecentList(); - bool updateGroupList(); - - bool filterFriendList(); - bool filterNearbyList(); - bool filterRecentList(); - void applyFilterToTab(const std::string& tab_name); + void updateFriendList(); + void updateNearbyList(); + void updateRecentList(); + void updateButtons(); const std::string& getActiveTabName() const; LLUUID getCurrentItemID() const; @@ -110,7 +105,6 @@ private: void onRecentViewSortMenuItemClicked(const LLSD& userdata); // misc callbacks - bool onFriendListUpdate(U32 changed_mask); static void onAvatarPicked( const std::vector<std::string>& names, const std::vector<LLUUID>& ids, @@ -135,21 +129,8 @@ private: Updater* mFriendListUpdater; Updater* mNearbyListUpdater; Updater* mRecentListUpdater; - Updater* mGroupListUpdater; std::string mFilterSubString; - - // The vectors below contain up-to date avatar lists - // for the corresponding tabs. - // When the user enters a filter, it gets applied - // to all the vectors and the result is shown in the tabs. - // We don't need to have such a vector for the groups tab - // since re-fetching the groups list is always fast. - typedef std::vector<LLUUID> uuid_vector_t; - uuid_vector_t mNearbyVec; - uuid_vector_t mOnlineFriendVec; - uuid_vector_t mAllFriendVec; - uuid_vector_t mRecentVec; }; #endif //LL_LLPANELPEOPLE_H diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index 42185d28e5..5df3d4f1d6 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -39,8 +39,10 @@ #include "message.h" #include "llagent.h" #include "llbutton.h" +#include "lllineeditor.h" #include "llparcel.h" #include "llviewerparcelmgr.h" +#include "lltexteditor.h" #include "lltexturectrl.h" #include "lluiconstants.h" #include "llworldmap.h" @@ -73,7 +75,8 @@ LLPanelPick::LLPanelPick(BOOL edit_mode/* = FALSE */) mPickId(LLUUID::null), mCreatorId(LLUUID::null), mDataReceived(FALSE), - mIsPickNew(false) + mIsPickNew(false), + mLocationChanged(false) { if (edit_mode) { @@ -123,6 +126,16 @@ BOOL LLPanelPick::postBuild() if (mEditMode) { + enableSaveButton(FALSE); + + mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelPick::onPickChanged, this, _1)); + + LLLineEditor* line_edit = getChild<LLLineEditor>("pick_name"); + line_edit->setKeystrokeCallback(boost::bind(&LLPanelPick::onPickChanged, this, _1), NULL); + + LLTextEditor* text_edit = getChild<LLTextEditor>("pick_desc"); + text_edit->setKeystrokeCallback(boost::bind(&LLPanelPick::onPickChanged, this, _1)); + childSetAction("cancel_btn", boost::bind(&LLPanelPick::onClickCancel, this)); childSetAction("set_to_curr_location_btn", boost::bind(&LLPanelPick::onClickSet, this)); childSetAction(XML_BTN_SAVE, boost::bind(&LLPanelPick::onClickSave, this)); @@ -287,6 +300,26 @@ void LLPanelPick::setEditMode( BOOL edit_mode ) updateButtons(); } +void LLPanelPick::onPickChanged(LLUICtrl* ctrl) +{ + if(mLocationChanged) + { + // Pick was enabled in onClickSet + return; + } + + if( mSnapshotCtrl->isDirty() + || getChild<LLLineEditor>("pick_name")->isDirty() + || getChild<LLTextEditor>("pick_desc")->isDirty() ) + { + enableSaveButton(TRUE); + } + else + { + enableSaveButton(FALSE); + } +} + ////////////////////////////////////////////////////////////////////////// // PROTECTED AREA ////////////////////////////////////////////////////////////////////////// @@ -466,6 +499,9 @@ void LLPanelPick::onClickSet() mSimName = parcel->getName(); } setPickLocation(createLocationText(std::string(""), SET_LOCATION_NOTICE, mSimName, mPosGlobal)); + + mLocationChanged = true; + enableSaveButton(TRUE); } // static @@ -552,3 +588,12 @@ void LLPanelPick::processParcelInfo(const LLParcelData& parcel_data) //*NOTE we don't removeObserver(...) ourselves cause LLRemoveParcelProcessor does it for us } + +void LLPanelPick::enableSaveButton(bool enable) +{ + if(!mEditMode) + { + return; + } + childSetEnabled(XML_BTN_SAVE, enable); +} diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h index 7ce58b59af..82cba72bc4 100644 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -74,6 +74,8 @@ public: // switches the panel to either View or Edit mode void setEditMode(BOOL edit_mode); + void onPickChanged(LLUICtrl* ctrl); + // because this panel works in two modes (edit/view) we are // free from managing two panel for editing and viewing picks and so // are free from controlling switching between them in the parent panel (e.g. Me Profile) @@ -128,6 +130,8 @@ protected: void onClickSave(); void onClickCancel(); + void enableSaveButton(bool enable); + protected: BOOL mEditMode; LLTextureCtrl* mSnapshotCtrl; @@ -146,6 +150,7 @@ protected: std::string mLocation; commit_callback_t mBackCb; + bool mLocationChanged; }; #endif // LL_LLPANELPICK_H diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp index 93317e613f..e74afba25a 100644 --- a/indra/newview/llpanelpicks.cpp +++ b/indra/newview/llpanelpicks.cpp @@ -126,8 +126,7 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) mPicksList->addItem(picture, pick_value); picture->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickItem, this, _1)); - picture->setRightMouseDownCallback(boost::bind(&LLPanelPicks::onRightMouseDownItem, this, _1, _2, _3, _4)); - picture->setRightMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); + picture->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4)); picture->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); } @@ -260,8 +259,10 @@ void LLPanelPicks::onClickMap() } -void LLPanelPicks::onRightMouseDownItem(LLUICtrl* item, S32 x, S32 y, MASK mask) +void LLPanelPicks::onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask) { + updateButtons(); + if (mPopupMenu) { mPopupMenu->buildDrawLabels(); diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h index 27a21305b3..7ebdc3089c 100644 --- a/indra/newview/llpanelpicks.h +++ b/indra/newview/llpanelpicks.h @@ -100,7 +100,7 @@ private: void updateButtons(); virtual void onDoubleClickItem(LLUICtrl* item); - virtual void onRightMouseDownItem(LLUICtrl* item, S32 x, S32 y, MASK mask); + virtual void onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask); LLPanelProfile* getProfilePanel(); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 4e070df7eb..80ecc95afb 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -337,7 +337,7 @@ void LLPanelPlaces::onFilterEdit(const std::string& search_string) LLStringUtil::trimHead(mFilterSubString); if (mActivePanel) - mActivePanel->onSearchEdit(mFilterSubString); + mActivePanel->onSearchEdit(mFilterSubString); } } @@ -386,7 +386,7 @@ void LLPanelPlaces::onTeleportButtonClicked() else { if (mActivePanel) - mActivePanel->onTeleport(); + mActivePanel->onTeleport(); } } @@ -432,7 +432,7 @@ void LLPanelPlaces::onShowOnMapButtonClicked() else { if (mActivePanel) - mActivePanel->onShowOnMap(); + mActivePanel->onShowOnMap(); } } @@ -510,7 +510,7 @@ void LLPanelPlaces::onOverflowMenuItemClicked(const LLSD& param) addChild(mPickPanel); mPickPanel->setExitCallback(boost::bind(&LLPanelPlaces::togglePickPanel, this, FALSE)); - } + } togglePickPanel(TRUE); @@ -733,7 +733,7 @@ void LLPanelPlaces::updateVerbs() else { if (mActivePanel) - mActivePanel->updateVerbs(); + mActivePanel->updateVerbs(); } } diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index f6672d9c8b..9754094aaa 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -42,11 +42,15 @@ #include "llaccordionctrltab.h" #include "llflatlistview.h" #include "lltextbox.h" +#include "llviewermenu.h" +#include "llviewerinventory.h" +#include "lllandmarkactions.h" +#include "llclipboard.h" class LLTeleportHistoryFlatItem : public LLPanel { public: - LLTeleportHistoryFlatItem(S32 index, const std::string ®ion_name); + LLTeleportHistoryFlatItem(S32 index, LLTeleportHistoryPanel::ContextMenu *context_menu, const std::string ®ion_name); virtual ~LLTeleportHistoryFlatItem() {}; virtual BOOL postBuild(); @@ -57,18 +61,23 @@ public: void onMouseEnter(S32 x, S32 y, MASK mask); void onMouseLeave(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + + static void showPlaceInfoPanel(S32 index); private: void onInfoBtnClick(); LLButton* mInfoBtn; + LLTeleportHistoryPanel::ContextMenu *mContextMenu; S32 mIndex; std::string mRegionName; }; -LLTeleportHistoryFlatItem::LLTeleportHistoryFlatItem(S32 index, const std::string ®ion_name) +LLTeleportHistoryFlatItem::LLTeleportHistoryFlatItem(S32 index, LLTeleportHistoryPanel::ContextMenu *context_menu, const std::string ®ion_name) : LLPanel(), mIndex(index), + mContextMenu(context_menu), mRegionName(region_name) { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_teleport_history_item.xml"); @@ -109,15 +118,105 @@ void LLTeleportHistoryFlatItem::onMouseLeave(S32 x, S32 y, MASK mask) LLPanel::onMouseLeave(x, y, mask); } -void LLTeleportHistoryFlatItem::onInfoBtnClick() +// virtual +BOOL LLTeleportHistoryFlatItem::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mContextMenu) + mContextMenu->show(this, mIndex, x, y); + + return LLPanel::handleRightMouseDown(x, y, mask); +} + +void LLTeleportHistoryFlatItem::showPlaceInfoPanel(S32 index) { LLSD params; - params["id"] = mIndex; + params["id"] = index; params["type"] = "teleport_history"; LLSideTray::getInstance()->showPanel("panel_places", params); } +void LLTeleportHistoryFlatItem::onInfoBtnClick() +{ + LLTeleportHistoryFlatItem::showPlaceInfoPanel(mIndex); +} + +LLTeleportHistoryPanel::ContextMenu::ContextMenu() : + mMenu(NULL) +{ +} + +void LLTeleportHistoryPanel::ContextMenu::show(LLView* spawning_view, S32 index, S32 x, S32 y) +{ + if (mMenu) + { + //preventing parent (menu holder) from deleting already "dead" context menus on exit + LLView* parent = mMenu->getParent(); + if (parent) + { + parent->removeChild(mMenu); + mMenu->setParent(NULL); + } + delete mMenu; + } + + mIndex = index; + mMenu = createMenu(); + + LLViewerInventoryItem *landmark = LLLandmarkActions::findLandmarkForGlobalPos( + LLTeleportHistoryStorage::getInstance()->getItems()[index].mGlobalPos); + + mMenu->setItemEnabled("Make Landmark", !landmark || landmark->getUUID().isNull()); + + mMenu->show(x, y); + LLMenuGL::showPopup(spawning_view, mMenu, x, y); +} + +LLContextMenu* LLTeleportHistoryPanel::ContextMenu::createMenu() +{ + // set up the callbacks for all of the avatar menu items + // (N.B. callbacks don't take const refs as mID is local scope) + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + + registrar.add("TeleportHistory.Teleport", boost::bind(&LLTeleportHistoryPanel::ContextMenu::onTeleport, this)); + registrar.add("TeleportHistory.MoreInformation",boost::bind(&LLTeleportHistoryPanel::ContextMenu::onInfo, this)); + registrar.add("TeleportHistory.Copy", boost::bind(&LLTeleportHistoryPanel::ContextMenu::onCopy, this)); + registrar.add("TeleportHistory.MakeLandmark", boost::bind(&LLTeleportHistoryPanel::ContextMenu::onMakeLandmark, this)); + + // create the context menu from the XUI + return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( + "menu_teleport_history_item.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); +} + +void LLTeleportHistoryPanel::ContextMenu::onTeleport() +{ + LLTeleportHistoryStorage::getInstance()->goToItem(mIndex); +} + +void LLTeleportHistoryPanel::ContextMenu::onInfo() +{ + LLTeleportHistoryFlatItem::showPlaceInfoPanel(mIndex); +} + +//static +void LLTeleportHistoryPanel::ContextMenu::gotSLURLCallback(const std::string& slurl) +{ + gClipboard.copyFromString(utf8str_to_wstring(slurl)); +} + +void LLTeleportHistoryPanel::ContextMenu::onCopy() +{ + LLVector3d globalPos = LLTeleportHistoryStorage::getInstance()->getItems()[mIndex].mGlobalPos; + LLLandmarkActions::getSLURLfromPosGlobal(globalPos, + boost::bind(&LLTeleportHistoryPanel::ContextMenu::gotSLURLCallback, _1), false); +} + +void LLTeleportHistoryPanel::ContextMenu::onMakeLandmark() +{ + //FIXME: it creates landmark for current agent positon, not for the global position of item of teleport history + LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark")); +} + // Not yet implemented; need to remove buildPanel() from constructor when we switch //static LLRegisterPanelClassWrapper<LLTeleportHistoryPanel> t_teleport_history("panel_teleport_history"); @@ -126,6 +225,7 @@ LLTeleportHistoryPanel::LLTeleportHistoryPanel() mFilterSubString(LLStringUtil::null), mTeleportHistory(NULL), mHistoryAccordion(NULL), + mAccordionTabMenu(NULL), mLastSelectedScrollList(NULL) { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_teleport_history.xml"); @@ -153,6 +253,8 @@ BOOL LLTeleportHistoryPanel::postBuild() if (dynamic_cast<LLAccordionCtrlTab*>(*iter)) { LLAccordionCtrlTab* tab = (LLAccordionCtrlTab*)*iter; + tab->setRightMouseDownCallback(boost::bind(&LLTeleportHistoryPanel::onAccordionTabRightClick, this, _1, _2, _3, _4)); + mItemContainers.put(tab); LLFlatListView* fl = getFlatListViewFromTab(tab); @@ -306,12 +408,12 @@ void LLTeleportHistoryPanel::showTeleportHistory() if (curr_tab <= tabs_cnt - 4) { - curr_date.secondsSinceEpoch(curr_date.secondsSinceEpoch() - seconds_in_day); + curr_date.secondsSinceEpoch(curr_date.secondsSinceEpoch() - seconds_in_day); } else if (curr_tab == tabs_cnt - 3) // 6 day and older, low boundary is 1 month { curr_date = LLDate::now(); - curr_date.split(&curr_year, &curr_month, &curr_day); + curr_date.split(&curr_year, &curr_month, &curr_day); curr_month--; if (0 == curr_month) { @@ -354,7 +456,7 @@ void LLTeleportHistoryPanel::showTeleportHistory() if (curr_flat_view) { - curr_flat_view->addItem(new LLTeleportHistoryFlatItem(index, (*iter).mTitle)); + curr_flat_view->addItem(new LLTeleportHistoryFlatItem(index, &mContextMenu, (*iter).mTitle)); } index--; @@ -376,7 +478,7 @@ void LLTeleportHistoryPanel::handleItemSelect(LLFlatListView* selected) S32 tabs_cnt = mItemContainers.size(); for (S32 n = 0; n < tabs_cnt; n++) - { + { LLAccordionCtrlTab* tab = mItemContainers.get(n); if (!tab->getVisible()) @@ -390,7 +492,7 @@ void LLTeleportHistoryPanel::handleItemSelect(LLFlatListView* selected) continue; flv->resetSelection(true); - } + } updateVerbs(); } @@ -411,6 +513,56 @@ void LLTeleportHistoryPanel::onDoubleClickItem(void* user_data) LLSideTray::getInstance()->showPanel("panel_places", key);*/ } +void LLTeleportHistoryPanel::onAccordionTabRightClick(LLView *view, S32 x, S32 y, MASK mask) +{ + LLAccordionCtrlTab *tab = (LLAccordionCtrlTab *) view; + + // If click occurred below the header, don't show this menu + if (y < tab->getRect().getHeight() - tab->getHeaderHeight() - tab->getPaddingBottom()) + return; + + if (mAccordionTabMenu) + { + //preventing parent (menu holder) from deleting already "dead" context menus on exit + LLView* parent = mAccordionTabMenu->getParent(); + if (parent) + { + parent->removeChild(mAccordionTabMenu); + mAccordionTabMenu->setParent(NULL); + } + delete mAccordionTabMenu; + } + + // set up the callbacks for all of the avatar menu items + // (N.B. callbacks don't take const refs as mID is local scope) + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + + registrar.add("TeleportHistory.TabOpen", boost::bind(&LLTeleportHistoryPanel::onAccordionTabOpen, this, tab)); + registrar.add("TeleportHistory.TabClose", boost::bind(&LLTeleportHistoryPanel::onAccordionTabClose, this, tab)); + + // create the context menu from the XUI + mAccordionTabMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( + "menu_teleport_history_tab.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); + + mAccordionTabMenu->setItemVisible("TabOpen", !tab->isExpanded() ? true : false); + mAccordionTabMenu->setItemVisible("TabClose", tab->isExpanded() ? true : false); + + mAccordionTabMenu->show(x, y); + LLMenuGL::showPopup(tab, mAccordionTabMenu, x, y); +} + +void LLTeleportHistoryPanel::onAccordionTabOpen(LLAccordionCtrlTab *tab) +{ + tab->setDisplayChildren(true); + mHistoryAccordion->arrange(); +} + +void LLTeleportHistoryPanel::onAccordionTabClose(LLAccordionCtrlTab *tab) +{ + tab->setDisplayChildren(false); + mHistoryAccordion->arrange(); +} + LLFlatListView* LLTeleportHistoryPanel::getFlatListViewFromTab(LLAccordionCtrlTab *tab) { for (child_list_const_iter_t iter = tab->beginChild(); iter != tab->endChild(); iter++) diff --git a/indra/newview/llpanelteleporthistory.h b/indra/newview/llpanelteleporthistory.h index 66187e69c6..ebba25cfa5 100644 --- a/indra/newview/llpanelteleporthistory.h +++ b/indra/newview/llpanelteleporthistory.h @@ -37,6 +37,7 @@ #include "llpanelplacestab.h" #include "llteleporthistory.h" +#include "llmenugl.h" class LLTeleportHistoryStorage; class LLAccordionCtrl; @@ -46,6 +47,25 @@ class LLFlatListView; class LLTeleportHistoryPanel : public LLPanelPlacesTab { public: + class ContextMenu + { + public: + ContextMenu(); + void show(LLView* spawning_view, S32 index, S32 x, S32 y); + + private: + LLContextMenu* createMenu(); + void onTeleport(); + void onInfo(); + void onCopy(); + void onMakeLandmark(); + + static void gotSLURLCallback(const std::string& slurl); + + LLContextMenu* mMenu; + S32 mIndex; + }; + LLTeleportHistoryPanel(); virtual ~LLTeleportHistoryPanel(); @@ -59,6 +79,9 @@ public: private: static void onDoubleClickItem(void* user_data); + void onAccordionTabRightClick(LLView *view, S32 x, S32 y, MASK mask); + void onAccordionTabOpen(LLAccordionCtrlTab *tab); + void onAccordionTabClose(LLAccordionCtrlTab *tab); void showTeleportHistory(); void handleItemSelect(LLFlatListView* ); LLFlatListView* getFlatListViewFromTab(LLAccordionCtrlTab *); @@ -70,6 +93,9 @@ private: typedef LLDynamicArray<LLAccordionCtrlTab*> item_containers_t; item_containers_t mItemContainers; + + ContextMenu mContextMenu; + LLContextMenu* mAccordionTabMenu; }; #endif //LL_LLPANELTELEPORTHISTORY_H diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 0ecdec65d6..19bb60b237 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -44,6 +44,7 @@ #include "llinventorymodel.h" #include "llkeyboard.h" #include "lllineeditor.h" +#include "llhelp.h" #include "llresmgr.h" #include "llscrollbar.h" @@ -103,7 +104,7 @@ const std::string HELLO_LSL = " llSay(0, \"Touched.\");\n" " }\n" "}\n"; -const std::string HELP_LSL_URL = "http://wiki.secondlife.com/wiki/LSL_Portal"; +const std::string HELP_LSL_PORTAL_TOPIC = "LSL_Portal"; const std::string DEFAULT_SCRIPT_NAME = "New Script"; // *TODO:Translate? const std::string DEFAULT_SCRIPT_DESC = "(No Description)"; // *TODO:Translate? @@ -264,7 +265,6 @@ struct LLSECKeywordCompare LLScriptEdCore::LLScriptEdCore( const std::string& sample, - const std::string& help_url, const LLHandle<LLFloater>& floater_handle, void (*load_callback)(void*), void (*save_callback)(void*, BOOL), @@ -274,7 +274,6 @@ LLScriptEdCore::LLScriptEdCore( : LLPanel(), mSampleText(sample), - mHelpURL(help_url), mEditor( NULL ), mLoadCallback( load_callback ), mSaveCallback( save_callback ), @@ -436,7 +435,7 @@ void LLScriptEdCore::initMenu() menuItem = getChild<LLMenuItemCallGL>("Help..."); menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnHelp, this)); - menuItem = getChild<LLMenuItemCallGL>("LSL Wiki Help..."); + menuItem = getChild<LLMenuItemCallGL>("Keyword Help..."); menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnDynamicHelp, this)); } @@ -539,9 +538,12 @@ void LLScriptEdCore::updateDynamicHelp(BOOL immediate) mLiveHelpTimer.stop(); } } - else if (immediate) + else { - setHelpPage(LLStringUtil::null); + if (immediate) + { + setHelpPage(LLStringUtil::null); + } } } @@ -557,6 +559,7 @@ void LLScriptEdCore::setHelpPage(const std::string& help_string) if (!history_combo) return; LLUIString url_string = gSavedSettings.getString("LSLHelpURL"); + url_string.setArg("[LSL_STRING]", help_string); addHelpItemToHistory(help_string); @@ -647,69 +650,52 @@ bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLS return false; } -// static -bool LLScriptEdCore::onHelpWebDialog(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - - switch(option) - { - case 0: - LLWeb::loadURL(notification["payload"]["help_url"]); - break; - default: - break; - } - return false; -} - void LLScriptEdCore::onBtnHelp() { - LLSD payload; - payload["help_url"] = mHelpURL; - LLNotifications::instance().add("WebLaunchLSLGuide", LLSD(), payload, onHelpWebDialog); + LLUI::sHelpImpl->showTopic(HELP_LSL_PORTAL_TOPIC); } void LLScriptEdCore::onBtnDynamicHelp() { LLFloater* live_help_floater = mLiveHelpHandle.get(); - if (live_help_floater) - { - live_help_floater->setFocus(TRUE); - updateDynamicHelp(TRUE); + if (!live_help_floater) + { + live_help_floater = new LLFloater(LLSD()); + LLUICtrlFactory::getInstance()->buildFloater(live_help_floater, "floater_lsl_guide.xml", NULL); + LLFloater* parent = dynamic_cast<LLFloater*>(getParent()); + parent->addDependentFloater(live_help_floater, TRUE); + live_help_floater->childSetCommitCallback("lock_check", onCheckLock, this); + live_help_floater->childSetValue("lock_check", gSavedSettings.getBOOL("ScriptHelpFollowsCursor")); + live_help_floater->childSetCommitCallback("history_combo", onHelpComboCommit, this); + live_help_floater->childSetAction("back_btn", onClickBack, this); + live_help_floater->childSetAction("fwd_btn", onClickForward, this); + + LLMediaCtrl* browser = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html"); + browser->setAlwaysRefresh(TRUE); + + LLComboBox* help_combo = live_help_floater->getChild<LLComboBox>("history_combo"); + LLKeywordToken *token; + LLKeywords::keyword_iterator_t token_it; + for (token_it = mEditor->keywordsBegin(); + token_it != mEditor->keywordsEnd(); + ++token_it) + { + token = token_it->second; + help_combo->add(wstring_to_utf8str(token->getToken())); + } + help_combo->sortByName(); - return; + // re-initialize help variables + mLastHelpToken = NULL; + mLiveHelpHandle = live_help_floater->getHandle(); + mLiveHelpHistorySize = 0; } - live_help_floater = new LLFloater(LLSD()); - LLUICtrlFactory::getInstance()->buildFloater(live_help_floater, "floater_lsl_guide.xml", NULL); - LLFloater* parent = dynamic_cast<LLFloater*>(getParent()); - parent->addDependentFloater(live_help_floater, TRUE); - live_help_floater->childSetCommitCallback("lock_check", onCheckLock, this); - live_help_floater->childSetValue("lock_check", gSavedSettings.getBOOL("ScriptHelpFollowsCursor")); - live_help_floater->childSetCommitCallback("history_combo", onHelpComboCommit, this); - live_help_floater->childSetAction("back_btn", onClickBack, this); - live_help_floater->childSetAction("fwd_btn", onClickForward, this); - - LLMediaCtrl* browser = live_help_floater->getChild<LLMediaCtrl>("lsl_guide_html"); - browser->setAlwaysRefresh(TRUE); - - LLComboBox* help_combo = live_help_floater->getChild<LLComboBox>("history_combo"); - LLKeywordToken *token; - LLKeywords::keyword_iterator_t token_it; - for (token_it = mEditor->keywordsBegin(); - token_it != mEditor->keywordsEnd(); - ++token_it) - { - token = token_it->second; - help_combo->add(wstring_to_utf8str(token->getToken())); - } - help_combo->sortByName(); + BOOL visible = TRUE; + BOOL take_focus = TRUE; + live_help_floater->setVisible(visible); + live_help_floater->setFrontmost(take_focus); - // re-initialize help variables - mLastHelpToken = NULL; - mLiveHelpHandle = live_help_floater->getHandle(); - mLiveHelpHistorySize = 0; updateDynamicHelp(TRUE); } @@ -945,7 +931,6 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata) self->mScriptEd = new LLScriptEdCore( HELLO_LSL, - HELP_LSL_URL, self->getHandle(), LLPreviewLSL::onLoad, LLPreviewLSL::onSave, @@ -1411,7 +1396,6 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) self->mScriptEd = new LLScriptEdCore( HELLO_LSL, - HELP_LSL_URL, self->getHandle(), &LLLiveLSLEditor::onLoad, &LLLiveLSLEditor::onSave, diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 623886101a..a00f580e32 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -64,7 +64,6 @@ class LLScriptEdCore : public LLPanel public: LLScriptEdCore( const std::string& sample, - const std::string& help_url, const LLHandle<LLFloater>& floater_handle, void (*load_callback)(void* userdata), void (*save_callback)(void* userdata, BOOL close_after_save), @@ -86,7 +85,6 @@ public: bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response); bool handleReloadFromServerDialog(const LLSD& notification, const LLSD& response); - static bool onHelpWebDialog(const LLSD& notification, const LLSD& response); static void onCheckLock(LLUICtrl*, void*); static void onHelpComboCommit(LLUICtrl* ctrl, void* userdata); static void onClickBack(void* userdata); @@ -116,7 +114,6 @@ protected: private: std::string mSampleText; - std::string mHelpURL; LLTextEditor* mEditor; void (*mLoadCallback)(void* userdata); void (*mSaveCallback)(void* userdata, BOOL close_after_save); @@ -124,7 +121,6 @@ private: void* mUserdata; LLComboBox *mFunctions; BOOL mForceClose; - //LLPanel* mGuiPanel; LLPanel* mCodePanel; LLScrollListCtrl* mErrorList; LLDynamicArray<LLEntryAndEdCore*> mBridges; diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 082bba027f..8a96a5a1ae 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -55,36 +55,30 @@ using namespace LLNotificationsUI; bool LLScreenChannel::mWasStartUpToastShown = false; //-------------------------------------------------------------------------- -LLScreenChannel::LLScreenChannel(LLUUID& id): mOverflowToastPanel(NULL), mStartUpToastPanel(NULL), - mToastAlignment(NA_BOTTOM), mCanStoreToasts(true), - mHiddenToastsNum(0), mOverflowToastHidden(false), - mIsHovering(false), mControlHovering(false), - mShowToasts(true) +////////////////////// +// LLScreenChannelBase +////////////////////// +LLScreenChannelBase::LLScreenChannelBase(const LLUUID& id) : + mOverflowToastPanel(NULL) + ,mToastAlignment(NA_BOTTOM) + ,mCanStoreToasts(true) + ,mHiddenToastsNum(0) + ,mOverflowToastHidden(false) + ,mIsHovering(false) + ,mControlHovering(false) + ,mShowToasts(true) { mID = id; mOverflowFormatString = LLTrans::getString("OverflowInfoChannelString"); - mWorldViewRectConnection = gViewerWindow->setOnWorldViewRectUpdated(boost::bind(&LLScreenChannel::updatePositionAndSize, this, _1, _2)); + mWorldViewRectConnection = gViewerWindow->setOnWorldViewRectUpdated(boost::bind(&LLScreenChannelBase::updatePositionAndSize, this, _1, _2)); setMouseOpaque( false ); setVisible(FALSE); } - -//-------------------------------------------------------------------------- -void LLScreenChannel::init(S32 channel_left, S32 channel_right) -{ - S32 channel_top = gViewerWindow->getWorldViewRect().getHeight(); - S32 channel_bottom = gViewerWindow->getWorldViewRect().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin"); - setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom)); - setVisible(TRUE); -} - -//-------------------------------------------------------------------------- -LLScreenChannel::~LLScreenChannel() +LLScreenChannelBase::~LLScreenChannelBase() { mWorldViewRectConnection.disconnect(); } - -//-------------------------------------------------------------------------- -void LLScreenChannel::updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect) +void LLScreenChannelBase::updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect) { S32 top_delta = old_world_rect.mTop - new_world_rect.mTop; S32 right_delta = old_world_rect.mRight - new_world_rect.mRight; @@ -105,6 +99,42 @@ void LLScreenChannel::updatePositionAndSize(LLRect old_world_rect, LLRect new_wo } setRect(this_rect); redrawToasts(); + +} + +void LLScreenChannelBase::init(S32 channel_left, S32 channel_right) +{ + S32 channel_top = gViewerWindow->getWorldViewRect().getHeight(); + S32 channel_bottom = gViewerWindow->getWorldViewRect().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin"); + setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom)); + setVisible(TRUE); +} + +//-------------------------------------------------------------------------- +////////////////////// +// LLScreenChannel +////////////////////// +//-------------------------------------------------------------------------- +LLScreenChannel::LLScreenChannel(LLUUID& id): LLScreenChannelBase(id) +{ +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::init(S32 channel_left, S32 channel_right) +{ + LLScreenChannelBase::init(channel_left, channel_right); +} + +//-------------------------------------------------------------------------- +LLScreenChannel::~LLScreenChannel() +{ + +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect) +{ + LLScreenChannelBase::updatePositionAndSize(old_world_rect, new_world_rect); } //-------------------------------------------------------------------------- @@ -112,7 +142,7 @@ void LLScreenChannel::addToast(LLToast::Params p) { bool store_toast = false, show_toast = false; - show_toast = mWasStartUpToastShown && (mShowToasts || p.force_show); + mDisplayToastsAlways ? show_toast = true : show_toast = mWasStartUpToastShown && (mShowToasts || p.force_show); store_toast = !show_toast && p.can_be_stored && mCanStoreToasts; if(!show_toast && !store_toast) @@ -561,7 +591,7 @@ void LLScreenChannel::removeAndStoreAllStorableToasts() else { ++it; - } + } } redrawToasts(); } diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h index f1ef6bd64d..459c28ac7c 100644 --- a/indra/newview/llscreenchannel.h +++ b/indra/newview/llscreenchannel.h @@ -55,10 +55,95 @@ typedef enum e_channel_alignment CA_RIGHT, } EChannelAlignment; +class LLScreenChannelBase : public LLUICtrl +{ + friend class LLChannelManager; +public: + LLScreenChannelBase(const LLUUID& id); + ~LLScreenChannelBase(); + + // Channel's outfit-functions + // update channel's size and position in the World View + virtual void updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect); + // initialization of channel's shape and position + virtual void init(S32 channel_left, S32 channel_right); + + + virtual void setToastAlignment(EToastAlignment align) {mToastAlignment = align;} + + virtual void setChannelAlignment(EChannelAlignment align) {mChannelAlignment = align;} + virtual void setOverflowFormatString ( const std::string& str) { mOverflowFormatString = str; } + + // kill or modify a toast by its ID + virtual void killToastByNotificationID(LLUUID id) {}; + virtual void modifyToastNotificationByID(LLUUID id, LLSD data) {}; + + // hide all toasts from screen, but not remove them from a channel + virtual void hideToastsFromScreen() {}; + // removes all toasts from a channel + virtual void removeToastsFromChannel() {}; + + // show all toasts in a channel + virtual void redrawToasts() {}; + + virtual void closeOverflowToastPanel() {}; + virtual void hideOverflowToastPanel() {}; + + + // Channel's behavior-functions + // set whether a channel will control hovering inside itself or not + virtual void setControlHovering(bool control) { mControlHovering = control; } + // set Hovering flag for a channel + virtual void setHovering(bool hovering) { mIsHovering = hovering; } + + void setCanStoreToasts(bool store) { mCanStoreToasts = store; } + + void setDisplayToastsAlways(bool display_toasts) { mDisplayToastsAlways = display_toasts; } + bool getDisplayToastsAlways() { return mDisplayToastsAlways; } + + // get number of hidden notifications from a channel + S32 getNumberOfHiddenToasts() { return mHiddenToastsNum;} + + + void setShowToasts(bool show) { mShowToasts = show; } + bool getShowToasts() { return mShowToasts; } + + // get toast allignment preset for a channel + e_notification_toast_alignment getToastAlignment() {return mToastAlignment;} + + // get ID of a channel + LLUUID getChannelID() { return mID; } + +protected: + // Channel's flags + bool mControlHovering; + bool mIsHovering; + bool mCanStoreToasts; + bool mDisplayToastsAlways; + bool mOverflowToastHidden; + // controls whether a channel shows toasts or not + bool mShowToasts; + // + EToastAlignment mToastAlignment; + EChannelAlignment mChannelAlignment; + + // attributes for the Overflow Toast + S32 mHiddenToastsNum; + LLToast* mOverflowToastPanel; + std::string mOverflowFormatString; + + // channel's ID + LLUUID mID; + + // store a connection to prevent futher crash that is caused by sending a signal to a destroyed channel + boost::signals2::connection mWorldViewRectConnection; +}; + + /** * Screen channel manages toasts visibility and positioning on the screen. */ -class LLScreenChannel : public LLUICtrl +class LLScreenChannel : public LLScreenChannelBase { friend class LLChannelManager; public: @@ -70,12 +155,6 @@ public: void updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect); // initialization of channel's shape and position void init(S32 channel_left, S32 channel_right); - // set allignment of toasts inside a channel - void setToastAlignment(EToastAlignment align) {mToastAlignment = align;} - // set allignment of channel inside a world view - void setChannelAlignment(EChannelAlignment align) {mChannelAlignment = align;} - // set a template for a string in the OverflowToast - void setOverflowFormatString ( std::string str) { mOverflowFormatString = str; } // Operating with toasts // add a toast to a channel @@ -104,37 +183,17 @@ public: // close the StartUp Toast void closeStartUpToast(); - // Channel's behavior-functions - // set whether a channel will control hovering inside itself or not - void setControlHovering(bool control) { mControlHovering = control; } - // set Hovering flag for a channel - void setHovering(bool hovering) { mIsHovering = hovering; } - // set whether a channel will store faded toasts or not - void setCanStoreToasts(bool store) { mCanStoreToasts = store; } - // tell all channels that the StartUp toast was shown and allow them showing of toasts - static void setStartUpToastShown() { mWasStartUpToastShown = true; } // get StartUp Toast's state static bool getStartUpToastShown() { return mWasStartUpToastShown; } - // set mode for dislaying of toasts - void setDisplayToastsAlways(bool display_toasts) { mDisplayToastsAlways = display_toasts; } - // get mode for dislaying of toasts - bool getDisplayToastsAlways() { return mDisplayToastsAlways; } - // tell a channel to show toasts or not - void setShowToasts(bool show) { mShowToasts = show; } - // determine whether channel shows toasts or not - bool getShowToasts() { return mShowToasts; } + // tell all channels that the StartUp toast was shown and allow them showing of toasts + static void setStartUpToastShown() { mWasStartUpToastShown = true; } // let a channel update its ShowToast flag void updateShowToastsState(); + // Channel's other interface functions functions - // get number of hidden notifications from a channel - S32 getNumberOfHiddenToasts() { return mHiddenToastsNum;} // update number of notifications in the StartUp Toast void updateStartUpString(S32 num); - // get toast allignment preset for a channel - e_notification_toast_alignment getToastAlignment() {return mToastAlignment;} - // get ID of a channel - LLUUID getChannelID() { return mID; } // Channel's signals // signal on storing of faded toasts event @@ -201,30 +260,10 @@ private: // Channel's flags static bool mWasStartUpToastShown; - bool mControlHovering; - bool mIsHovering; - bool mCanStoreToasts; - bool mDisplayToastsAlways; - bool mOverflowToastHidden; - // controls whether a channel shows toasts or not - bool mShowToasts; - // - EToastAlignment mToastAlignment; - EChannelAlignment mChannelAlignment; - - // attributes for the Overflow Toast - S32 mHiddenToastsNum; - LLToast* mOverflowToastPanel; - std::string mOverflowFormatString; // attributes for the StartUp Toast LLToast* mStartUpToastPanel; - // channel's ID - LLUUID mID; - - // store a connection to prevent futher crash that is caused by sending a signal to a destroyed channel - boost::signals2::connection mWorldViewRectConnection; std::vector<ToastElem> mToastList; std::vector<ToastElem> mStoredToastList; diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index b25331e439..ae8c9f770b 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1721,13 +1721,8 @@ void LLSelectMgr::selectionSetFullbright(U8 fullbright) getSelection()->applyToObjects(&sendfunc); } -void LLSelectMgr::selectionSetMediaTypeAndURL(U8 media_type, const std::string& media_url) +void LLSelectMgr::selectionSetMedia(U8 media_type) { - U8 media_flags = LLTextureEntry::MF_NONE; - if (media_type == LLViewerObject::MEDIA_TYPE_WEB_PAGE) - { - media_flags = LLTextureEntry::MF_WEB_PAGE; - } struct f : public LLSelectedTEFunctor { @@ -1737,33 +1732,72 @@ void LLSelectMgr::selectionSetMediaTypeAndURL(U8 media_type, const std::string& { if (object->permModify()) { - // update viewer side color in anticipation of update from simulator + // update viewer has media object->setTEMediaFlags(te, mMediaFlags); } return true; } - } setfunc(media_flags); + } setfunc(media_type); getSelection()->applyToTEs(&setfunc); - - struct g : public LLSelectedObjectFunctor + struct f2 : public LLSelectedObjectFunctor { - U8 media_type; - const std::string& media_url ; - g(U8 a, const std::string& b) : media_type(a), media_url(b) {} virtual bool apply(LLViewerObject* object) { if (object->permModify()) { object->sendTEUpdate(); - object->setMediaType(media_type); - object->setMediaURL(media_url); } return true; } - } sendfunc(media_type, media_url); - getSelection()->applyToObjects(&sendfunc); + } func2; + mSelectedObjects->applyToObjects( &func2 ); } +// This function expects media_data to be a map containing relevant +// media data name/value pairs (e.g. home_url, etc.) +void LLSelectMgr::selectionSetMediaData(const LLSD &media_data) +{ + + struct f : public LLSelectedTEFunctor + { + const LLSD &mMediaData; + f(const LLSD& t) : mMediaData(t) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object); + if (NULL != vo) + { + vo->syncMediaData(te, mMediaData, true/*merge*/, true/*ignore_agent*/); + } + } + return true; + } + } setfunc(media_data); + getSelection()->applyToTEs(&setfunc); + + struct f2 : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object); + if (NULL != vo) + { + // Send updated media data FOR THE ENTIRE OBJECT + vo->sendMediaDataUpdate(); + } + } + return true; + } + } func2; + getSelection()->applyToObjects(&func2); +} + + + void LLSelectMgr::selectionSetGlow(F32 glow) { struct f1 : public LLSelectedTEFunctor @@ -5057,7 +5091,15 @@ void LLSelectNode::selectTE(S32 te_index, BOOL selected) { return; } - mTESelectMask |= 0x1 << te_index; + S32 mask = 0x1 << te_index; + if(selected) + { + mTESelectMask |= mask; + } + else + { + mTESelectMask &= ~mask; + } mLastTESelected = te_index; } @@ -6042,6 +6084,29 @@ bool LLObjectSelection::applyToRootNodes(LLSelectedNodeFunctor *func, bool first return result; } +BOOL LLObjectSelection::isMultipleTESelected() +{ + BOOL te_selected = FALSE; + // ...all faces + for (LLObjectSelection::iterator iter = begin(); + iter != end(); iter++) + { + LLSelectNode* nodep = *iter; + for (S32 i = 0; i < SELECT_MAX_TES; i++) + { + if(nodep->isTESelected(i)) + { + if(te_selected) + { + return TRUE; + } + te_selected = TRUE; + } + } + } + return FALSE; +} + //----------------------------------------------------------------------------- // contains() //----------------------------------------------------------------------------- diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 08c2783746..9e02170d74 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -307,6 +307,7 @@ public: S32 getTECount(); S32 getRootObjectCount(); + BOOL isMultipleTESelected(); BOOL contains(LLViewerObject* object); BOOL contains(LLViewerObject* object, S32 te); @@ -504,7 +505,8 @@ public: void selectionSetTexGen( U8 texgen ); void selectionSetShiny( U8 shiny ); void selectionSetFullbright( U8 fullbright ); - void selectionSetMediaTypeAndURL( U8 media_type, const std::string& media_url ); + void selectionSetMedia( U8 media_type ); + void selectionSetMediaData(const LLSD &media_data); // NOTE: modifies media_data!!! void selectionSetClickAction(U8 action); void selectionSetIncludeInSearch(bool include_in_search); void selectionSetGlow(const F32 glow); diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index 381e63f020..2be0aa40d2 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -48,6 +48,7 @@ #include "lliconctrl.h"//for Home tab icon #include "llsidetraypanelcontainer.h" #include "llwindow.h"//for SetCursor +#include "lltransientfloatermgr.h" //#include "llscrollcontainer.h" @@ -248,6 +249,7 @@ LLSideTray::LLSideTray(Params& params) // register handler function to process data from the xml. // panel_name should be specified via "parameter" attribute. commit.add("SideTray.ShowPanel", boost::bind(&LLSideTray::showPanel, this, _2, LLUUID::null)); + LLTransientFloaterMgr::getInstance()->addControlView(this); } @@ -448,13 +450,17 @@ void LLSideTray::reflectCollapseChange() setPanelRect(); if(mCollapsed) + { gFloaterView->setSnapOffsetRight(0); + setFocus(FALSE); + } else + { gFloaterView->setSnapOffsetRight(mMaxBarWidth); + setFocus(TRUE); + } gFloaterView->refresh(); - - setFocus( FALSE ); } void LLSideTray::arrange () diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 4e13cb17a2..7bf0d31d94 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -433,6 +433,11 @@ void LLSpatialGroup::clearDrawMap() mDrawMap.clear(); } +BOOL LLSpatialGroup::isRecentlyVisible() const +{ + return (LLDrawable::getCurrentFrame() - (S32)mVisible) < LLDrawable::getMinVisFrameRange() ; +} + BOOL LLSpatialGroup::isVisible() const { return mVisible[LLViewerCamera::sCurCameraID] == LLDrawable::getCurrentFrame() ? TRUE : FALSE; diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 16e8782a8e..64c2a9acbc 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -267,6 +267,7 @@ public: BOOL removeObject(LLDrawable *drawablep, BOOL from_octree = FALSE); BOOL updateInGroup(LLDrawable *drawablep, BOOL immediate = FALSE); // Update position if it's in the group BOOL isVisible() const; + BOOL isRecentlyVisible() const; void setVisible(); void shift(const LLVector3 &offset); BOOL boundObjects(BOOL empty, LLVector3& newMin, LLVector3& newMax); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 6a55b571ae..053b863b6d 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1429,6 +1429,17 @@ bool idle_startup() LLStartUp::deletePasswordFromDisk(); } + // this is the base used to construct help URLs + text = LLUserAuth::getInstance()->getResponse("help_url_format"); + if (!text.empty()) + { + // replace the default help URL format + gSavedSettings.setString("HelpURLFormat",text); + + // don't fall back to Nebraska's pre-connection static help + gSavedSettings.setBOOL("HelpUseLocal", false); + } + // this is their actual ability to access content text = LLUserAuth::getInstance()->getResponse("agent_access_max"); if (!text.empty()) diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index d7df258750..b0930cd86d 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -225,22 +225,14 @@ void LLStatusBar::draw() BOOL LLStatusBar::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (mHideNavbarContextMenu) - { - mHideNavbarContextMenu->buildDrawLabels(); - mHideNavbarContextMenu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, mHideNavbarContextMenu, x, y); - } - + show_navbar_context_menu(this,x,y); return TRUE; } BOOL LLStatusBar::postBuild() { - mHideNavbarContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gMenuHolder->addChild(mHideNavbarContextMenu); - gMenuBarView->setRightMouseDownCallback(boost::bind(&LLStatusBar::onMainMenuRightClicked, this, _1, _2, _3, _4)); + gMenuBarView->setRightMouseDownCallback(boost::bind(&show_navbar_context_menu, _1, _2, _3)); return TRUE; } @@ -560,11 +552,6 @@ void LLStatusBar::setupDate() } } -void LLStatusBar::onMainMenuRightClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask) -{ - handleRightMouseDown(x, y, mask); -} - // static void LLStatusBar::onClickStatGraph(void* data) { diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 81a69e9590..d5629e6f1e 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -91,7 +91,6 @@ private: // simple method to setup the part that holds the date void setupDate(); - void onMainMenuRightClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask); static void onCommitSearch(LLUICtrl*, void* data); static void onClickSearch(void* data); static void onClickStatGraph(void* data); @@ -111,8 +110,7 @@ private: S32 mSquareMetersCommitted; LLFrameTimer* mBalanceTimer; LLFrameTimer* mHealthTimer; - LLMenuGL* mHideNavbarContextMenu; - + static std::vector<std::string> sDays; static std::vector<std::string> sMonths; static const U32 MAX_DATE_STRING_LENGTH; diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index c1eecf4c12..669d8d1d70 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -109,6 +109,15 @@ BOOL LLSysWellWindow::postBuild() } //--------------------------------------------------------------------------------- +void LLSysWellWindow::setMinimized(BOOL minimize) +{ + // we don't show empty Message Well window + setVisible(!minimize && !isWindowEmpty()); + + LLFloater::setMinimized(minimize); +} + +//--------------------------------------------------------------------------------- void LLSysWellWindow::connectListUpdaterToSignal(std::string notification_type) { LLNotificationsUI::LLNotificationManager* manager = LLNotificationsUI::LLNotificationManager::getInstance(); @@ -155,10 +164,10 @@ void LLSysWellWindow::addItem(LLSysWellItem::Params p) { handleItemAdded(IT_NOTIFICATION); - reshapeWindow(); + reshapeWindow(); - new_item->setOnItemCloseCallback(boost::bind(&LLSysWellWindow::onItemClose, this, _1)); - new_item->setOnItemClickCallback(boost::bind(&LLSysWellWindow::onItemClick, this, _1)); + new_item->setOnItemCloseCallback(boost::bind(&LLSysWellWindow::onItemClose, this, _1)); + new_item->setOnItemClickCallback(boost::bind(&LLSysWellWindow::onItemClick, this, _1)); } else { @@ -226,11 +235,11 @@ void LLSysWellWindow::onStoreToast(LLPanel* info_panel, LLUUID id) //--------------------------------------------------------------------------------- void LLSysWellWindow::initChannel() { - LLNotificationsUI::LLScreenChannel* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID( + LLNotificationsUI::LLScreenChannelBase* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID( LLUUID(gSavedSettings.getString("NotificationChannelUUID"))); - if(channel) + mChannel = dynamic_cast<LLNotificationsUI::LLScreenChannel*>(channel); + if(mChannel) { - mChannel = channel; mChannel->setOnStoreToastCallback(boost::bind(&LLSysWellWindow::onStoreToast, this, _1, _2)); } else @@ -240,7 +249,7 @@ void LLSysWellWindow::initChannel() } //--------------------------------------------------------------------------------- -void LLSysWellWindow::getEnabledRect(LLRect& rect) +void LLSysWellWindow::getAllowedRect(LLRect& rect) { rect = gViewerWindow->getWorldViewRect(); } @@ -252,7 +261,7 @@ void LLSysWellWindow::toggleWindow() { setDockControl(new LLDockControl( LLBottomTray::getInstance()->getSysWell(), this, - getDockTongue(), LLDockControl::TOP, boost::bind(&LLSysWellWindow::getEnabledRect, this, _1))); + getDockTongue(), LLDockControl::TOP, boost::bind(&LLSysWellWindow::getAllowedRect, this, _1))); } if(!getVisible()) @@ -404,20 +413,18 @@ bool LLSysWellWindow::isWindowEmpty() //--------------------------------------------------------------------------------- //virtual -void LLSysWellWindow::sessionAdded(const LLUUID& sessionId, - const std::string& name, const LLUUID& otherParticipantId) +void LLSysWellWindow::sessionAdded(const LLUUID& session_id, + const std::string& name, const LLUUID& other_participant_id) { - if (mMessageList->getItemByValue(get_session_value(sessionId)) == NULL) + //*TODO get rid of get_session_value, session_id's are unique, cause performance degradation with lots chiclets (IB) + if (mMessageList->getItemByValue(get_session_value(session_id)) == NULL) { - S32 chicletCounter = 0; - LLIMModel::LLIMSession* session = get_if_there(LLIMModel::sSessionsMap, - sessionId, (LLIMModel::LLIMSession*) NULL); - if (session != NULL) + S32 chicletCounter = LLIMModel::getInstance()->getNumUnread(session_id); + if (chicletCounter > -1) { - chicletCounter = session->mNumUnread; + addIMRow(session_id, chicletCounter, name, other_participant_id); + reshapeWindow(); } - addIMRow(sessionId, chicletCounter, name, otherParticipantId); - reshapeWindow(); } } @@ -491,6 +498,7 @@ LLSysWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID& switch (im_chiclet_type) { case LLIMChiclet::TYPE_GROUP: + case LLIMChiclet::TYPE_AD_HOC: mChiclet = getChild<LLIMChiclet>("group_chiclet"); childSetVisible("p2p_chiclet", false); break; diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h index 37a2690a82..203b949715 100644 --- a/indra/newview/llsyswellwindow.h +++ b/indra/newview/llsyswellwindow.h @@ -68,6 +68,8 @@ public: void toggleWindow(); /*virtual*/ BOOL canClose() { return FALSE; } /*virtual*/ void setDocked(bool docked, bool pop_on_undock = true); + // override LLFloater's minimization according to EXT-1216 + /*virtual*/ void setMinimized(BOOL minimize); // Handlers void onItemClick(LLSysWellItem* item); @@ -86,8 +88,8 @@ private: IT_INSTANT_MESSAGE }EItemType; - // gets a rect valid for SysWellWindow's position on a screen (EXT-1111) - void getEnabledRect(LLRect& rect); + // gets a rect that bounds possible positions for the SysWellWindow on a screen (EXT-1111) + void getAllowedRect(LLRect& rect); // connect counter and list updaters to the corresponding signals void connectListUpdaterToSignal(std::string notification_type); // init Window's channel diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index 97a15759bf..84931e4d2d 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -41,7 +41,7 @@ using namespace LLNotificationsUI; //-------------------------------------------------------------------------- -LLToast::LLToast(LLToast::Params p) : LLFloater(LLSD()), +LLToast::LLToast(LLToast::Params p) : LLModalDialog(LLSD(), p.is_modal), mPanel(p.panel), mTimerValue(p.timer_period), mNotificationID(p.notif_id), @@ -49,7 +49,6 @@ LLToast::LLToast(LLToast::Params p) : LLFloater(LLSD()), mCanFade(p.can_fade), mCanBeStored(p.can_be_stored), mHideBtnEnabled(p.enable_hide_btn), - mIsModal(p.is_modal), mHideBtn(NULL), mNotification(p.notification), mHideBtnPressed(false) @@ -67,13 +66,6 @@ LLToast::LLToast(LLToast::Params p) : LLFloater(LLSD()), mHideBtn->setClickedCallback(boost::bind(&LLToast::hide,this)); } - if(mIsModal) - { - gFocusMgr.setMouseCapture( this ); - gFocusMgr.setTopCtrl( this ); - setFocus(TRUE); - } - // init callbacks if present if(!p.on_delete_toast.empty()) mOnDeleteToastSignal.connect(p.on_delete_toast); @@ -104,11 +96,6 @@ void LLToast::setHideButtonEnabled(bool enabled) LLToast::~LLToast() { mOnToastDestroyedSignal(this); - if(mIsModal) - { - gFocusMgr.unlockFocus(); - gFocusMgr.releaseFocusIfNeeded( this ); - } } //-------------------------------------------------------------------------- @@ -167,15 +154,30 @@ void LLToast::tick() } //-------------------------------------------------------------------------- -void LLToast::insertPanel(LLPanel* panel) + +void LLToast::reshapeToPanel() { - LLRect panel_rect, toast_rect; + LLPanel* panel = getPanel(); + if(!panel) + return; + + LLRect panel_rect; panel_rect = panel->getRect(); reshape(panel_rect.getWidth(), panel_rect.getHeight()); panel_rect.setLeftTopAndSize(0, panel_rect.getHeight(), panel_rect.getWidth(), panel_rect.getHeight()); panel->setRect(panel_rect); + + LLRect toast_rect = getRect(); + toast_rect.setLeftTopAndSize(toast_rect.mLeft,toast_rect.mTop,panel_rect.getWidth(), panel_rect.getHeight()); + setRect(toast_rect); + +} + +void LLToast::insertPanel(LLPanel* panel) +{ addChild(panel); + reshapeToPanel(); } //-------------------------------------------------------------------------- @@ -190,18 +192,6 @@ void LLToast::draw() } //-------------------------------------------------------------------------- -void LLToast::setModal(bool modal) -{ - mIsModal = modal; - if(mIsModal) - { - gFocusMgr.setMouseCapture( this ); - gFocusMgr.setTopCtrl( this ); - setFocus(TRUE); - } -} - -//-------------------------------------------------------------------------- void LLToast::setVisible(BOOL show) { if(show) diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 9248747c43..29c231a01d 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -35,7 +35,7 @@ #include "llpanel.h" -#include "llfloater.h" +#include "llmodaldialog.h" #include "lltimer.h" #include "llnotifications.h" @@ -51,7 +51,7 @@ namespace LLNotificationsUI * Represents toast pop-up. * This is a parent view for all toast panels. */ -class LLToast : public LLFloater +class LLToast : public LLModalDialog { public: typedef boost::function<void (LLToast* toast)> toast_callback_t; @@ -99,6 +99,9 @@ public: // Operating with toasts // insert a panel to a toast void insertPanel(LLPanel* panel); + + void reshapeToPanel(); + // get toast's panel LLPanel* getPanel() { return mPanel; } // enable/disable Toast's Hide button @@ -131,8 +134,6 @@ public: void setCanBeStored(bool can_be_stored) { mCanBeStored = can_be_stored; } // bool getCanBeStored() { return mCanBeStored; } - // - void setModal(bool modal); // Registers signals/callbacks for events @@ -168,7 +169,6 @@ private: LLColor4 mBgColor; bool mCanFade; - bool mIsModal; bool mCanBeStored; bool mHideBtnEnabled; bool mHideBtnPressed; diff --git a/indra/newview/lltoastpanel.h b/indra/newview/lltoastpanel.h index bc9888f4b4..418373e8c6 100644 --- a/indra/newview/lltoastpanel.h +++ b/indra/newview/lltoastpanel.h @@ -39,6 +39,12 @@ #include <string> +class LLToastPanelBase: public LLPanel +{ +public: + virtual void init(LLSD& data){}; +}; + /** * Base class for all panels that can be added to the toast. * All toast panels should contain necessary logic for representing certain notification diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp index ceb1358d1c..880d5d5e12 100644 --- a/indra/newview/lltool.cpp +++ b/indra/newview/lltool.cpp @@ -67,18 +67,20 @@ LLTool::~LLTool() BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) { - // This is necessary to force clicks in the world to cause edit - // boxes that might have keyboard focus to relinquish it, and hence - // cause a commit to update their value. JC - if (down) + BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); + + // This behavior was moved here from LLViewerWindow::handleAnyMouseClick, so it can be selectively overridden by LLTool subclasses. + if(down && result) { + // This is necessary to force clicks in the world to cause edit + // boxes that might have keyboard focus to relinquish it, and hence + // cause a commit to update their value. JC gFocusMgr.setKeyboardFocus(NULL); } - - return LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); + + return result; } - BOOL LLTool::handleMouseDown(S32 x, S32 y, MASK mask) { if (gDebugClicks) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 5c210c5c28..d5db224143 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -48,6 +48,7 @@ #include "lltooltip.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" +#include "llmediaentry.h" #include "llmenugl.h" #include "llmutelist.h" #include "llselectmgr.h" @@ -75,8 +76,6 @@ extern void handle_buy(void*); extern BOOL gDebugClicks; -static bool handle_media_click(const LLPickInfo& info); -static bool handle_media_hover(const LLPickInfo& info); static void handle_click_action_play(); static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp); static ECursorType cursor_from_parcel_media(U8 click_action); @@ -90,6 +89,16 @@ LLToolPie::LLToolPie() { } +BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down) +{ + BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); + + // This override DISABLES the keyboard focus reset that LLTool::handleAnyMouseClick adds. + // LLToolPie will do the right thing in its pick callback. + + return result; +} + BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) { //left mouse down always picks transparent @@ -258,9 +267,9 @@ BOOL LLToolPie::pickLeftMouseDownCallback() } } - if (handle_media_click(mPick)) + if (handleMediaClick(mPick)) { - return FALSE; + return TRUE; } // put focus back "in world" @@ -466,10 +475,7 @@ void LLToolPie::selectionPropertiesReceived() BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) { mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE); - - // FIXME: This was in the pluginapi branch, but I don't think it's correct. -// gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - + LLViewerObject *parent = NULL; LLViewerObject *object = mHoverPick.getObject(); @@ -484,7 +490,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) gViewerWindow->setCursor(cursor); lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } - else if (handle_media_hover(mHoverPick)) + else if (handleMediaHover(mHoverPick)) { // cursor set by media object lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; @@ -522,6 +528,9 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) { LLViewerObject* obj = mPick.getObject(); + + handleMediaMouseUp(); + U8 click_action = final_click_action(obj); if (click_action != CLICK_ACTION_NONE) { @@ -543,6 +552,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) break; } } + mGrabMouseButtonDown = FALSE; LLToolMgr::getInstance()->clearTransientTool(); gAgent.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on @@ -1038,6 +1048,7 @@ void LLToolPie::stopEditing() void LLToolPie::onMouseCaptureLost() { mMouseOutsideSlop = FALSE; + handleMediaMouseUp(); } @@ -1078,7 +1089,7 @@ static void handle_click_action_play() } } -static bool handle_media_click(const LLPickInfo& pick) +bool LLToolPie::handleMediaClick(const LLPickInfo& pick) { //FIXME: how do we handle object in different parcel than us? LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); @@ -1104,22 +1115,25 @@ static bool handle_media_click(const LLPickInfo& pick) // is media playing on this face? const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); + LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL; + viewer_media_t media_impl = mep ? LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()) : NULL; - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(tep->getID()); - if (tep - && media_impl.notNull() - && media_impl->hasMedia() - && gSavedSettings.getBOOL("MediaOnAPrimUI")) + if (tep + && mep + && gSavedSettings.getBOOL("MediaOnAPrimUI") + && media_impl.notNull()) { - LLObjectSelectionHandle selection = LLViewerMediaFocus::getInstance()->getSelection(); - if (! selection->contains(pick.getObject(), pick.mObjectFace)) + // LLObjectSelectionHandle selection = /*LLViewerMediaFocus::getInstance()->getSelection()*/ LLSelectMgr::getInstance()->getSelection(); + if (/*! selection->contains(pick.getObject(), pick.mObjectFace)*/ + ! LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) ) { LLViewerMediaFocus::getInstance()->setFocusFace(TRUE, pick.getObject(), pick.mObjectFace, media_impl); } else { - media_impl->mouseDown(pick.mXYCoords.mX, pick.mXYCoords.mY); - media_impl->mouseCapture(); // the mouse-up will happen when capture is lost + media_impl->mouseDown(pick.mUVCoords); + mMediaMouseCaptureID = mep->getMediaID(); + setMouseCapture(TRUE); // This object will send a mouse-up to the media when it loses capture. } return true; @@ -1131,7 +1145,7 @@ static bool handle_media_click(const LLPickInfo& pick) return false; } -static bool handle_media_hover(const LLPickInfo& pick) +bool LLToolPie::handleMediaHover(const LLPickInfo& pick) { //FIXME: how do we handle object in different parcel than us? LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); @@ -1156,15 +1170,20 @@ static bool handle_media_hover(const LLPickInfo& pick) // is media playing on this face? const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(tep->getID()); - if (tep - && media_impl.notNull() - && media_impl->hasMedia() + const LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL; + if (mep && gSavedSettings.getBOOL("MediaOnAPrimUI")) - { - if(LLViewerMediaFocus::getInstance()->getFocus()) + { + viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + if(LLViewerMediaFocus::getInstance()->getFocus() && media_impl.notNull()) { - media_impl->mouseMove(pick.mXYCoords.mX, pick.mXYCoords.mY); + media_impl->mouseMove(pick.mUVCoords); + + gViewerWindow->setCursor(media_impl->getLastSetCursor()); + } + else + { + gViewerWindow->setCursor(UI_CURSOR_ARROW); } // Set mouse over flag if unset @@ -1182,6 +1201,28 @@ static bool handle_media_hover(const LLPickInfo& pick) return false; } +bool LLToolPie::handleMediaMouseUp() +{ + bool result = false; + if(mMediaMouseCaptureID.notNull()) + { + // Face media needs to know the mouse went up. + viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mMediaMouseCaptureID); + if(media_impl) + { + // This will send a mouseUp event to the plugin using the last known mouse coordinate (from a mouseDown or mouseMove), which is what we want. + media_impl->onMouseCaptureLost(); + } + + mMediaMouseCaptureID.setNull(); + + setMouseCapture(FALSE); + + result = true; + } + + return result; +} static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp) { diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 328653d2b8..f6a67c13b1 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -42,9 +42,12 @@ class LLObjectSelection; class LLToolPie : public LLTool, public LLSingleton<LLToolPie> { + LOG_CLASS(LLToolPie); public: LLToolPie( ); + // Virtual functions inherited from LLMouseHandler + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType 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); @@ -81,9 +84,15 @@ private: BOOL useClickAction (MASK mask, LLViewerObject* object,LLViewerObject* parent); void showVisualContextMenuEffect(); + + bool handleMediaClick(const LLPickInfo& info); + bool handleMediaHover(const LLPickInfo& info); + bool handleMediaMouseUp(); + private: BOOL mGrabMouseButtonDown; BOOL mMouseOutsideSlop; // for this drag, has mouse moved outside slop region + LLUUID mMediaMouseCaptureID; LLPickInfo mPick; LLPickInfo mHoverPick; LLPointer<LLViewerObject> mClickActionObject; diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index 901d0594f1..e7a8ad6605 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -37,7 +37,7 @@ #include "llagent.h" // teleportViaLocation() #include "llcommandhandler.h" #include "llfloaterdirectory.h" -#include "llfloatermediabrowser.h" +#include "llfloaterhelpbrowser.h" #include "llfloaterreg.h" #include "llfloaterurldisplay.h" #include "llfloaterworldmap.h" @@ -105,7 +105,7 @@ bool LLURLDispatcherImpl::dispatchCore(const std::string& url, bool trusted_browser) { if (url.empty()) return false; - if (dispatchHelp(url, right_mouse)) return true; + //if (dispatchHelp(url, right_mouse)) return true; if (dispatchApp(url, right_mouse, web, trusted_browser)) return true; if (dispatchRegion(url, right_mouse)) return true; @@ -140,19 +140,6 @@ bool LLURLDispatcherImpl::dispatchRightClick(const std::string& url) } // static -bool LLURLDispatcherImpl::dispatchHelp(const std::string& url, bool right_mouse) -{ -#if LL_LIBXUL_ENABLED - if (LLSLURL::isURLHelp(url)) - { - gViewerHtmlHelp.show(); - return true; - } -#endif - return false; -} - -// static bool LLURLDispatcherImpl::dispatchApp(const std::string& url, bool right_mouse, LLMediaCtrl* web, diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 51d699c0f7..2f656479f6 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -65,8 +65,9 @@ #include "llfloatergodtools.h" #include "llfloatergroups.h" #include "llfloaterhardwaresettings.h" -#include "llfloaterhtmlcurrency.h" +#include "llfloaterhelpbrowser.h" #include "llfloatermediabrowser.h" +#include "llfloatermediasettings.h" #include "llfloaterhud.h" #include "llfloaterimagepreview.h" #include "llimfloater.h" @@ -105,6 +106,7 @@ #include "llfloaterurldisplay.h" #include "llfloatervoicedevicesettings.h" #include "llfloaterwater.h" +#include "llfloaterwhitelistentry.h" #include "llfloaterwindlight.h" #include "llfloaterworldmap.h" #include "llinspectavatar.h" @@ -164,8 +166,8 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>); LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGroupPicker>); + LLFloaterReg::add("help_browser", "floater_help_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHelpBrowser>); LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>); - LLFloaterReg::add("html_simple", "floater_html_simple.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHtmlSimple>); LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>); LLFloaterReg::add("inventory", "floater_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventory>); @@ -178,6 +180,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMemLeak>); LLFloaterReg::add("media_browser", "floater_media_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaBrowser>); + LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaSettings>); LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMove>); @@ -238,17 +241,13 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("voice_call", "floater_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCall>); + LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>); LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>); // *NOTE: Please keep these alphabetized for easier merges // debug use only LLFloaterReg::add("media_remote_ctrl", "floater_media_remote.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaRemoteCtrl>); - - // Untested / dangerous - not for release -#if !LL_RELEASE_FOR_DOWNLOAD - LLFloaterReg::add("buy_currency_html", "floater_html_simple.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHtmlCurrency>); -#endif LLFloaterReg::registerControlVariables(); // Make sure visibility and rect controls get preserved when saving } diff --git a/indra/newview/llviewerhelp.cpp b/indra/newview/llviewerhelp.cpp new file mode 100644 index 0000000000..0e0727e382 --- /dev/null +++ b/indra/newview/llviewerhelp.cpp @@ -0,0 +1,125 @@ +/** + * @file llviewerhelp.cpp + * @brief Utility functions for the Help system + * @author Tofu Linden + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterhelpbrowser.h" +#include "llfloaterreg.h" +#include "llfocusmgr.h" +#include "llviewercontrol.h" +#include "llversionviewer.h" +#include "llappviewer.h" + +#include "llviewerhelputil.h" +#include "llviewerhelp.h" + + +////////////////////////////// +// implement LLHelp interface + +void LLViewerHelp::showTopic(const std::string &topic) +{ + showHelp(); + + if( gSavedSettings.getBOOL("HelpUseLocal") ) + { + LLFloaterHelpBrowser* helpbrowser = dynamic_cast<LLFloaterHelpBrowser*>(LLFloaterReg::getInstance("help_browser")); + helpbrowser->navigateToLocalPage( "help-offline" , "index.html" ); + } + else + { + const LLOSInfo& osinfo = LLAppViewer::instance()->getOSInfo(); + std::string helpURL = LLViewerHelpUtil::buildHelpURL( topic, gSavedSettings, osinfo ); + setRawURL( helpURL ); + } +} + +std::string LLViewerHelp::defaultTopic() +{ + // *hack: to be done properly + return "this_is_fallbacktopic"; +} + +////////////////////////////// +// our own interfaces + +std::string LLViewerHelp::getTopicFromFocus() +{ + // use UI element with viewer's keyboard focus as basis for searching + LLUICtrl* focused = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + + if (focused) + { + std::string topic; + if (focused->findHelpTopic(topic)) + { + return topic; + } + } + + // didn't find a help topic in the UI hierarchy for focused + // element, return the fallback topic name instead. + return defaultTopic(); +} + +// static +void LLViewerHelp::showHelp() +{ + LLFloaterHelpBrowser* helpbrowser = dynamic_cast<LLFloaterHelpBrowser*>(LLFloaterReg::getInstance("help_browser")); + if (helpbrowser) + { + BOOL visible = TRUE; + BOOL take_focus = TRUE; + helpbrowser->setVisible(visible); + helpbrowser->setFrontmost(take_focus); + } + else + { + llwarns << "Eep, help_browser floater not found" << llendl; + } +} + +// static +void LLViewerHelp::setRawURL(std::string url) +{ + LLFloaterHelpBrowser* helpbrowser = dynamic_cast<LLFloaterHelpBrowser*>(LLFloaterReg::getInstance("help_browser")); + if (helpbrowser) + { + helpbrowser->openMedia(url); + } + else + { + llwarns << "Eep, help_browser floater not found" << llendl; + } +} + diff --git a/indra/newview/llviewerhelp.h b/indra/newview/llviewerhelp.h new file mode 100644 index 0000000000..17aab6f239 --- /dev/null +++ b/indra/newview/llviewerhelp.h @@ -0,0 +1,65 @@ +/** + * @file llviewerhelp.h + * @brief Utility functions for the Help system + * @author Tofu Linden + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLVIEWERHELP_H +#define LL_LLVIEWERHELP_H + +// The Help UI lives in llfloaterhelpbrowser, llviewerhelp provides a +// layer of abstraction that protects help-system-using code from the details of +// the Help UI floater and how help topics are converted into URLs. + +#include "llhelp.h" // our abstract base +#include "llsingleton.h" + +class LLUICtrl; + +class LLViewerHelp : public LLHelp, public LLSingleton<LLViewerHelp> +{ + friend class LLSingleton<LLViewerHelp>; + + public: + /// display the specified help topic in the help viewer + /*virtual*/ void showTopic(const std::string &topic); + + /// return default (fallback) topic name suitable for showTopic() + /*virtual*/ std::string defaultTopic(); + + // return topic derived from viewer UI focus, else default topic + std::string getTopicFromFocus(); + + private: + static void showHelp(); // make sure help UI is visible & raised + static void setRawURL(std::string url); // send URL to help UI +}; + +#endif // header guard diff --git a/indra/newview/llviewerhelputil.cpp b/indra/newview/llviewerhelputil.cpp new file mode 100644 index 0000000000..c1555eacdc --- /dev/null +++ b/indra/newview/llviewerhelputil.cpp @@ -0,0 +1,114 @@ +/** + * @file llviewerhelp.cpp + * @brief Utility functions for the Help system + * @author Soft Linden + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llversionviewer.h" + +//#include "llfloaterhelpbrowser.h" +//#include "llfloaterreg.h" +//#include "llfocusmgr.h" +//#include "llviewercontrol.h" +//#include "llappviewer.h" + +#include "llstring.h" +#include "lluri.h" +#include "llsys.h" + +#include "llcontrol.h" + +#include "llviewerhelputil.h" + + +////////////////////////////////////////////// +// Build a help URL from a topic and formatter + +//static +std::string LLViewerHelpUtil::helpURLEncode( const std::string &component ) +{ + // Every character rfc3986 allows as unreserved in 2.3, minus the tilde + // which we may grant special meaning. Yay. + const char* allowed = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "-._"; + std::string escaped = LLURI::escape(component, allowed); + + return escaped; +} + +static std::string buildHelpVersion( const U32 ver_int ) +{ + std::ostringstream ver_str; + ver_str << ver_int; + return ver_str.str(); // not encoded - numbers are rfc3986-safe +} + +//static +std::string LLViewerHelpUtil::buildHelpURL( const std::string &topic, + LLControlGroup &savedSettings, + const LLOSInfo &osinfo ) +{ + std::string helpURL = savedSettings.getString("HelpURLFormat"); + LLSD substitution; + substitution["TOPIC"] = helpURLEncode(topic); + + substitution["CHANNEL"] = helpURLEncode(savedSettings.getString("VersionChannelName")); + + // *TODO: We should put this version pattern in a central place; this and near + // equivalents are replicated in other code - what's a good location? + std::ostringstream version; + version << LL_VERSION_MAJOR << "." + << LL_VERSION_MINOR << "." + << LL_VERSION_PATCH << "." + << LL_VERSION_BUILD; + substitution["VERSION"] = helpURLEncode(version.str()); + substitution["VERSION_MAJOR"] = buildHelpVersion(LL_VERSION_MAJOR); + substitution["VERSION_MINOR"] = buildHelpVersion(LL_VERSION_MINOR); + substitution["VERSION_PATCH"] = buildHelpVersion(LL_VERSION_PATCH); + substitution["VERSION_BUILD"] = buildHelpVersion(LL_VERSION_BUILD); + + substitution["OS"] = helpURLEncode(osinfo.getOSStringSimple()); + + std::string language = savedSettings.getString("Language"); + if( language.empty() || language == "default" ) + { + language = savedSettings.getString("SystemLanguage"); + } + substitution["LANGUAGE"] = helpURLEncode(language); + + LLStringUtil::format(helpURL, substitution); + + return helpURL; +} diff --git a/indra/newview/llviewerhelputil.h b/indra/newview/llviewerhelputil.h new file mode 100644 index 0000000000..8ee0d96023 --- /dev/null +++ b/indra/newview/llviewerhelputil.h @@ -0,0 +1,49 @@ +/** + * @file llviewerhelputil.h + * @brief Utility functions for the Help system + * @author Soft Linden + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLVIEWERHELPUTIL_H +#define LL_LLVIEWERHELPUTIL_H + +class LLControlGroup; +class LLOSInfo; + +class LLViewerHelpUtil +{ + public: + static std::string helpURLEncode( const std::string &component ); + static std::string buildHelpURL( const std::string &topic, + LLControlGroup &savedSettings, + const LLOSInfo &osinfo); +}; + +#endif // header guard diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index f033d66c1f..100a34291b 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -35,12 +35,14 @@ #include "llviewermedia.h" #include "llviewermediafocus.h" #include "llmimetypes.h" +#include "llmediaentry.h" #include "llviewercontrol.h" #include "llviewertexture.h" #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "llversionviewer.h" #include "llviewertexturelist.h" +#include "llvovolume.h" #include "llpluginclassmedia.h" #include "llevent.h" // LLSimpleListener @@ -95,10 +97,10 @@ bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer ) /////////////////////////////////////////////////////////////////////////////// // -void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLPluginClassMediaOwner::EMediaEvent event ) +void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLViewerMediaObserver::EMediaEvent event ) { + // Broadcast the event to any observers. observerListType::iterator iter = mObservers.begin(); - while( iter != mObservers.end() ) { LLViewerMediaObserver *self = *iter; @@ -166,55 +168,127 @@ public: }; typedef std::vector<LLViewerMediaImpl*> impl_list; static impl_list sViewerMediaImplList; +static LLTimer sMediaCreateTimer; +static const F32 LLVIEWERMEDIA_CREATE_DELAY = 1.0f; + +////////////////////////////////////////////////////////////////////////////////////////// +static void add_media_impl(LLViewerMediaImpl* media) +{ + sViewerMediaImplList.push_back(media); +} + +////////////////////////////////////////////////////////////////////////////////////////// +static void remove_media_impl(LLViewerMediaImpl* media) +{ + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + if(media == *iter) + { + sViewerMediaImplList.erase(iter); + return; + } + } +} + ////////////////////////////////////////////////////////////////////////////////////////// // LLViewerMedia ////////////////////////////////////////////////////////////////////////////////////////// // static -viewer_media_t LLViewerMedia::newMediaImpl(const std::string& media_url, - const LLUUID& texture_id, - S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop, - std::string mime_type) +viewer_media_t LLViewerMedia::newMediaImpl( + const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop) { LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id); if(media_impl == NULL || texture_id.isNull()) { // Create the media impl - media_impl = new LLViewerMediaImpl(media_url, texture_id, media_width, media_height, media_auto_scale, media_loop, mime_type); - sViewerMediaImplList.push_back(media_impl); + media_impl = new LLViewerMediaImpl(texture_id, media_width, media_height, media_auto_scale, media_loop); } else { media_impl->stop(); media_impl->mTextureId = texture_id; - media_impl->mMediaURL = media_url; media_impl->mMediaWidth = media_width; media_impl->mMediaHeight = media_height; media_impl->mMediaAutoScale = media_auto_scale; media_impl->mMediaLoop = media_loop; - if(! media_url.empty()) - media_impl->navigateTo(media_url, mime_type, true); } + return media_impl; } -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::removeMedia(LLViewerMediaImpl* media) -{ - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); +viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self) +{ + // Try to find media with the same media ID + viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID()); + + bool was_loaded = false; + bool needs_navigate = false; - for(; iter != end; iter++) + if(media_impl) + { + was_loaded = media_impl->hasMedia(); + + media_impl->setHomeURL(media_entry->getHomeURL()); + + media_impl->mMediaAutoScale = media_entry->getAutoScale(); + media_impl->mMediaLoop = media_entry->getAutoLoop(); + media_impl->mMediaWidth = media_entry->getWidthPixels(); + media_impl->mMediaHeight = media_entry->getHeightPixels(); + if (media_impl->mMediaSource) + { + media_impl->mMediaSource->setAutoScale(media_impl->mMediaAutoScale); + media_impl->mMediaSource->setLoop(media_impl->mMediaLoop); + media_impl->mMediaSource->setSize(media_entry->getWidthPixels(), media_entry->getHeightPixels()); + } + + if((was_loaded || media_entry->getAutoPlay()) && !update_from_self) + { + if(!media_entry->getCurrentURL().empty()) + { + needs_navigate = (media_entry->getCurrentURL() != previous_url); + } + else if(!media_entry->getHomeURL().empty()) + { + needs_navigate = (media_entry->getHomeURL() != previous_url); + } + } + } + else { - if(media == *iter) + media_impl = newMediaImpl( + media_entry->getMediaID(), + media_entry->getWidthPixels(), + media_entry->getHeightPixels(), + media_entry->getAutoScale(), + media_entry->getAutoLoop()); + + media_impl->setHomeURL(media_entry->getHomeURL()); + + if(media_entry->getAutoPlay()) { - sViewerMediaImplList.erase(iter); - return; + needs_navigate = true; } } + + if(media_impl && needs_navigate) + { + std::string url = media_entry->getCurrentURL(); + if(url.empty()) + url = media_entry->getHomeURL(); + + media_impl->navigateTo(url, "", true, true); + } + + return media_impl; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -323,6 +397,36 @@ void LLViewerMedia::setVolume(F32 volume) } } +// This is the predicate function used to sort sViewerMediaImplList by priority. +static inline bool compare_impl_interest(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) +{ + if(i1->hasFocus()) + { + // The item with user focus always comes to the front of the list, period. + return true; + } + else if(i2->hasFocus()) + { + // The item with user focus always comes to the front of the list, period. + return false; + } + else if(i1->getUsedInUI() && !i2->getUsedInUI()) + { + // i1 is a UI element, i2 is not. This makes i1 "less than" i2, so it sorts earlier in our list. + return true; + } + else if(i2->getUsedInUI() && !i1->getUsedInUI()) + { + // i2 is a UI element, i1 is not. This makes i2 "less than" i1, so it sorts earlier in our list. + return false; + } + else + { + // The object with the larger interest value should be earlier in the list, so we reverse the sense of the comparison here. + return (i1->getInterest() > i2->getInterest()); + } +} + ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerMedia::updateMedia() @@ -334,32 +438,138 @@ void LLViewerMedia::updateMedia() { LLViewerMediaImpl* pimpl = *iter; pimpl->update(); + pimpl->calculateInterest(); } + + // Sort the static instance list using our interest criteria + std::stable_sort(sViewerMediaImplList.begin(), sViewerMediaImplList.end(), compare_impl_interest); + + // Go through the list again and adjust according to priority. + iter = sViewerMediaImplList.begin(); + end = sViewerMediaImplList.end(); + + F64 total_cpu = 0.0f; + int impl_count_total = 0; + int impl_count_interest_low = 0; + int impl_count_interest_normal = 0; + +#if 0 + LL_DEBUGS("PluginPriority") << "Sorted impls:" << llendl; +#endif + + U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal"); + U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal"); + U32 max_low = gSavedSettings.getU32("PluginInstancesLow"); + F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit"); + // Setting max_cpu to 0.0 disables CPU usage checking. + bool check_cpu_usage = (max_cpu != 0.0f); + + // Notes on tweakable params: + // max_instances must be set high enough to allow the various instances used in the UI (for the help browser, search, etc.) to be loaded. + // If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow. + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + + LLPluginClassMedia::EPriority new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + + if(impl_count_total > (int)max_instances) + { + // Hard limit on the number of instances that will be loaded at one time + new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; + } + else if(!pimpl->getVisible()) + { + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if(pimpl->hasFocus()) + { + new_priority = LLPluginClassMedia::PRIORITY_HIGH; + } + else if(pimpl->getUsedInUI()) + { + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + } + else + { + // Look at interest and CPU usage for instances that aren't in any of the above states. + + // Heuristic -- if the media texture's approximate screen area is less than 1/4 of the native area of the texture, + // turn it down to low instead of normal. This may downsample for plugins that support it. + bool media_is_small = pimpl->getInterest() < (pimpl->getApproximateTextureInterest() / 4); + + if(pimpl->getInterest() == 0.0f) + { + // This media is completely invisible, due to being outside the view frustrum or out of range. + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if(check_cpu_usage && (total_cpu > max_cpu)) + { + // Higher priority plugins have already used up the CPU budget. Set remaining ones to slideshow priority. + new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; + } + else if((impl_count_interest_normal < (int)max_normal) && !media_is_small) + { + // Up to max_normal inworld get normal priority + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } + else if (impl_count_interest_low + impl_count_interest_normal < (int)max_low + (int)max_normal) + { + // The next max_low inworld get turned down + new_priority = LLPluginClassMedia::PRIORITY_LOW; + impl_count_interest_low++; + + // Set the low priority size for downsampling to approximately the size the texture is displayed at. + { + F32 approximate_interest_dimension = fsqrtf(pimpl->getInterest()); + + pimpl->setLowPrioritySizeLimit(llround(approximate_interest_dimension)); + } + } + else + { + // Any additional impls (up to max_instances) get very infrequent time + new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; + } + } + + pimpl->setPriority(new_priority); + +#if 0 + LL_DEBUGS("PluginPriority") << " " << pimpl + << ", setting priority to " << new_priority + << (pimpl->hasFocus()?", HAS FOCUS":"") + << (pimpl->getUsedInUI()?", is UI":"") + << ", cpu " << pimpl->getCPUUsage() + << ", interest " << pimpl->getInterest() + << ", media url " << pimpl->getMediaURL() << llendl; +#endif + + total_cpu += pimpl->getCPUUsage(); + impl_count_total++; + } + + LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << llendl; + } ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerMedia::cleanupClass() { - // This is no longer necessary, since the list is no longer smart pointers. -#if 0 - while(!sViewerMediaImplList.empty()) - { - sViewerMediaImplList.pop_back(); - } -#endif + // This is no longer necessary, since sViewerMediaImplList is no longer smart pointers. } ////////////////////////////////////////////////////////////////////////////////////////// // LLViewerMediaImpl ////////////////////////////////////////////////////////////////////////////////////////// -LLViewerMediaImpl::LLViewerMediaImpl(const std::string& media_url, - const LLUUID& texture_id, +LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop, - const std::string& mime_type) + U8 media_loop) : mMediaSource( NULL ), mMovieImageHasMips(false), @@ -368,13 +578,30 @@ LLViewerMediaImpl::LLViewerMediaImpl(const std::string& media_url, mMediaHeight(media_height), mMediaAutoScale(media_auto_scale), mMediaLoop(media_loop), - mMediaURL(media_url), - mMimeType(mime_type), mNeedsNewTexture(true), mSuspendUpdates(false), - mVisible(true) + mVisible(true), + mLastSetCursor( UI_CURSOR_ARROW ), + mMediaNavState( MEDIANAVSTATE_NONE ), + mInterest(0.0f), + mUsedInUI(false), + mHasFocus(false), + mPriority(LLPluginClassMedia::PRIORITY_UNLOADED), + mDoNavigateOnLoad(false), + mDoNavigateOnLoadServerRequest(false), + mIsUpdated(false) { - createMediaSource(); + + add_media_impl(this); + + // connect this media_impl to the media texture, creating it if it doesn't exist.0 + // This is necessary because we need to be able to use getMaxVirtualSize() even if the media plugin is not loaded. + LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture(mTextureId); + if(media_tex) + { + media_tex->setMediaImpl(); + } + } ////////////////////////////////////////////////////////////////////////////////////////// @@ -386,7 +613,26 @@ LLViewerMediaImpl::~LLViewerMediaImpl() } destroyMediaSource(); - LLViewerMedia::removeMedia(this); + + LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId) ; + + remove_media_impl(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) +{ + // Broadcast to observers using the superclass version + LLViewerMediaEventEmitter::emitEvent(plugin, event); + + // If this media is on one or more LLVOVolume objects, tell them about the event as well. + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + while(iter != mObjectList.end()) + { + LLVOVolume *self = *iter; + ++iter; + self->mediaEvent(this, plugin, event); + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -396,11 +642,7 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) { if(! initializePlugin(mime_type)) { - LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << mime_type << LL_ENDL; - LLSD args; - args["MIME_TYPE"] = mime_type; - LLNotifications::instance().add("NoPlugin", args); - + // This may be the case where the plugin's priority is PRIORITY_UNLOADED return false; } } @@ -412,29 +654,42 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::createMediaSource() { - if(! mMediaURL.empty()) + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) { - navigateTo(mMediaURL, mMimeType, true); + // This media shouldn't be created yet. + return; } - else if(! mMimeType.empty()) + + if(mDoNavigateOnLoad) { - initializeMedia(mMimeType); + if(! mMediaURL.empty()) + { + navigateTo(mMediaURL, mMimeType, false, mDoNavigateOnLoadServerRequest); + } + else if(! mMimeType.empty()) + { + initializeMedia(mMimeType); + } } - } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::destroyMediaSource() { mNeedsNewTexture = true; - if(! mMediaSource) + + // Tell the viewer media texture it's no longer active + LLViewerMediaTexture* oldImage = LLViewerTextureManager::findMediaTexture( mTextureId ); + if (oldImage) { - return; + oldImage->setPlaying(FALSE) ; } - // Restore the texture - updateMovieImage(LLUUID::null, false); - delete mMediaSource; - mMediaSource = NULL; + + if(mMediaSource) + { + delete mMediaSource; + mMediaSource = NULL; + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -487,6 +742,11 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ } } + LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL; + LLSD args; + args["MIME_TYPE"] = media_type; + LLNotifications::instance().add("NoPlugin", args); + return NULL; } @@ -506,7 +766,15 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) // and unconditionally set the mime type mMimeType = media_type; - LLPluginClassMedia* media_source = newSourceFromMediaType(media_type, this, mMediaWidth, mMediaHeight); + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This impl should not be loaded at this time. + LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; + + return false; + } + + LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight); if (media_source) { @@ -543,13 +811,11 @@ void LLViewerMediaImpl::play() { if(!initializePlugin(mMimeType)) { - // Plugin failed initialization... should assert or something + // This may be the case where the plugin's priority is PRIORITY_UNLOADED return; } } - // updateMovieImage(mTextureId, true); - mMediaSource->loadURI( mMediaURL ); if(/*mMediaSource->pluginSupportsMediaTime()*/ true) { @@ -606,6 +872,8 @@ void LLViewerMediaImpl::setVolume(F32 volume) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::focus(bool focus) { + mHasFocus = focus; + if (mMediaSource) { // call focus just for the hell of it, even though this apopears to be a nop @@ -621,11 +889,19 @@ void LLViewerMediaImpl::focus(bool focus) } ////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::hasFocus() const +{ + // FIXME: This might be able to be a bit smarter by hooking into LLViewerMediaFocus, etc. + return mHasFocus; +} + +////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseDown(S32 x, S32 y) { scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; +// llinfos << "mouse down (" << x << ", " << y << ")" << llendl; if (mMediaSource) { mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, x, y, 0); @@ -638,6 +914,7 @@ void LLViewerMediaImpl::mouseUp(S32 x, S32 y) scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; +// llinfos << "mouse up (" << x << ", " << y << ")" << llendl; if (mMediaSource) { mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, x, y, 0); @@ -647,9 +924,10 @@ void LLViewerMediaImpl::mouseUp(S32 x, S32 y) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseMove(S32 x, S32 y) { - scaleMouse(&x, &y); + scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; +// llinfos << "mouse move (" << x << ", " << y << ")" << llendl; if (mMediaSource) { mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, x, y, 0); @@ -657,6 +935,37 @@ void LLViewerMediaImpl::mouseMove(S32 x, S32 y) } ////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords) +{ + if(mMediaSource) + { + mouseDown( + llround(texture_coords.mV[VX] * mMediaSource->getTextureWidth()), + llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight())); + } +} + +void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords) +{ + if(mMediaSource) + { + mouseUp( + llround(texture_coords.mV[VX] * mMediaSource->getTextureWidth()), + llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight())); + } +} + +void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords) +{ + if(mMediaSource) + { + mouseMove( + llround(texture_coords.mV[VX] * mMediaSource->getTextureWidth()), + llround((1.0f - texture_coords.mV[VY]) * mMediaSource->getTextureHeight())); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseLeftDoubleClick(S32 x, S32 y) { scaleMouse(&x, &y); @@ -694,6 +1003,10 @@ BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateHome() { + mMediaURL = mHomeURL; + mDoNavigateOnLoad = !mMediaURL.empty(); + mDoNavigateOnLoadServerRequest = false; + if(mMediaSource) { mMediaSource->loadURI( mHomeURL ); @@ -701,17 +1014,43 @@ void LLViewerMediaImpl::navigateHome() } ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type) +void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request) { + if(server_request) + { + setNavState(MEDIANAVSTATE_SERVER_SENT); + } + else + { + setNavState(MEDIANAVSTATE_NONE); + } + + // Always set the current URL. + mMediaURL = url; + + // If the current URL is not null, make the instance do a navigate on load. + mDoNavigateOnLoad = !mMediaURL.empty(); + + // and if this was a server request, the navigate on load will also need to be one. + mDoNavigateOnLoadServerRequest = server_request; + + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This impl should not be loaded at this time. + LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; + + return; + } + if(rediscover_type) { - LLURI uri(url); + LLURI uri(mMediaURL); std::string scheme = uri.scheme(); if(scheme.empty() || "http" == scheme || "https" == scheme) { - LLHTTPClient::getHeaderOnly( url, new LLMimeDiscoveryResponder(this)); + LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this)); } else if("data" == scheme || "file" == scheme || "about" == scheme) { @@ -719,7 +1058,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi // We use "data" internally for a text/html url for loading the login screen if(initializeMedia("text/html")) { - mMediaSource->loadURI( url ); + mMediaSource->loadURI( mMediaURL ); } } else @@ -727,24 +1066,23 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi // This catches 'rtsp://' urls if(initializeMedia(scheme)) { - mMediaSource->loadURI( url ); + mMediaSource->loadURI( mMediaURL ); } } } else if (mMediaSource) { - mMediaSource->loadURI( url ); + mMediaSource->loadURI( mMediaURL ); } else if(initializeMedia(mime_type) && mMediaSource) { - mMediaSource->loadURI( url ); + mMediaSource->loadURI( mMediaURL ); } else { LL_WARNS("Media") << "Couldn't navigate to: " << url << " as there is no media type for: " << mime_type << LL_ENDL; return; } - mMediaURL = url; } @@ -806,49 +1144,27 @@ bool LLViewerMediaImpl::canNavigateBack() return result; } - ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::updateMovieImage(const LLUUID& uuid, BOOL active) +void LLViewerMediaImpl::update() { - // IF the media image hasn't changed, do nothing - if (mTextureId == uuid) - { - return; - } - // If we have changed media uuid, restore the old one - if (!mTextureId.isNull()) + if(mMediaSource == NULL) { - LLViewerMediaTexture* old_image = LLViewerTextureManager::findMediaTexture( mTextureId ); - if (old_image) + if(mPriority != LLPluginClassMedia::PRIORITY_UNLOADED) { - old_image->setPlaying(FALSE); - LLViewerTexture* original_texture = old_image->getOldTexture(); - if(original_texture) + // This media may need to be loaded. + if(sMediaCreateTimer.hasExpired()) { - old_image->switchToTexture(original_texture); + LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL; + createMediaSource(); + sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY); + } + else + { + LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL; } } } - // If the movie is playing, set the new media image - if (active && !uuid.isNull()) - { - LLViewerMediaTexture* viewerImage = LLViewerTextureManager::findMediaTexture( uuid ); - if( viewerImage ) - { - mTextureId = uuid; - - // Can't use mipmaps for movies because they don't update the full image - mMovieImageHasMips = viewerImage->getUseMipMaps(); - viewerImage->reinit(FALSE); - // FIXME -// viewerImage->mIsMediaTexture = TRUE; - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::update() -{ + if(mMediaSource == NULL) { return; @@ -877,6 +1193,10 @@ void LLViewerMediaImpl::update() if(placeholder_image) { LLRect dirty_rect; + + // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered. + placeholder_image->setPlaying(TRUE); + if(mMediaSource->getDirty(&dirty_rect)) { // Constrain the dirty rect to be inside the texture @@ -930,12 +1250,11 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() if (mNeedsNewTexture || placeholder_image->getUseMipMaps() -// || ! placeholder_image->getType() == LLViewerTexture::MEDIA_TEXTURE || placeholder_image->getWidth() != mMediaSource->getTextureWidth() || placeholder_image->getHeight() != mMediaSource->getTextureHeight()) { - llinfos << "initializing media placeholder" << llendl; - llinfos << "movie image id " << mTextureId << llendl; + LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; + LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; int texture_width = mMediaSource->getTextureWidth(); int texture_height = mMediaSource->getTextureHeight(); @@ -960,9 +1279,6 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() placeholder_image->createGLTexture(discard_level, raw); - // placeholder_image->setExplicitFormat() - placeholder_image->setUseMipMaps(FALSE); - // MEDIAOPT: set this dynamically on play/stop // FIXME // placeholder_image->mIsMediaTexture = true; @@ -996,11 +1312,6 @@ void LLViewerMediaImpl::setVisible(bool visible) createMediaSource(); } } - - if(mMediaSource) - { - mMediaSource->setPriority(mVisible?LLPluginClassMedia::PRIORITY_NORMAL:LLPluginClassMedia::PRIORITY_HIDDEN); - } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1059,7 +1370,7 @@ bool LLViewerMediaImpl::hasMedia() } ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event) +void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent event) { switch(event) { @@ -1070,11 +1381,77 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* self, LLPluginClass LLNotifications::instance().add("MediaPluginFailed", args); } break; + + case MEDIA_EVENT_CURSOR_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << plugin->getCursorName() << LL_ENDL; + + std::string cursor = plugin->getCursorName(); + + if(cursor == "arrow") + mLastSetCursor = UI_CURSOR_ARROW; + else if(cursor == "ibeam") + mLastSetCursor = UI_CURSOR_IBEAM; + else if(cursor == "splith") + mLastSetCursor = UI_CURSOR_SIZEWE; + else if(cursor == "splitv") + mLastSetCursor = UI_CURSOR_SIZENS; + else if(cursor == "hand") + mLastSetCursor = UI_CURSOR_HAND; + else // for anything else, default to the arrow + mLastSetCursor = UI_CURSOR_ARROW; + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL; + + if(getNavState() == MEDIANAVSTATE_SERVER_SENT) + { + setNavState(MEDIANAVSTATE_SERVER_BEGUN); + } + else + { + setNavState(MEDIANAVSTATE_BEGUN); + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL; + setNavState(MEDIANAVSTATE_NONE); + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_LOCATION_CHANGED, uri is: " << plugin->getLocation() << LL_ENDL; + + if(getNavState() == MEDIANAVSTATE_BEGUN) + { + setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED); + } + else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) + { + setNavState(MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED); + } + else + { + // Don't track redirects. + setNavState(MEDIANAVSTATE_NONE); + } + } + break; + + default: break; } + // Just chain the event to observers. - emitEvent(self, event); + emitEvent(plugin, event); } //////////////////////////////////////////////////////////////////////////////// @@ -1137,6 +1514,146 @@ LLViewerMediaImpl::canPaste() const return FALSE; } +void LLViewerMediaImpl::setUpdated(BOOL updated) +{ + mIsUpdated = updated ; +} + +BOOL LLViewerMediaImpl::isUpdated() +{ + return mIsUpdated ; +} + +void LLViewerMediaImpl::calculateInterest() +{ + LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId ); + + if(texture != NULL) + { + mInterest = texture->getMaxVirtualSize(); + } + else + { + // I don't think this case should ever be hit. + LL_WARNS("Plugin") << "no texture!" << LL_ENDL; + mInterest = 0.0f; + } +} + +F64 LLViewerMediaImpl::getApproximateTextureInterest() +{ + F64 result = 0.0f; + + if(mMediaSource) + { + result = mMediaSource->getFullWidth(); + result *= mMediaSource->getFullHeight(); + } + + return result; +} + +void LLViewerMediaImpl::setUsedInUI(bool used_in_ui) +{ + mUsedInUI = used_in_ui; + + // HACK: Force elements used in UI to load right away. + // This fixes some issues where UI code that uses the browser instance doesn't expect it to be unloaded. + if(mUsedInUI && (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)) + { + if(getVisible()) + { + mPriority = LLPluginClassMedia::PRIORITY_NORMAL; + } + else + { + mPriority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + + createMediaSource(); + } +}; + +F64 LLViewerMediaImpl::getCPUUsage() const +{ + F64 result = 0.0f; + + if(mMediaSource) + { + result = mMediaSource->getCPUUsage(); + } + + return result; +} + +void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority) +{ + mPriority = priority; + + if(priority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + if(mMediaSource) + { + // Need to unload the media source + destroyMediaSource(); + } + } + + if(mMediaSource) + { + mMediaSource->setPriority(mPriority); + } + + // NOTE: loading (or reloading) media sources whose priority has risen above PRIORITY_UNLOADED is done in update(). +} + +void LLViewerMediaImpl::setLowPrioritySizeLimit(int size) +{ + if(mMediaSource) + { + mMediaSource->setLowPrioritySizeLimit(size); + } +} + +void LLViewerMediaImpl::setNavState(EMediaNavState state) +{ + mMediaNavState = state; + + switch (state) + { + case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << llendl; break; + case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << llendl; break; + case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << llendl; break; + case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << llendl; break; + case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << llendl; break; + } +} + + +void LLViewerMediaImpl::addObject(LLVOVolume* obj) +{ + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + for(; iter != mObjectList.end() ; ++iter) + { + if(*iter == obj) + { + return ; //already in the list. + } + } + + mObjectList.push_back(obj) ; +} + +void LLViewerMediaImpl::removeObject(LLVOVolume* obj) +{ + mObjectList.remove(obj) ; +} + +const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const +{ + return &mObjectList ; +} ////////////////////////////////////////////////////////////////////////////////////////// //static diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 9a61394383..775f72d56f 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -41,9 +41,13 @@ #include "llviewermediaobserver.h" +#include "llpluginclassmedia.h" + class LLViewerMediaImpl; class LLUUID; class LLViewerMediaTexture; +class LLMediaEntry; +class LLVOVolume ; typedef LLPointer<LLViewerMediaImpl> viewer_media_t; /////////////////////////////////////////////////////////////////////////////// @@ -55,7 +59,7 @@ public: bool addObserver( LLViewerMediaObserver* subject ); bool remObserver( LLViewerMediaObserver* subject ); - void emitEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event); + virtual void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event); private: typedef std::list< LLViewerMediaObserver* > observerListType; @@ -69,15 +73,13 @@ class LLViewerMedia // Special case early init for just web browser component // so we can show login screen. See .cpp file for details. JC - static viewer_media_t newMediaImpl(const std::string& media_url, - const LLUUID& texture_id, - S32 media_width, - S32 media_height, - U8 media_auto_scale, - U8 media_loop, - std::string mime_type = "none/none"); + static viewer_media_t newMediaImpl(const LLUUID& texture_id, + S32 media_width = 0, + S32 media_height = 0, + U8 media_auto_scale = false, + U8 media_loop = false); - static void removeMedia(LLViewerMediaImpl* media); + static viewer_media_t updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self); static LLViewerMediaImpl* getMediaImplFromTextureID(const LLUUID& texture_id); static std::string getCurrentUserAgent(); static void updateBrowserUserAgent(); @@ -102,15 +104,18 @@ class LLViewerMediaImpl LOG_CLASS(LLViewerMediaImpl); public: - LLViewerMediaImpl(const std::string& media_url, + LLViewerMediaImpl( const LLUUID& texture_id, S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop, - const std::string& mime_type); + U8 media_loop); ~LLViewerMediaImpl(); + + // Override inherited version from LLViewerMediaEventEmitter + virtual void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event); + void createMediaSource(); void destroyMediaSource(); void setMediaType(const std::string& media_type); @@ -126,36 +131,44 @@ public: void seek(F32 time); void setVolume(F32 volume); void focus(bool focus); + // True if the impl has user focus. + bool hasFocus() const; void mouseDown(S32 x, S32 y); void mouseUp(S32 x, S32 y); void mouseMove(S32 x, S32 y); + void mouseDown(const LLVector2& texture_coords); + void mouseUp(const LLVector2& texture_coords); + void mouseMove(const LLVector2& texture_coords); void mouseLeftDoubleClick(S32 x,S32 y ); void mouseCapture(); void navigateHome(); - void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false); + void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false); void navigateStop(); bool handleKeyHere(KEY key, MASK mask); bool handleUnicodeCharHere(llwchar uni_char); bool canNavigateForward(); bool canNavigateBack(); std::string getMediaURL() { return mMediaURL; } - std::string getMediaHomeURL() { return mHomeURL; } + std::string getHomeURL() { return mHomeURL; } + void setHomeURL(const std::string& home_url) { mHomeURL = home_url; }; std::string getMimeType() { return mMimeType; } void scaleMouse(S32 *mouse_x, S32 *mouse_y); void update(); - void updateMovieImage(const LLUUID& image_id, BOOL active); void updateImagesMediaStreams(); LLUUID getMediaTextureID(); void suspendUpdates(bool suspend) { mSuspendUpdates = suspend; }; void setVisible(bool visible); + bool getVisible() const { return mVisible; }; bool isMediaPlaying(); bool isMediaPaused(); bool hasMedia(); + ECursorType getLastSetCursor() { return mLastSetCursor; }; + // utility function to create a ready-to-use media instance from a desired media type. static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height); @@ -191,7 +204,7 @@ public: /*virtual*/ BOOL hasMouseCapture() { return gFocusMgr.getMouseCapture() == this; }; // Inherited from LLPluginClassMediaOwner - /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent); + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent); // LLEditMenuHandler overrides /*virtual*/ void cut(); @@ -203,6 +216,45 @@ public: /*virtual*/ void paste(); /*virtual*/ BOOL canPaste() const; + void addObject(LLVOVolume* obj) ; + void removeObject(LLVOVolume* obj) ; + const std::list< LLVOVolume* >* getObjectList() const ; + void setUpdated(BOOL updated) ; + BOOL isUpdated() ; + + // Updates the "interest" value in this object + void calculateInterest(); + F64 getInterest() const { return mInterest; }; + F64 getApproximateTextureInterest(); + + // Mark this object as being used in a UI panel instead of on a prim + // This will be used as part of the interest sorting algorithm. + void setUsedInUI(bool used_in_ui); + bool getUsedInUI() const { return mUsedInUI; }; + + F64 getCPUUsage() const; + + void setPriority(LLPluginClassMedia::EPriority priority); + LLPluginClassMedia::EPriority getPriority() { return mPriority; }; + + void setLowPrioritySizeLimit(int size); + + typedef enum + { + MEDIANAVSTATE_NONE, // State is outside what we need to track for navigation. + MEDIANAVSTATE_BEGUN, // a MEDIA_EVENT_NAVIGATE_BEGIN has been received which was not server-directed + MEDIANAVSTATE_FIRST_LOCATION_CHANGED, // first LOCATION_CHANGED event after a non-server-directed BEGIN + MEDIANAVSTATE_SERVER_SENT, // server-directed nav has been requested, but MEDIA_EVENT_NAVIGATE_BEGIN hasn't been received yet + MEDIANAVSTATE_SERVER_BEGUN, // MEDIA_EVENT_NAVIGATE_BEGIN has been received which was server-directed + MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED // first LOCATION_CHANGED event after a server-directed BEGIN + + }EMediaNavState; + + // Returns the current nav state of the media. + // note that this will be updated BEFORE listeners and objects receive media messages + EMediaNavState getNavState() { return mMediaNavState; } + void setNavState(EMediaNavState state); + public: // a single media url with some data and an impl. LLPluginClassMedia* mMediaSource; @@ -220,7 +272,19 @@ public: bool mNeedsNewTexture; bool mSuspendUpdates; bool mVisible; + ECursorType mLastSetCursor; + EMediaNavState mMediaNavState; + F64 mInterest; + bool mUsedInUI; + bool mHasFocus; + LLPluginClassMedia::EPriority mPriority; + bool mDoNavigateOnLoad; + bool mDoNavigateOnLoadServerRequest; + +private: + BOOL mIsUpdated ; + std::list< LLVOVolume* > mObjectList ; private: LLViewerMediaTexture *updatePlaceholderImage(); diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index e7576d5c76..f9377ab37b 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -47,6 +47,7 @@ #include "llparcel.h" #include "llviewerparcelmgr.h" #include "llweb.h" +#include "llmediaentry.h" // // LLViewerMediaFocus // @@ -91,14 +92,38 @@ void LLViewerMediaFocus::cleanupClass() void LLViewerMediaFocus::setFocusFace( BOOL b, LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl ) { LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + + if(mMediaImpl.notNull()) + { + mMediaImpl->focus(false); + } + if (b && media_impl.notNull()) { + bool face_auto_zoom = false; mMediaImpl = media_impl; + mMediaImpl->focus(true); + LLSelectMgr::getInstance()->deselectAll(); LLSelectMgr::getInstance()->selectObjectOnly(objectp, face); + if(objectp.notNull()) + { + LLTextureEntry* tep = objectp->getTE(face); + if(! tep->hasMedia()) + { + // Error condition + } + LLMediaEntry* mep = tep->getMediaData(); + face_auto_zoom = mep->getAutoZoom(); + if(! mep->getAutoPlay()) + { + std::string url = mep->getCurrentURL().empty() ? mep->getHomeURL() : mep->getCurrentURL(); + media_impl->navigateTo(url, "", true); + } + } mFocus = LLSelectMgr::getInstance()->getSelection(); - if(mMediaHUD.get() && ! parcel->getMediaPreventCameraZoom()) + if(mMediaHUD.get() && face_auto_zoom && ! parcel->getMediaPreventCameraZoom()) { mMediaHUD.get()->resetZoomLevel(); mMediaHUD.get()->nextZoomLevel(); @@ -108,6 +133,7 @@ void LLViewerMediaFocus::setFocusFace( BOOL b, LLPointer<LLViewerObject> objectp gFocusMgr.setKeyboardFocus(this); } mObjectID = objectp->getID(); + mObjectFace = face; // LLViewerMedia::addObserver(this, mObjectID); @@ -133,6 +159,8 @@ void LLViewerMediaFocus::setFocusFace( BOOL b, LLPointer<LLViewerObject> objectp // and null out the media impl mMediaImpl = NULL; + mObjectID = LLUUID::null; + mObjectFace = 0; } if(mMediaHUD.get()) { @@ -230,6 +258,12 @@ void LLViewerMediaFocus::setMouseOverFlag(bool b, viewer_media_t media_impl) gHUDView->addChild(media_hud); } mMediaHUD.get()->setMediaImpl(media_impl); + + if(mMediaImpl.notNull() && (mMediaImpl != media_impl)) + { + mMediaImpl->focus(false); + } + mMediaImpl = media_impl; } mMouseOverFlag = b; @@ -356,3 +390,8 @@ F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& // Return the aspect ratio. return *width / *height; } + +bool LLViewerMediaFocus::isFocusedOnFace(LLPointer<LLViewerObject> objectp, S32 face) +{ + return objectp->getID() == mObjectID && face == mObjectFace; +} diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h index a078d24b6a..2688a8b708 100644 --- a/indra/newview/llviewermediafocus.h +++ b/indra/newview/llviewermediafocus.h @@ -72,6 +72,9 @@ public: void setPickInfo(LLPickInfo pick_info) { mPickInfo = pick_info; } F32 getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth); + // TODO: figure out why selection mgr hates me + bool isFocusedOnFace(LLPointer<LLViewerObject> objectp, S32 face); + protected: /*virtual*/ void onFocusReceived(); /*virtual*/ void onFocusLost(); @@ -83,6 +86,7 @@ private: LLPickInfo mPickInfo; LLHandle<LLPanelMediaHUD> mMediaHUD; LLUUID mObjectID; + S32 mObjectFace; viewer_media_t mMediaImpl; }; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index a0bd5f301b..12253455a3 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -103,9 +103,6 @@ #include "llfloatergodtools.h" #include "llfloatergroupinvite.h" #include "llfloatergroups.h" -#include "llfloaterhtmlcurrency.h" -#include "llfloatermediabrowser.h" // gViewerHtmlHelp -#include "llfloaterhtmlsimple.h" #include "llfloaterhud.h" #include "llfloaterinspect.h" #include "llfloaterlagmeter.h" @@ -182,6 +179,7 @@ #include "lluuid.h" #include "llviewercamera.h" #include "llviewergenericmessage.h" +#include "llviewerhelp.h" #include "llviewertexturelist.h" // gTextureList #include "llviewerinventory.h" #include "llviewermenufile.h" // init_menu_file() @@ -375,7 +373,6 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt void dump_select_mgr(void*); void dump_inventory(void*); -void edit_ui(void*); void toggle_visibility(void*); BOOL get_visibility(void*); @@ -1247,21 +1244,6 @@ class LLAdvancedBuyCurrencyTest : public view_listener_t }; -//////////////////////// -// TOGGLE EDITABLE UI // -//////////////////////// - - -class LLAdvancedToggleEditableUI : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - edit_ui(NULL); - return true; - } -}; - - ///////////////////// // DUMP SELECT MGR // ///////////////////// @@ -5587,11 +5569,6 @@ class LLObjectEnableSitOrStand : public view_listener_t } }; -void edit_ui(void*) -{ - LLFloater::setEditModeEnabled(!LLFloater::getEditModeEnabled()); -} - void dump_select_mgr(void*) { LLSelectMgr::getInstance()->dump(); @@ -5649,8 +5626,8 @@ class LLShowFloater : public view_listener_t } else if (floater_name == "help f1") { - llinfos << "Spawning HTML help window" << llendl; - gViewerHtmlHelp.show(); + LLViewerHelp* vhelp = LLViewerHelp::getInstance(); + vhelp->showTopic(vhelp->getTopicFromFocus()); } else if (floater_name == "complaint reporter") { @@ -7689,6 +7666,19 @@ class LLHelpShowFirstTimeTip : public view_listener_t } }; +void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y) +{ + static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml", + gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if(gMenuHolder->hasVisibleMenu()) + { + gMenuHolder->hideMenus(); + } + show_navbar_context_menu->buildDrawLabels(); + show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y); +} + void initialize_menus() { // A parameterized event handler used as ctrl-8/9/0 zoom controls below. @@ -7886,7 +7876,6 @@ void initialize_menus() // Advanced > UI view_listener_t::addMenu(new LLAdvancedWebBrowserTest(), "Advanced.WebBrowserTest"); view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); - view_listener_t::addMenu(new LLAdvancedToggleEditableUI(), "Advanced.ToggleEditableUI"); view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); view_listener_t::addMenu(new LLAdvancedDumpFocusHolder(), "Advanced.DumpFocusHolder"); diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index cf482266d6..dd6aac2dd3 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -52,6 +52,7 @@ void show_debug_menus(); // checks for if menus should be shown first. void toggle_debug_menus(void*); void show_context_menu( S32 x, S32 y, MASK mask ); void show_build_mode_context_menu(S32 x, S32 y, MASK mask); +void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y); BOOL enable_save_into_inventory(void*); void handle_reset_view(); void handle_cut(void*); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index d3d5f060e1..05011a1568 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -47,6 +47,7 @@ #include "llframetimer.h" #include "llinventory.h" #include "llmaterialtable.h" +#include "llmediadataresponder.h" #include "llmutelist.h" #include "llnamevalue.h" #include "llprimitive.h" @@ -100,6 +101,8 @@ #include "llvowlsky.h" #include "llmanip.h" #include "lltrans.h" +#include "llsdutil.h" +#include "llmediaentry.h" //#define DEBUG_UPDATE_TYPE @@ -470,6 +473,7 @@ void LLViewerObject::cleanupVOClasses() LLVOWater::cleanupClass(); LLVOTree::cleanupClass(); LLVOAvatar::cleanupClass(); + LLVOVolume::cleanupClass(); } // Replaces all name value pairs with data from \n delimited list @@ -700,6 +704,42 @@ void LLViewerObject::hideExtraDisplayItems( BOOL hidden ) } } +U32 LLViewerObject::checkMediaURL(const std::string &media_url) +{ + U32 retval = (U32)0x0; + if (!mMedia && !media_url.empty()) + { + retval |= MEDIA_URL_ADDED; + mMedia = new LLViewerObjectMedia; + mMedia->mMediaURL = media_url; + mMedia->mMediaType = LLViewerObject::MEDIA_SET; + mMedia->mPassedWhitelist = FALSE; + } + else if (mMedia) + { + if (media_url.empty()) + { + retval |= MEDIA_URL_REMOVED; + delete mMedia; + mMedia = NULL; + } + else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test. + { + /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() && + LLTextureEntry::getVersionFromMediaVersionString(media_url) == + LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1)) + */ + { + // If the media URL is different and WE were not the one who + // changed it, mark dirty. + retval |= MEDIA_URL_UPDATED; + } + mMedia->mMediaURL = media_url; + mMedia->mPassedWhitelist = FALSE; + } + } + return retval; +} U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, void **user_data, @@ -1045,35 +1085,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, std::string media_url; mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL, media_url, block_num); - //if (!media_url.empty()) - //{ - // llinfos << "WEBONPRIM media_url " << media_url << llendl; - //} - if (!mMedia && !media_url.empty()) - { - retval |= MEDIA_URL_ADDED; - mMedia = new LLViewerObjectMedia; - mMedia->mMediaURL = media_url; - mMedia->mMediaType = LLViewerObject::MEDIA_TYPE_WEB_PAGE; - mMedia->mPassedWhitelist = FALSE; - } - else if (mMedia) - { - if (media_url.empty()) - { - retval |= MEDIA_URL_REMOVED; - delete mMedia; - mMedia = NULL; - } - else if (mMedia->mMediaURL != media_url) - { - // We just added or changed a web page. - retval |= MEDIA_URL_UPDATED; - mMedia->mMediaURL = media_url; - mMedia->mPassedWhitelist = FALSE; - } - } - + retval |= checkMediaURL(media_url); + // // Unpack particle system data // @@ -1456,31 +1469,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mText = NULL; } + std::string media_url; if (value & 0x200) { - std::string media_url; dp->unpackString(media_url, "MediaURL"); - if (!mMedia) - { - retval |= MEDIA_URL_ADDED; - mMedia = new LLViewerObjectMedia; - mMedia->mMediaURL = media_url; - mMedia->mMediaType = LLViewerObject::MEDIA_TYPE_WEB_PAGE; - mMedia->mPassedWhitelist = FALSE; - } - else if (mMedia->mMediaURL != media_url) - { - retval |= MEDIA_URL_UPDATED; - mMedia->mMediaURL = media_url; - mMedia->mPassedWhitelist = FALSE; - } - } - else if (mMedia) - { - retval |= MEDIA_URL_REMOVED; - delete mMedia; - mMedia = NULL; } + retval |= checkMediaURL(media_url); // // Unpack particle system data @@ -3472,7 +3466,7 @@ U8 LLViewerObject::getMediaType() const } else { - return LLViewerObject::MEDIA_TYPE_NONE; + return LLViewerObject::MEDIA_NONE; } } @@ -3734,16 +3728,13 @@ S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, LLHost hos } -void LLViewerObject::changeTEImage(const LLViewerTexture* old_image, LLViewerTexture* new_image) +void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) { - U32 end = getNumTEs() ; - for (U32 face = 0 ; face < end ; face++) + if(index < 0 || index >= getNumTEs()) { - if(old_image == mTEImages[face]) - { - mTEImages[face] = new_image ; - } + return ; } + mTEImages[index] = new_image ; } S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid) diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 08e2ec47cd..bec36f9da7 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -158,10 +158,16 @@ public: virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); // Types of media we can associate - enum { MEDIA_TYPE_NONE = 0, MEDIA_TYPE_WEB_PAGE = 1 }; + enum { MEDIA_NONE = 0, MEDIA_SET = 1 }; // Return codes for processUpdateMessage - enum { MEDIA_URL_REMOVED = 0x1, MEDIA_URL_ADDED = 0x2, MEDIA_URL_UPDATED = 0x4, INVALID_UPDATE = 0x80000000 }; + enum { + MEDIA_URL_REMOVED = 0x1, + MEDIA_URL_ADDED = 0x2, + MEDIA_URL_UPDATED = 0x4, + MEDIA_FLAGS_CHANGED = 0x8, + INVALID_UPDATE = 0x80000000 + }; virtual U32 processUpdateMessage(LLMessageSystem *mesgsys, void **user_data, @@ -318,7 +324,7 @@ public: /*virtual*/ S32 setTEGlow(const U8 te, const F32 glow); /*virtual*/ BOOL setMaterial(const U8 material); virtual void setTEImage(const U8 te, LLViewerTexture *imagep); // Not derived from LLPrimitive - void changeTEImage(const LLViewerTexture* old_image, LLViewerTexture* new_image) ; + void changeTEImage(S32 index, LLViewerTexture* new_image) ; LLViewerTexture *getTEImage(const U8 te) const; void fitFaceTexture(const U8 face); @@ -504,6 +510,10 @@ private: ExtraParameter* getExtraParameterEntry(U16 param_type) const; ExtraParameter* getExtraParameterEntryCreate(U16 param_type); bool unpackParameterEntry(U16 param_type, LLDataPacker *dp); + + // This function checks to see if the given media URL has changed its version + // and the update wasn't due to this agent's last action. + U32 checkMediaURL(const std::string &media_url); public: // diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 86d51bfd4b..a3f9c839a0 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -46,6 +46,7 @@ #include "llnotifications.h" #include "llfirstuse.h" #include "llpluginclassmedia.h" +#include "llviewertexture.h" // Static Variables @@ -219,17 +220,25 @@ void LLViewerParcelMedia::play(LLParcel* parcel) // Delete the old one first so they don't fight over the texture. sMediaImpl->stop(); - sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, - media_width, media_height, media_auto_scale, + sMediaImpl = LLViewerMedia::newMediaImpl( + placeholder_texture_id, + media_width, + media_height, + media_auto_scale, media_loop); + sMediaImpl->navigateTo(media_url); } } else { // There is no media impl, make a new one - sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, - media_width, media_height, media_auto_scale, + sMediaImpl = LLViewerMedia::newMediaImpl( + placeholder_texture_id, + media_width, + media_height, + media_auto_scale, media_loop); + sMediaImpl->navigateTo(media_url); } LLFirstUse::useMedia(); diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index c5b09403cb..7ca11d8364 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -50,7 +50,6 @@ #include "llfirstuse.h" #include "llfloaterbuyland.h" #include "llfloatergroups.h" -//#include "llfloaterhtml.h" #include "llfloatersellland.h" #include "llfloatertools.h" #include "llnotify.h" diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 2c68a106c3..7ea55b49e8 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1428,6 +1428,8 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("EventQueueGet"); capabilityNames.append("FetchInventory"); capabilityNames.append("WebFetchInventoryDescendents"); + capabilityNames.append("ObjectMedia"); + capabilityNames.append("ObjectMediaNavigate"); capabilityNames.append("FetchLib"); capabilityNames.append("FetchLibDescendents"); capabilityNames.append("GroupProposalBallot"); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index e3d657068f..a2f6b70006 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -62,6 +62,10 @@ #include "llappviewer.h" #include "lltextureatlas.h" #include "lltextureatlasmanager.h" +#include "lltextureentry.h" +#include "llmediaentry.h" +#include "llvovolume.h" +#include "llviewermedia.h" /////////////////////////////////////////////////////////////////////////////// // statics @@ -114,45 +118,18 @@ LLViewerTexture* LLViewerTextureManager::findTexture(const LLUUID& id) LLViewerMediaTexture* LLViewerTextureManager::findMediaTexture(const LLUUID &media_id) { - LLViewerMediaTexture::media_map_t::iterator iter = LLViewerMediaTexture::sMediaMap.find(media_id); - if(iter == LLViewerMediaTexture::sMediaMap.end()) - return NULL; - - ((LLViewerMediaTexture*)(iter->second))->getLastReferencedTimer()->reset() ; - return iter->second; + return LLViewerMediaTexture::findMediaTexture(media_id) ; } LLViewerMediaTexture* LLViewerTextureManager::getMediaTexture(const LLUUID& id, BOOL usemipmaps, LLImageGL* gl_image) { - LLViewerMediaTexture* tex = LLViewerTextureManager::findMediaTexture(id) ; + LLViewerMediaTexture* tex = LLViewerMediaTexture::findMediaTexture(id) ; if(!tex) { tex = LLViewerTextureManager::createMediaTexture(id, usemipmaps, gl_image) ; } - LLViewerTexture* old_tex = tex->getOldTexture() ; - if(!old_tex) - { - //if there is a fetched texture with the same id, replace it by this media texture - old_tex = gTextureList.findImage(id) ; - if(old_tex) - { - tex->setOldTexture(old_tex) ; - } - } - - if (gSavedSettings.getBOOL("ParcelMediaAutoPlayEnable") && gSavedSettings.getBOOL("AudioStreamingVideo")) - { - if(!tex->isPlaying()) - { - if(old_tex) - { - old_tex->switchToTexture(tex) ; - } - tex->setPlaying(TRUE) ; - } - } - tex->getLastReferencedTimer()->reset() ; + tex->initVirtualSize() ; return tex ; } @@ -303,7 +280,7 @@ void LLViewerTextureManager::cleanup() LLViewerFetchedTexture::sMissingAssetImagep = NULL; LLViewerFetchedTexture::sWhiteImagep = NULL; - LLViewerMediaTexture::sMediaMap.clear() ; + LLViewerMediaTexture::cleanup() ; } //---------------------------------------------------------------------------------------------- @@ -437,6 +414,7 @@ void LLViewerTexture::init(bool firstinit) mTextureState = NO_DELETE ; mDontDiscard = FALSE; mMaxVirtualSize = 0.f; + mNeedsResetMaxVirtualSize = FALSE ; } //virtual @@ -538,33 +516,24 @@ void LLViewerTexture::resetTextureStats(BOOL zero) } } +//virtual +F32 LLViewerTexture::getMaxVirtualSize() +{ + return mMaxVirtualSize ; +} + +//virtual void LLViewerTexture::addFace(LLFace* facep) { mFaceList.push_back(facep) ; } + +//virtual void LLViewerTexture::removeFace(LLFace* facep) { mFaceList.remove(facep) ; } -void LLViewerTexture::switchToTexture(LLViewerTexture* new_texture) -{ - if(this == new_texture) - { - return ; - } - - new_texture->addTextureStats(getMaxVirtualSize()) ; - - for(ll_face_list_t::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ) - { - LLFace* facep = *iter++ ; - facep->setTexture(new_texture) ; - facep->getViewerObject()->changeTEImage(this, new_texture) ; - gPipeline.markTextured(facep->getDrawable()); - } -} - void LLViewerTexture::forceActive() { mTextureState = ACTIVE ; @@ -613,7 +582,16 @@ BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* image { llassert_always(mGLTexturep.notNull()) ; - return mGLTexturep->createGLTexture(discard_level, imageraw, usename) ; + BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename) ; + + if(ret) + { + mFullWidth = mGLTexturep->getCurrentWidth() ; + mFullHeight = mGLTexturep->getCurrentHeight() ; + mComponents = mGLTexturep->getComponents() ; + } + + return ret ; } void LLViewerTexture::setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes) @@ -2142,18 +2120,59 @@ void LLViewerMediaTexture::updateClass() for(media_map_t::iterator iter = sMediaMap.begin() ; iter != sMediaMap.end(); ) { - LLViewerMediaTexture* mediap = iter->second; - ++iter ; + LLViewerMediaTexture* mediap = iter->second; + // + //Note: delay some time to delete the media textures to stop endlessly creating and immediately removing media texture. + // if(mediap->getNumRefs() == 1 && mediap->getLastReferencedTimer()->getElapsedTimeF32() > MAX_INACTIVE_TIME) //one by sMediaMap { - sMediaMap.erase(mediap->getID()) ; + media_map_t::iterator cur = iter++ ; + sMediaMap.erase(cur) ; } + else + { + ++iter ; + } + } +} + +//static +void LLViewerMediaTexture::removeMediaImplFromTexture(const LLUUID& media_id) +{ + LLViewerMediaTexture* media_tex = findMediaTexture(media_id) ; + if(media_tex) + { + media_tex->invalidateMediaImpl() ; } } +//static +void LLViewerMediaTexture::cleanup() +{ + sMediaMap.clear() ; +} + +//static +LLViewerMediaTexture* LLViewerMediaTexture::findMediaTexture(const LLUUID& media_id) +{ + media_map_t::iterator iter = sMediaMap.find(media_id); + if(iter == sMediaMap.end()) + { + return NULL; + } + + LLViewerMediaTexture* media_tex = iter->second ; + media_tex->setMediaImpl() ; + media_tex->getLastReferencedTimer()->reset() ; + + return media_tex; +} + LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LLImageGL* gl_image) - : LLViewerTexture(id, usemipmaps) + : LLViewerTexture(id, usemipmaps), + mMediaImplp(NULL), + mUpdateVirtualSizeTime(0) { sMediaMap.insert(std::make_pair(id, this)); @@ -2165,6 +2184,13 @@ LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LL mGLTexturep->setNeedsAlphaAndPickMask(FALSE) ; mIsPlaying = FALSE ; + + setMediaImpl() ; +} + +//virtual +LLViewerMediaTexture::~LLViewerMediaTexture() +{ } void LLViewerMediaTexture::reinit(BOOL usemipmaps /* = TRUE */) @@ -2172,7 +2198,6 @@ void LLViewerMediaTexture::reinit(BOOL usemipmaps /* = TRUE */) mGLTexturep = NULL ; init(false); mUseMipMaps = usemipmaps ; - mIsPlaying = FALSE ; getLastReferencedTimer()->reset() ; generateGLTexture() ; @@ -2195,14 +2220,336 @@ S8 LLViewerMediaTexture::getType() const return LLViewerTexture::MEDIA_TEXTURE ; } -void LLViewerMediaTexture::setOldTexture(LLViewerTexture* tex) +void LLViewerMediaTexture::invalidateMediaImpl() { - mOldTexturep = tex ; + mMediaImplp = NULL ; } + +void LLViewerMediaTexture::setMediaImpl() +{ + if(!mMediaImplp) + { + mMediaImplp = LLViewerMedia::getMediaImplFromTextureID(mID) ; + } +} + +//return true if all faces to reference to this media texture are found +//Note: mMediaFaceList is valid only for the current instant +// because it does not check the face validity after the current frame. +BOOL LLViewerMediaTexture::findFaces() +{ + mMediaFaceList.clear() ; + + BOOL ret = TRUE ; + + //for parcel media + LLViewerTexture* tex = gTextureList.findImage(mID) ; + if(tex) + { + const ll_face_list_t* face_list = tex->getFaceList() ; + for(ll_face_list_t::const_iterator iter = face_list->begin(); iter != face_list->end(); ++iter) + { + mMediaFaceList.push_back(*iter) ; + } + } -LLViewerTexture* LLViewerMediaTexture::getOldTexture() const + if(!mMediaImplp) + { + return TRUE ; + } + + //for media on a face. + const std::list< LLVOVolume* >* obj_list = mMediaImplp->getObjectList() ; + std::list< LLVOVolume* >::const_iterator iter = obj_list->begin() ; + for(; iter != obj_list->end(); ++iter) + { + LLVOVolume* obj = *iter ; + if(obj->mDrawable.isNull()) + { + ret = FALSE ; + continue ; + } + + S32 face_id = -1 ; + while((face_id = obj->getFaceIndexWithMediaImpl(mMediaImplp, face_id)) > -1) + { + LLFace* facep = obj->mDrawable->getFace(face_id) ; + if(facep) + { + mMediaFaceList.push_back(facep) ; + } + else + { + ret = FALSE ; + } + } + } + + return ret ; +} + +void LLViewerMediaTexture::initVirtualSize() +{ + if(mIsPlaying) + { + return ; + } + + findFaces() ; + for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) + { + addTextureStats((*iter)->getVirtualSize()) ; + } +} + +void LLViewerMediaTexture::addMediaToFace(LLFace* facep) +{ + if(!mIsPlaying) + { + return ; //no need to add the face because the media is not in playing. + } + + switchTexture(facep) ; +} + +void LLViewerMediaTexture::removeMediaFromFace(LLFace* facep) +{ + if(!mIsPlaying) + { + return ; //no need to remove the face because the media is not in playing. + } + if(!facep) + { + return ; + } + + mIsPlaying = FALSE ; //set to remove the media from the face. + switchTexture(facep) ; + mIsPlaying = TRUE ; //set the flag back. + + if(mFaceList.empty()) //no face referencing to this media + { + stopPlaying() ; + } +} + +//virtual +void LLViewerMediaTexture::addFace(LLFace* facep) +{ + LLViewerTexture::addFace(facep) ; + + const LLTextureEntry* te = facep->getTextureEntry() ; + if(te) + { + LLViewerTexture* tex = gTextureList.findImage(te->getID()) ; + if(tex) + { + mTextureList.push_back(tex) ;//increase the reference number by one for tex to avoid deleting it. + return ; + } + } + llerrs << "The face does not have a valid texture before media texture." << llendl ; +} + +//virtual +void LLViewerMediaTexture::removeFace(LLFace* facep) +{ + LLViewerTexture::removeFace(facep) ; + + const LLTextureEntry* te = facep->getTextureEntry() ; + if(te) + { + LLViewerTexture* tex = gTextureList.findImage(te->getID()) ; + if(tex) + { + for(std::list< LLPointer<LLViewerTexture> >::iterator iter = mTextureList.begin(); + iter != mTextureList.end(); ++iter) + { + if(*iter == tex) + { + mTextureList.erase(iter) ; //decrease the reference number for tex by one. + return ; + } + } + + // + //we have some trouble here: the texture of the face is changed. + //we need to find the former texture, and remove it from the list to avoid memory leaking. + if(mFaceList.empty()) + { + mTextureList.clear() ; + return ; + } + S32 end = mFaceList.size() ; + std::vector<const LLTextureEntry*> te_list(end) ; + S32 i = 0 ; + for(ll_face_list_t::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ++iter) + { + te_list[i++] = (*iter)->getTextureEntry() ;//all textures are in use. + } + for(std::list< LLPointer<LLViewerTexture> >::iterator iter = mTextureList.begin(); + iter != mTextureList.end(); ++iter) + { + for(i = 0 ; i < end ; i++) + { + if(te_list[i] && te_list[i]->getID() == (*iter)->getID())//the texture is in use. + { + te_list[i] = NULL ; + break ; + } + } + if(i == end) //no hit for this texture, remove it. + { + mTextureList.erase(iter) ; //decrease the reference number for tex by one. + return ; + } + } + } + } + llerrs << "mTextureList texture reference number is corrupted." << llendl ; +} + +void LLViewerMediaTexture::stopPlaying() +{ + if(mMediaImplp) + { + mMediaImplp->stop() ; + } + mIsPlaying = FALSE ; +} + +void LLViewerMediaTexture::switchTexture(LLFace* facep) +{ + if(facep) + { + //check if another media is playing on this face. + if(facep->getTexture() && facep->getTexture() != this + && facep->getTexture()->getType() == LLViewerTexture::MEDIA_TEXTURE) + { + if(mID == facep->getTexture()->getID()) //this is a parcel media + { + return ; //let the prim media win. + } + } + + if(mIsPlaying) //old textures switch to the media texture + { + facep->switchTexture(this) ; + } + else //switch to old textures. + { + const LLTextureEntry* te = facep->getTextureEntry() ; + if(te) + { + LLViewerTexture* tex = gTextureList.findImage(te->getID()) ; + facep->switchTexture(tex) ; + } + } + } +} + +void LLViewerMediaTexture::setPlaying(BOOL playing) { - return mOldTexturep ; + if(!mMediaImplp) + { + return ; + } + if(!playing && !mIsPlaying) + { + return ; //media is already off + } + + if(playing == mIsPlaying && !mMediaImplp->isUpdated()) + { + return ; //nothing has changed since last time. + } + + mIsPlaying = playing ; + if(mIsPlaying) //is about to play this media + { + if(findFaces()) + { + //about to update all faces. + mMediaImplp->setUpdated(FALSE) ; + } + + if(mMediaFaceList.empty())//no face pointing to this media + { + stopPlaying() ; + return ; + } + + for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) + { + switchTexture(*iter) ; + } + } + else //stop playing this media + { + if(mFaceList.empty()) + { + return ; + } + + ll_face_list_t::iterator cur ; + for(ll_face_list_t::iterator iter = mFaceList.begin(); iter!= mFaceList.end(); ) + { + cur = iter++ ; + switchTexture(*cur) ; //cur could be removed in this function. + } + } + return ; +} + +//virtual +F32 LLViewerMediaTexture::getMaxVirtualSize() +{ + if(LLFrameTimer::getFrameCount() == mUpdateVirtualSizeTime) + { + return mMaxVirtualSize ; + } + mUpdateVirtualSizeTime = LLFrameTimer::getFrameCount() ; + + if(mNeedsResetMaxVirtualSize) + { + mMaxVirtualSize = 0.f ;//reset + mNeedsResetMaxVirtualSize = FALSE ; + } + + if(mIsPlaying) //media is playing + { + if(mFaceList.size() > 0) + { + for(std::list<LLFace*>::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ++iter) + { + LLFace* facep = *iter ; + if(facep->getDrawable()->isRecentlyVisible()) + { + addTextureStats(facep->getVirtualSize()) ; + } + } + } + } + else //media is not in playing + { + findFaces() ; + + if(!mMediaFaceList.empty()) + { + for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) + { + LLFace* facep = *iter ; + if(facep->getDrawable()->isRecentlyVisible()) + { + addTextureStats(facep->getVirtualSize()) ; + } + } + } + } + + mNeedsResetMaxVirtualSize = TRUE ; + + return mMaxVirtualSize ; } //---------------------------------------------------------------------------------------------- //end of LLViewerMediaTexture diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 0be1bf81de..596bfea670 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -49,6 +49,7 @@ class LLFace; class LLImageGL ; +class LLViewerObject; class LLViewerTexture; class LLViewerFetchedTexture ; class LLViewerMediaTexture ; @@ -58,7 +59,9 @@ typedef void (*loaded_callback_func)( BOOL success, LLViewerFetchedTexture *src_ class LLVFile; class LLMessageSystem; - +class LLViewerMediaImpl ; +class LLVOVolume ; + class LLLoadedCallbackEntry { public: @@ -123,6 +126,8 @@ public: BOOST_MAX_LEVEL }; + typedef std::list<LLFace*> ll_face_list_t ; + protected: virtual ~LLViewerTexture(); LOG_CLASS(LLViewerTexture); @@ -152,16 +157,17 @@ public: //maxVirtualSize of the texture void addTextureStats(F32 virtual_size) const ; void resetTextureStats(BOOL zero = FALSE); - F32 getMaxVirtualSize()const {return mMaxVirtualSize ;} + virtual F32 getMaxVirtualSize() ; LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;} S32 getFullWidth() const { return mFullWidth; } S32 getFullHeight() const { return mFullHeight; } - void addFace(LLFace* facep) ; - void removeFace(LLFace* facep) ; - + virtual void addFace(LLFace* facep) ; + virtual void removeFace(LLFace* facep) ; + const ll_face_list_t* getFaceList() const {return &mFaceList ;} + void generateGLTexture() ; void destroyGLTexture() ; @@ -206,8 +212,6 @@ public: //end of functions to access LLImageGL //--------------------------------------------------------------------------------------------- - void switchToTexture(LLViewerTexture* new_texture) ; //make all faces pointing to this texture to point to new_texture. - //----------------- /*virtual*/ void setActive() ; void forceActive() ; @@ -233,10 +237,9 @@ protected: BOOL mUseMipMaps ; S8 mComponents; mutable F32 mMaxVirtualSize; // The largest virtual size of the image, in pixels - how much data to we need? - + mutable BOOL mNeedsResetMaxVirtualSize ; LLFrameTimer mLastReferencedTimer; - typedef std::list<LLFace*> ll_face_list_t ; ll_face_list_t mFaceList ; //reverse pointer pointing to the faces using this image as texture //GL texture @@ -498,34 +501,61 @@ private: class LLViewerMediaTexture : public LLViewerTexture { protected: - /*virtual*/ ~LLViewerMediaTexture() {} + /*virtual*/ ~LLViewerMediaTexture() ; public: LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ; /*virtual*/ S8 getType() const; - void reinit(BOOL usemipmaps = TRUE); BOOL getUseMipMaps() {return mUseMipMaps ; } - void setUseMipMaps(BOOL mipmap) ; + void setUseMipMaps(BOOL mipmap) ; + + void setPlaying(BOOL playing) ; + BOOL isPlaying() const {return mIsPlaying;} + void setMediaImpl() ; - void setOldTexture(LLViewerTexture* tex) ; - LLViewerTexture* getOldTexture() const ; + void initVirtualSize() ; + void invalidateMediaImpl() ; - void setPlaying(BOOL playing) {mIsPlaying = playing ;} - BOOL isPlaying() const {return mIsPlaying;} + void addMediaToFace(LLFace* facep) ; + void removeMediaFromFace(LLFace* facep) ; + + /*virtual*/ void addFace(LLFace* facep) ; + /*virtual*/ void removeFace(LLFace* facep) ; + + /*virtual*/ F32 getMaxVirtualSize() ; +private: + void switchTexture(LLFace* facep) ; + BOOL findFaces() ; + void stopPlaying() ; private: - LLPointer<LLViewerTexture> mOldTexturep ; //the texture this media texture replaces. + // + //an instant list, recording all faces referencing or can reference to this media texture. + //NOTE: it is NOT thread safe. + // + std::list< LLFace* > mMediaFaceList ; + + //an instant list keeping all textures which are replaced by the current media texture, + //is only used to avoid the removal of those textures from memory. + std::list< LLPointer<LLViewerTexture> > mTextureList ; + + LLViewerMediaImpl* mMediaImplp ; BOOL mIsPlaying ; + U32 mUpdateVirtualSizeTime ; public: static void updateClass() ; + static void cleanup() ; -public: + static LLViewerMediaTexture* findMediaTexture(const LLUUID& media_id) ; + static void removeMediaImplFromTexture(const LLUUID& media_id) ; + +private: typedef std::map< LLUUID, LLPointer<LLViewerMediaTexture> > media_map_t ; - static media_map_t sMediaMap ; + static media_map_t sMediaMap ; }; //just an interface class, do not create instance from this class. diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index d23f10f880..4a0efbaddc 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3223,9 +3223,9 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_trans // assume that pickAsync put the results in the back of the mPicks list if(mPicks.size() != 0) { - mLastPick = mPicks.back(); - mLastPick.fetchResults(); - mPicks.pop_back(); + mLastPick = mPicks.back(); + mLastPick.fetchResults(); + mPicks.pop_back(); } else { diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 93cb0f0f45..e69779b2dc 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -46,6 +46,8 @@ #include "llvolumemessage.h" #include "material_codes.h" #include "message.h" +#include "llmediadataresponder.h" +#include "llpluginclassmedia.h" // for code in the mediaEvent handler #include "object_flags.h" #include "llagentconstants.h" #include "lldrawable.h" @@ -65,6 +67,10 @@ #include "llworld.h" #include "llselectmgr.h" #include "pipeline.h" +#include "llsdutil.h" +#include "llmediaentry.h" +#include "llmediadatafetcher.h" +#include "llagent.h" const S32 MIN_QUIET_FRAMES_COALESCE = 30; const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; @@ -100,6 +106,8 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mLODChanged = FALSE; mSculptChanged = FALSE; mSpotLightPriority = 0.f; + + mMediaImplList.resize(getNumTEs()); } LLVOVolume::~LLVOVolume() @@ -108,14 +116,31 @@ LLVOVolume::~LLVOVolume() mTextureAnimp = NULL; delete mVolumeImpl; mVolumeImpl = NULL; + + if(!mMediaImplList.empty()) + { + for(U32 i = 0 ; i < mMediaImplList.size() ; i++) + { + if(mMediaImplList[i].notNull()) + { + mMediaImplList[i]->removeObject(this) ; + } + } + } } // static void LLVOVolume::initClass() { + LLMediaDataFetcher::initClass(); } +// static +void LLVOVolume::cleanupClass() +{ + LLMediaDataFetcher::cleanupClass(); +} U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, void **user_data, @@ -123,6 +148,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, LLDataPacker *dp) { LLColor4U color; + const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA); // Do base class updates... U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); @@ -190,10 +216,15 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, // // Unpack texture entry data // - if (unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num) & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR)) + S32 result = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num); + if (result & teDirtyBits) { updateTEData(); } + if (result & TEM_CHANGE_MEDIA) + { + retval |= MEDIA_FLAGS_CHANGED; + } } else { @@ -226,9 +257,16 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, // llerrs << "Bogus TE data in " << getID() << ", crashing!" << llendl; llwarns << "Bogus TE data in " << getID() << llendl; } - else if (res2 & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR)) + else { - updateTEData(); + if (res2 & teDirtyBits) + { + updateTEData(); + } + if (res2 & TEM_CHANGE_MEDIA) + { + retval |= MEDIA_FLAGS_CHANGED; + } } U32 value = dp->getPassFlags(); @@ -266,14 +304,29 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, U8 tdpbuffer[1024]; LLDataPackerBinaryBuffer tdp(tdpbuffer, 1024); mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num); - if ( unpackTEMessage(tdp) & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR)) + S32 result = unpackTEMessage(tdp); + if (result & teDirtyBits) { updateTEData(); } + if (result & TEM_CHANGE_MEDIA) + { + retval |= MEDIA_FLAGS_CHANGED; + } } } } - + if (retval & (MEDIA_URL_REMOVED | MEDIA_URL_ADDED | MEDIA_URL_UPDATED | MEDIA_FLAGS_CHANGED)) { + // If the media changed at all, request new media data + if(mMedia) + { + llinfos << "Media URL: " << mMedia->mMediaURL << llendl; + } + requestMediaDataUpdate(); + } + // ...and clean up any media impls + cleanUpMediaImpls(); + return retval; } @@ -1327,6 +1380,46 @@ BOOL LLVOVolume::isRootEdit() const return TRUE; } +//virtual +void LLVOVolume::setNumTEs(const U8 num_tes) +{ + const U8 old_num_tes = getNumTEs() ; + + if(old_num_tes && old_num_tes < num_tes) //new faces added + { + LLViewerObject::setNumTEs(num_tes) ; + + if(mMediaImplList.size() >= old_num_tes && mMediaImplList[old_num_tes -1].notNull())//duplicate the last media textures if exists. + { + mMediaImplList.resize(num_tes) ; + const LLTextureEntry* te = getTE(old_num_tes - 1) ; + for(U8 i = old_num_tes; i < num_tes ; i++) + { + setTE(i, *te) ; + mMediaImplList[i] = mMediaImplList[old_num_tes -1] ; + } + mMediaImplList[old_num_tes -1]->setUpdated(TRUE) ; + } + } + else if(old_num_tes > num_tes && mMediaImplList.size() > num_tes) //old faces removed + { + U8 end = mMediaImplList.size() ; + for(U8 i = num_tes; i < end ; i++) + { + removeMediaImpl(i) ; + } + mMediaImplList.resize(num_tes) ; + + LLViewerObject::setNumTEs(num_tes) ; + } + else + { + LLViewerObject::setNumTEs(num_tes) ; + } + + return ; +} + void LLVOVolume::setTEImage(const U8 te, LLViewerTexture *imagep) { BOOL changed = (mTEImages[te] != imagep); @@ -1510,6 +1603,321 @@ void LLVOVolume::updateTEData() }*/ } +bool LLVOVolume::hasMedia() const +{ + bool result = false; + const U8 numTEs = getNumTEs(); + for (U8 i = 0; i < numTEs; i++) + { + const LLTextureEntry* te = getTE(i); + if(te->hasMedia()) + { + result = true; + break; + } + } + return result; +} + +void LLVOVolume::requestMediaDataUpdate() +{ + LLMediaDataFetcher::fetchMedia(this); +} + +void LLVOVolume::cleanUpMediaImpls() +{ + // Iterate through our TEs and remove any Impls that are no longer used + const U8 numTEs = getNumTEs(); + for (U8 i = 0; i < numTEs; i++) + { + const LLTextureEntry* te = getTE(i); + if( ! te->hasMedia()) + { + // Delete the media IMPL! + removeMediaImpl(i) ; + } + } +} + +void LLVOVolume::updateObjectMediaData(const LLSD &media_data_array) +{ + // media_data_array is an array of media entry maps + + //llinfos << "updating:" << this->getID() << " " << ll_pretty_print_sd(media_data_array) << llendl; + + LLSD::array_const_iterator iter = media_data_array.beginArray(); + LLSD::array_const_iterator end = media_data_array.endArray(); + U8 texture_index = 0; + for (; iter != end; ++iter, ++texture_index) + { + syncMediaData(texture_index, *iter, false/*merge*/, false/*ignore_agent*/); + } +} + +void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool merge, bool ignore_agent) +{ + LLTextureEntry *te = getTE(texture_index); + //llinfos << "BEFORE: texture_index = " << texture_index + // << " hasMedia = " << te->hasMedia() << " : " + // << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; + + std::string previous_url; + LLMediaEntry* mep = te->getMediaData(); + if(mep) + { + // Save the "current url" from before the update so we can tell if + // it changes. + previous_url = mep->getCurrentURL(); + } + + if (merge) + { + te->mergeIntoMediaData(media_data); + } + else { + // XXX Question: what if the media data is undefined LLSD, but the + // update we got above said that we have media flags?? Here we clobber + // that, assuming the data from the service is more up-to-date. + te->updateMediaData(media_data); + } + + mep = te->getMediaData(); + if(mep) + { + bool update_from_self = false; + if (!ignore_agent) + { + LLUUID updating_agent = LLTextureEntry::getAgentIDFromMediaVersionString(getMediaURL()); + update_from_self = (updating_agent == gAgent.getID()); + } + viewer_media_t media_impl = LLViewerMedia::updateMediaImpl(mep, previous_url, update_from_self); + + addMediaImpl(media_impl, texture_index) ; + } + + //llinfos << "AFTER: texture_index = " << texture_index + // << " hasMedia = " << te->hasMedia() << " : " + // << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; +} + +void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) +{ + switch(event) + { + + case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED: + { + switch(impl->getNavState()) + { + case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED: + { + // This is the first location changed event after the start of a non-server-directed nav. It may need to be broadcast. + + bool block_navigation = false; + // FIXME: if/when we allow the same media impl to be used by multiple faces, the logic here will need to be fixed + // to deal with multiple face indices. + int face_index = getFaceIndexWithMediaImpl(impl, -1); + std::string new_location = plugin->getLocation(); + + // Find the media entry for this navigate + LLMediaEntry* mep = NULL; + LLTextureEntry *te = getTE(face_index); + if(te) + { + mep = te->getMediaData(); + } + + if(mep) + { + if(!mep->checkCandidateUrl(new_location)) + { + block_navigation = true; + } + } + else + { + llwarns << "Couldn't find media entry!" << llendl; + } + + if(block_navigation) + { + llinfos << "blocking navigate to URI " << new_location << llendl; + + // "bounce back" to the current URL from the media entry + // NOTE: the only way block_navigation can be true is if we found the media entry, so we're guaranteed here that mep is not NULL. + impl->navigateTo(mep->getCurrentURL()); + } + else + { + + llinfos << "broadcasting navigate with URI " << new_location << llendl; + + // Post the navigate to the cap + std::string cap = getRegion()->getCapability("ObjectMediaNavigate"); + if(cap.empty()) + { + // XXX *TODO: deal with no cap! It may happen! (retry?) + LL_WARNS("Media") << "Can't broadcast navigate event -- ObjectMediaNavigate cap is not available" << LL_ENDL; + return; + } + + // If we got here, the cap is available. Index through all faces that have this media and send the navigate message. + LLSD sd; + sd["object_id"] = mID; + sd["current_url"] = new_location; + sd["texture_index"] = face_index; + LLHTTPClient::post(cap, sd, new LLMediaDataResponder("ObjectMediaNavigate", sd, this)); + } + } + break; + + case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: + // This is the first location changed event after the start of a server-directed nav. Don't broadcast it. + llinfos << " NOT broadcasting navigate (server-directed)" << llendl; + break; + + default: + // This is a subsequent location-changed due to a redirect. Don't broadcast. + llinfos << " NOT broadcasting navigate (redirect)" << llendl; + break; + } + } + break; + + default: + break; + } + +} + +void LLVOVolume::sendMediaDataUpdate() const +{ + std::string url = getRegion()->getCapability("ObjectMedia"); + if (!url.empty()) + { + LLSD sd_payload; + sd_payload["verb"] = "UPDATE"; + sd_payload[LLTextureEntry::OBJECT_ID_KEY] = mID; + LLSD object_media_data; + for (int i=0; i < getNumTEs(); i++) { + LLTextureEntry *texture_entry = getTE(i); + llassert((texture_entry->getMediaData() != NULL) == texture_entry->hasMedia()); + const LLSD &media_data = + (texture_entry->getMediaData() == NULL) ? LLSD() : texture_entry->getMediaData()->asLLSD(); + object_media_data.append(media_data); + } + sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data; + + llinfos << "Sending media data: " << getID() << " " << ll_pretty_print_sd(sd_payload) << llendl; + + LLHTTPClient::post(url, sd_payload, new LLMediaDataResponder("ObjectMedia", sd_payload, this)); + } + // XXX *TODO: deal with no cap! It may happen! (retry?) +} + +void LLVOVolume::removeMediaImpl(S32 texture_index) +{ + if(mMediaImplList.size() <= (U32)texture_index || mMediaImplList[texture_index].isNull()) + { + return ; + } + + //make the face referencing to mMediaImplList[texture_index] to point back to the old texture. + if(mDrawable) + { + LLFace* facep = mDrawable->getFace(texture_index) ; + if(facep) + { + LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ; + if(media_tex) + { + media_tex->removeMediaFromFace(facep) ; + } + } + } + + //check if some other face(s) of this object reference(s)to this media impl. + S32 i ; + S32 end = (S32)mMediaImplList.size() ; + for(i = 0; i < end ; i++) + { + if( i != texture_index && mMediaImplList[i] == mMediaImplList[texture_index]) + { + break ; + } + } + + if(i == end) //this object does not need this media impl. + { + mMediaImplList[texture_index]->removeObject(this) ; + } + + mMediaImplList[texture_index] = NULL ; + return ; +} + +void LLVOVolume::addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) +{ + if((S32)mMediaImplList.size() < texture_index + 1) + { + mMediaImplList.resize(texture_index + 1) ; + } + + if(mMediaImplList[texture_index].notNull()) + { + if(mMediaImplList[texture_index] == media_impl) + { + return ; + } + + removeMediaImpl(texture_index) ; + } + + mMediaImplList[texture_index] = media_impl; + media_impl->addObject(this) ; + + //add the face to show the media if it is in playing + if(mDrawable) + { + LLFace* facep = mDrawable->getFace(texture_index) ; + if(facep) + { + LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ; + if(media_tex) + { + media_tex->addMediaToFace(facep) ; + } + } + else //the face is not available now, start media on this face later. + { + media_impl->setUpdated(TRUE) ; + } + } + return ; +} + +viewer_media_t LLVOVolume::getMediaImpl(U8 face_id) const +{ + if(mMediaImplList.size() > face_id) + { + return mMediaImplList[face_id]; + } + return NULL; +} + +S32 LLVOVolume::getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id) +{ + S32 end = (S32)mMediaImplList.size() ; + for(S32 face_id = start_face_id + 1; face_id < end; face_id++) + { + if(mMediaImplList[face_id] == media_impl) + { + return face_id ; + } + } + return -1 ; +} + //---------------------------------------------------------------------------- void LLVOVolume::setLightTextureID(LLUUID id) diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 1b90219836..9a79b620d5 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -35,6 +35,7 @@ #include "llviewerobject.h" #include "llviewertexture.h" +#include "llviewermedia.h" #include "llframetimer.h" #include "llapr.h" #include "m3math.h" // LLMatrix3 @@ -45,6 +46,8 @@ class LLViewerTextureAnim; class LLDrawPool; class LLSelectNode; +typedef std::vector<viewer_media_t> media_list_t; + enum LLVolumeInterfaceType { INTERFACE_FLEXIBLE = 1, @@ -75,12 +78,14 @@ public: // Class which embodies all Volume objects (with pcode LL_PCODE_VOLUME) class LLVOVolume : public LLViewerObject { + LOG_CLASS(LLVOVolume); protected: virtual ~LLVOVolume(); public: static void initClass(); - static void preUpdateGeom(); + static void cleanupClass(); + static void preUpdateGeom(); enum { @@ -153,6 +158,7 @@ public: /*virtual*/ void setScale(const LLVector3 &scale, BOOL damped); + /*virtual*/ void setNumTEs(const U8 num_tes); /*virtual*/ void setTEImage(const U8 te, LLViewerTexture *imagep); /*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid); /*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color); @@ -224,13 +230,31 @@ public: BOOL isVolumeGlobal() const; BOOL canBeFlexible() const; BOOL setIsFlexible(BOOL is_flexible); - + + void updateObjectMediaData(const LLSD &media_data_duples); + void mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event); + + // Sync the given media data with the impl and the given te + void syncMediaData(S32 te, const LLSD &media_data, bool merge, bool ignore_agent); + + // Send media data update to the simulator. + void sendMediaDataUpdate() const; + + viewer_media_t getMediaImpl(U8 face_id) const; + S32 getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id); + + bool hasMedia() const; + protected: S32 computeLODDetail(F32 distance, F32 radius); BOOL calcLOD(); LLFace* addFace(S32 face_index); void updateTEData(); + void requestMediaDataUpdate(); + void cleanUpMediaImpls(); + void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ; + void removeMediaImpl(S32 texture_index) ; public: LLViewerTextureAnim *mTextureAnimp; U8 mTexAnimMode; @@ -251,6 +275,7 @@ private: LLVolumeInterface *mVolumeImpl; LLPointer<LLViewerFetchedTexture> mSculptTexture; LLPointer<LLViewerFetchedTexture> mLightTexture; + media_list_t mMediaImplList; // statics public: diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index da1cd59619..7e22e17188 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -94,7 +94,7 @@ value="0.58 0.66 0.84 1" /> <color name="AvatarNameColor" - value="0.98 0.69 0.36 1" /> + reference="White" /> <color name="BackgroundChatColor" reference="DkGray_66" /> @@ -253,7 +253,7 @@ reference="White_10" /> <color name="DefaultHighlightLight" - reference="White_25" /> + reference="White_25" /> <color name="DefaultShadowDark" reference="Black_50" /> @@ -493,7 +493,7 @@ value="0 0.78 0.78 1" /> <color name="NotifyBoxColor" - value="0.27 0.67 1 1" /> + value="LtGray" /> <color name="NotifyCautionBoxColor" value="1 0.82 0.46 1" /> @@ -625,7 +625,7 @@ reference="Black" /> <color name="TextDefaultColor" - value="0 0 0 .33" /> + value="Black" /> <color name="TextEmbeddedItemColor" value="0 0 0.5 1" /> @@ -643,16 +643,16 @@ value="0 0 0 .33" /> <color name="TimeTextColor" - reference="LtGray" /> + reference="LtGray_50" /> <color name="TitleBarFocusColor" reference="White_10" /> <color name="ToolTipBgColor" - value="0 0 0 .75" /> + value="DkGray" /> <color name="ToolTipBorderColor" - value="0 0 0 .75" /> + value="White_50" /> <color name="ToolTipTextColor" reference="LtGray" /> diff --git a/indra/newview/skins/default/html/en-us/help-offline/index.html b/indra/newview/skins/default/html/en-us/help-offline/index.html new file mode 100644 index 0000000000..bf3677603e --- /dev/null +++ b/indra/newview/skins/default/html/en-us/help-offline/index.html @@ -0,0 +1,29 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Offline Help</title> +<style> +body {background-color:#000000;font-family:verdana,helvetica,sans-serif;font-size:62.5%;color:#e9f1f8;width:100%;padding:0px;margin:0px;} +a {color:#93a9d5;} +a:active {color:#50607C;text-decoration:underline;} +a:hover {color:#ff7900;text-decoration:underline;} +#infobox{position:absolute;top:40%;left:50%;z-index:1;padding:0;width:592px;margin-left:-296px;margin-top:-150px;text-align:center;font-size:1.2em; color:#ccc;} +#infobox #submitbtn {padding:15px 3px 5px 15px;height:28px;width:127px;margin-left:244px;} +#infobox #submitbtn input {text-transform:capitalize;color:#fff;font-size:1.0em;height:28px;width:127px;border:none;font-weight:normal;background:url(../../btn_purplepill_bg.png) bottom left no-repeat;vertical-align:text-bottom;font-weight:bold;} +#infobox #submitbtn input:hover.input_over, #login_box #submitbtn input:hover.input_off {color:#fff;border:none;background:url(../../btn_purplepill_bg.png) bottom right no-repeat;} +#infobox #submitbtn input:active.input_over {color:#fff;border:none;background:url(../../btn_purplepill_bg.png) top left no-repeat;} +#infobox #submitbtn input.pressed {color:#888;border:none;background:url(../../btn_purplepill_bg.png) top right no-repeat;} +</style> +</head> +<body> +<div id="infobox"> + <p> + Second Life Offline Help. + </p> + <p> + You are not online and are configured not to fetch help remotely. This is all the help that is available + until more stuff is done. Yeah. + </p> + </div> +</div> +</body> diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 46c294768d..8a6e9486a2 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -110,12 +110,10 @@ <texture name="Home_Off" file_name="navbar/Home_Off.png" preload="false" /> <texture name="Home_Press" file_name="navbar/Home_Press.png" preload="false" /> - <texture name="Icon_Close_Background" file_name="windows/Icon_Close_Background.png" preload="true" /> <texture name="Icon_Close_Foreground" file_name="windows/Icon_Close_Foreground.png" preload="true" /> <texture name="Icon_Close_Press" file_name="windows/Icon_Close_Press.png" preload="true" /> <texture name="Icon_Close_Toast" file_name="windows/Icon_Close_Toast.png" preload="true" /> - <texture name="Icon_Dock_Background" file_name="windows/Icon_Dock_Background.png" preload="true" /> <texture name="Icon_Dock_Foreground" file_name="windows/Icon_Dock_Foreground.png" preload="true" /> <texture name="Icon_Dock_Press" file_name="windows/Icon_Dock_Press.png" preload="true" /> @@ -125,16 +123,16 @@ <texture name="Icon_Gear_Foreground" file_name="windows/Icon_Gear_Foreground.png" preload="false" /> <texture name="Icon_Gear_Press" file_name="windows/Icon_Gear_Press.png" preload="false" /> - <texture name="Icon_Help_Background" file_name="windows/Icon_Help_Background.png" preload="false" /> <texture name="Icon_Help_Foreground" file_name="windows/Icon_Help_Foreground.png" preload="false" /> <texture name="Icon_Help_Press" file_name="windows/Icon_Help_Press.png" preload="false" /> <texture name="Icon_Info" file_name="windows/Icon_Info.png" preload="false" /> - <texture name="Icon_Minimize_Background" file_name="windows/Icon_Minimize_Background.png" preload="true" /> <texture name="Icon_Minimize_Foreground" file_name="windows/Icon_Minimize_Foreground.png" preload="true" /> <texture name="Icon_Minimize_Press" file_name="windows/Icon_Minimize_Press.png" preload="true" /> - <texture name="Icon_Undock_Background" file_name="windows/Icon_Undock_Background.png" preload="false" /> + <texture name="Icon_Restore_Foreground" file_name="windows/Icon_Restore_Foreground.png" preload="false" /> + <texture name="Icon_Restore_Press" file_name="windows/Icon_Restore_Press.png" preload="false" /> + <texture name="Icon_Undock_Foreground" file_name="windows/Icon_Undock_Foreground.png" preload="false" /> <texture name="Icon_Undock_Press" file_name="windows/Icon_Undock_Press.png" preload="false" /> @@ -175,6 +173,9 @@ <texture name="Inv_Underpants" file_name="icons/Inv_Underpants.png" preload="false" /> <texture name="Inv_Undershirt" file_name="icons/Inv_Undershirt.png" preload="false" /> + <texture name="Linden_Dollar_Alert" file_name="widgets/Linden_Dollar_Alert.png"/> + <texture name="Linden_Dollar_Background" file_name="widgets/Linden_Dollar_Background.png"/> + <texture name="ListItem_Select" file_name="widgets/ListItem_Select.png" preload="true" /> <texture name="ListItem_Over" file_name="widgets/ListItem_Over.png" preload="true" /> @@ -442,8 +443,6 @@ <texture name="cam_zoom_plus_in.tga" preload="false" /> <texture name="cam_zoom_minus_in.tga" preload="false" /> - <texture name="close_inactive_blue.tga" /> - <texture name="closebox.tga" /> <texture name="icn_clear_lineeditor.tga" /> <texture name="icn_chatbar.tga" /> @@ -493,10 +492,6 @@ <texture name="up_arrow.tga" file_name="up_arrow.png" /> <texture name="down_arrow.tga" file_name="down_arrow.png" /> - <texture name="restore_inactive.tga" /> - <texture name="restore.tga" /> - <texture name="restore_pressed.tga" /> - <texture name="tearoffbox.tga" /> <texture name="tearoff_pressed.tga" /> diff --git a/indra/newview/skins/default/textures/widgets/Linden_Dollar_Alert.png b/indra/newview/skins/default/textures/widgets/Linden_Dollar_Alert.png Binary files differnew file mode 100644 index 0000000000..a1f21e8194 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/Linden_Dollar_Alert.png diff --git a/indra/newview/skins/default/textures/widgets/Linden_Dollar_Background.png b/indra/newview/skins/default/textures/widgets/Linden_Dollar_Background.png Binary files differnew file mode 100644 index 0000000000..a1d602f6f0 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/Linden_Dollar_Background.png diff --git a/indra/newview/skins/default/textures/windows/Icon_Restore_Foreground.png b/indra/newview/skins/default/textures/windows/Icon_Restore_Foreground.png Binary files differnew file mode 100644 index 0000000000..1e753aaf1d --- /dev/null +++ b/indra/newview/skins/default/textures/windows/Icon_Restore_Foreground.png diff --git a/indra/newview/skins/default/textures/windows/Icon_Restore_Press.png b/indra/newview/skins/default/textures/windows/Icon_Restore_Press.png Binary files differnew file mode 100644 index 0000000000..be66b05230 --- /dev/null +++ b/indra/newview/skins/default/textures/windows/Icon_Restore_Press.png diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 97afe6d324..c9e143bf95 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -3,6 +3,7 @@ height="440" layout="topleft" name="floater_about" + help_topic="floater_about" save_rect="true" title="About [APP_NAME]" width="470"> diff --git a/indra/newview/skins/default/xui/en/floater_buy_currency.xml b/indra/newview/skins/default/xui/en/floater_buy_currency.xml index 52c7944ba9..991c9a84a3 100644 --- a/indra/newview/skins/default/xui/en/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/en/floater_buy_currency.xml @@ -1,296 +1,291 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <floater can_minimize="false" - height="270" + height="275" layout="topleft" name="buy currency" - help_topic="buy_currency" + help_topic="buy_linden_dollars" single_instance="true" - title="Buy Currency" + title="Buy L$" width="350"> <floater.string name="buy_currency"> - Buy L$ [LINDENS] for approx. US$ [USD] + Buy L$ [LINDENS] for approx. [LOCALAMOUNT] </floater.string> - <text + <floater.string + name="account_website"> + http://secondlife.com/account/billing.php + </floater.string> + <icon + height="215" + image_name="Linden_Dollar_Background" + layout="topleft" + left="0" + name="normal_background" + top="17" + width="350" /> + <text type="string" length="1" - bottom_delta="48" follows="top|left" font="SansSerifHuge" - height="24" layout="topleft" - left="16" - name="info_buying" - right="-20"> - Buying Currency: + left="20" + height="30" + top="30" + width="300" + name="info_need_more"> + You need more L$: </text> <text type="string" length="1" - bottom_delta="0" follows="top|left" - font="SansSerifHuge" - height="24" + height="16" layout="topleft" - left="16" - name="info_cannot_buy" - right="-20"> - Cannot buy now: + left="20" + width="300" + name="contacting"> + Contacting LindeX... </text> <text type="string" length="1" - bottom_delta="0" follows="top|left" font="SansSerifHuge" - height="24" layout="topleft" - left="16" - name="info_need_more" - right="-20"> - You need more currency: + left="20" + height="30" + top="30" + width="200" + name="info_buying"> + Buy L$ </text> - <icon - follows="top|left" - height="64" - image_name="badge_note.j2c" - layout="topleft" - left="0" - name="step_error" - top="48" - width="64" /> <text type="string" length="1" - bottom_delta="96" - follows="top|left" - height="140" - layout="topleft" - left="72" - name="error_message" - right="-20"> - Something ain't right. - </text> - <button - follows="bottom|left" - height="20" - label="Go to website" - layout="topleft" - left_delta="0" - name="error_web" - top_delta="124" - width="120" /> - <icon - follows="top|left" - height="64" - image_name="badge_note.j2c" - layout="topleft" - left="0" - name="step_1" - top="48" - width="64" /> - <text - type="string" - length="1" - bottom_delta="-38" follows="top|left" + font="SansSerifMedium" height="16" layout="topleft" - left="72" - name="contacting" - right="-20"> - Contacting LindeX... + left="20" + name="balance_label" + top_pad="10" + width="210"> + I have </text> <text type="string" length="1" - bottom_delta="0" + font="SansSerifMedium" follows="top|left" + halign="right" height="16" layout="topleft" - left="72" - name="buy_action_unknown" - right="-20"> - Buy L$ on the LindeX currency exchange + left="200" + name="balance_amount" + top_delta="0" + width="100"> + L$ [AMT] </text> <text type="string" length="1" - bottom_delta="0" follows="top|left" + font="SansSerifMedium" height="16" + top_pad="15" layout="topleft" - left="72" - name="buy_action" - right="-20"> - [NAME] L$ [PRICE] + left="20" + name="currency_action" + width="210"> + I want to buy </text> <text + font="SansSerifMedium" type="string" length="1" - follows="top|left" + follows="left|top" height="16" layout="topleft" - left_delta="0" - name="currency_action" - top_pad="4" - width="40"> - Buy L$ + top_delta="0" + left="222" + name="currency_label" + width="15"> + L$ </text> <line_editor type="string" - length="1" - follows="top|right" - height="16" - layout="topleft" - left_pad="5" + halign="right" + font="SansSerifMedium" + select_on_focus="true" + follows="top|left" + top_delta="-7" + height="22" + label="L$" + left_pad="3" name="currency_amt" - top_delta="0" - width="80"> + width="60"> 1234 </line_editor> <text type="string" - length="1" - follows="top|right" - height="16" - layout="topleft" - left_pad="5" - name="currency_est" - top_delta="0" - width="180"> - for approx. US$ [USD,number,2] - </text> - <text - type="string" - length="1" - follows="top|right" - height="16" - layout="topleft" - left_delta="5" - name="getting_data" - top_delta="0" - width="180"> - Getting data... - </text> - <text - type="string" + font="SansSerifMedium" length="1" follows="top|left" height="16" layout="topleft" - left="80" - name="balance_label" - top="110" - width="240"> - You currently have + left="20" + top_pad="10" + name="buying_label" + width="210"> + For the price </text> <text type="string" length="1" + font="SansSerifMedium" + text_color="EmphasisColor" follows="top|left" halign="right" height="16" - layout="topleft" - left_delta="0" - name="balance_amount" top_delta="0" - width="240"> - L$ [AMT] + layout="topleft" + left="170" + name="currency_est" + width="130"> + [LOCALAMOUNT] </text> <text type="string" + font="SansSerifSmall" + text_color="EmphasisColor" length="1" follows="top|left" height="16" layout="topleft" - left_delta="0" - name="buying_label" - top_pad="4" - width="240"> - You are buying + left="40" + width="100" + halign="right" + name="getting_data"> + Estimating... </text> <text type="string" + font="SansSerifSmall" + top_delta="0" length="1" follows="top|left" halign="right" height="16" + left_pad="10" + width="150" layout="topleft" - left_delta="0" - name="buying_amount" - top_delta="0" - width="240"> - L$ [AMT] + name="buy_action"> + [NAME] L$ [PRICE] </text> <text type="string" + font="SansSerifMedium" length="1" follows="top|left" height="16" layout="topleft" - left_delta="0" + left="20" name="total_label" - top_pad="4" - width="240"> - Your balance will be + width="210"> + My new balance will be </text> <text type="string" length="1" + font="SansSerifMedium" follows="top|left" - halign="right" + top_delta="0" height="16" layout="topleft" - left_delta="0" + left="200" + halign="right" name="total_amount" - top_delta="0" - width="240"> + width="100"> L$ [AMT] </text> <text type="string" length="1" - bottom_delta="48" follows="top|left" - height="32" layout="topleft" - left="72" - name="purchase_warning_repurchase" - right="-20"> - Confirming this purchase only buys the currency. -You'll need to try the operation again. + left="20" + width="300" + name="purchase_warning_repurchase"> + Confirming this purchase only buys the L$. +You'll need to try again. </text> <text type="string" length="1" - bottom_delta="0" follows="top|left" - height="32" layout="topleft" - left="72" - name="purchase_warning_notenough" - right="-20"> - You aren't buying enough currency + left="20" + name="purchase_warning_notenough"> + You aren't buying enough L$. Increase the amount to buy. </text> + + <button + follows="bottom|left" + height="20" + label="Buy Now" + layout="topleft" + left="151" + name="buy_btn" + top="248" + width="90"/> <button follows="bottom|right" height="20" label="Cancel" layout="topleft" - left="237" + left_pad="10" name="cancel_btn" - top="234" - width="90" /> - <button - follows="bottom|left" - height="20" - label="Purchase" + width="90"/> + <icon + height="215" + image_name="Linden_Dollar_Alert" layout="topleft" - left_delta="-96" - name="buy_btn" - top_delta="0" - width="90" /> + left="0" + name="error_background" + top="15" + width="350"/> + <text + type="string" + font="SansSerifHuge" + left="170" + width="170" + height="80" + top="30" + name="info_cannot_buy"> + Take your +[SECOND_LIFE] to +the next level... + </text> + <button + follows="bottom|left" + height="20" + label="Continue to the Web" + layout="topleft" + left="170" + name="error_web" + top="120" + width="160"/> + <text + type="string" + width="350" + height="20" + top_pad="92" + left_pad="-300" + follows="bottom|right" + name="cannot_buy_message"> + Continue to the web site and enter payment information + </text> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_help_browser.xml b/indra/newview/skins/default/xui/en/floater_help_browser.xml index a1265d49f9..512b4c85a1 100644 --- a/indra/newview/skins/default/xui/en/floater_help_browser.xml +++ b/indra/newview/skins/default/xui/en/floater_help_browser.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater can_resize="true" - height="440" + height="400" layout="topleft" min_height="140" min_width="467" @@ -9,8 +9,8 @@ help_topic="floater_help_browser" save_rect="true" single_instance="true" - title="Holy Bananas, it's the Help Browser" - width="820"> + title="Help Browser" + width="620"> <floater.string name="home_page_url"> http://www.secondlife.com @@ -20,150 +20,13 @@ http://support.secondlife.com </floater.string> <layout_stack - bottom="440" + bottom="400" follows="left|right|top|bottom" layout="topleft" left="10" name="stack1" top="20" - width="800"> - <layout_panel - auto_resize="false" - height="20" - layout="topleft" - left="0" - name="nav_controls" - top="400" - user_resize="false" - width="800"> - <button - follows="left|top" - height="20" - label="Back" - layout="topleft" - left="0" - name="back" - top="0" - width="55" /> - <button - follows="left|top" - height="20" - label="Forward" - layout="topleft" - left_pad="3" - name="forward" - top_delta="0" - width="68" /> - <button - enabled="false" - follows="left|top" - height="20" - label="Reload" - layout="topleft" - left_pad="2" - name="reload" - top_delta="0" - width="70"/> - <combo_box - allow_text_entry="true" - follows="left|top|right" - height="20" - layout="topleft" - left_pad="5" - max_chars="255" - name="address" - top_delta="0" - width="540" /> - <button - enabled="false" - follows="right|top" - height="20" - label="Go" - layout="topleft" - left_pad="5" - name="go" - top_delta="0" - width="55" /> - </layout_panel> - <layout_panel - auto_resize="false" - height="20" - layout="topleft" - left_delta="0" - name="time_controls" - top_delta="0" - user_resize="false" - width="800"> - <button - follows="left|top" - height="20" - label="rewind" - layout="topleft" - left="0" - name="rewind" - top="0" - width="55" /> - <button - follows="left|top" - height="20" - image_selected="button_anim_play_selected.tga" - image_unselected="button_anim_play.tga" - layout="topleft" - left_delta="55" - name="play" - picture_style="true" - top_delta="0" - width="55" /> - <button - follows="left|top" - height="20" - image_selected="button_anim_pause_selected.tga" - image_unselected="button_anim_pause.tga" - layout="topleft" - left_delta="0" - name="pause" - picture_style="true" - top_delta="0" - width="55" /> - <button - follows="left|top" - height="20" - label="stop" - layout="topleft" - left_pad="10" - name="stop" - top_delta="0" - width="55" /> - <button - follows="left|top" - height="20" - label="forward" - layout="topleft" - left_pad="20" - name="seek" - top_delta="0" - width="55" /> - </layout_panel> - <layout_panel - auto_resize="false" - height="20" - layout="topleft" - left_delta="0" - name="parcel_owner_controls" - top_delta="0" - user_resize="false" - width="540"> - <button - enabled="false" - follows="left|top" - height="20" - label="Send Current URL to Parcel" - layout="topleft" - left="0" - name="assign" - top="0" - width="200" /> - </layout_panel> + width="600"> <layout_panel height="20" layout="topleft" @@ -171,7 +34,7 @@ name="external_controls" top_delta="0" user_resize="false" - width="540"> + width="570"> <web_browser bottom="-10" follows="left|right|top|bottom" @@ -179,7 +42,7 @@ left="0" name="browser" top="0" - width="540" /> + width="570" /> <button follows="bottom|left" height="20" @@ -189,25 +52,17 @@ name="open_browser" top_pad="5" width="185" /> - <check_box - control_name="UseExternalBrowser" - follows="bottom|left" - height="20" - label="Always open in my web browser" - layout="topleft" - left_pad="5" - name="open_always" - top_delta="0" - width="200" /> +<!-- <button follows="bottom|right" height="20" label="Close" layout="topleft" - left_pad="80" + left_pad="290" name="close" top_delta="0" width="70" /> +--> </layout_panel> </layout_stack> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_media_settings.xml b/indra/newview/skins/default/xui/en/floater_media_settings.xml new file mode 100644 index 0000000000..6ba26f938d --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_media_settings.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater bottom="-666" can_close="true" can_drag_on_left="false" can_minimize="true" + can_resize="false" can_tear_off="true" default_tab_group="1" enabled="true" + width="365" height="535" left="330" min_height="430" min_width="620" + mouse_opaque="true" name="Medis Settings" title="Media Settings"> + <button bottom="-525" enabled="true" follows="right|bottom" font="SansSerif" + halign="center" height="20" label="OK" label_selected="OK" left="75" + mouse_opaque="true" name="OK" scale_image="true" width="90" /> + <button bottom_delta="0" enabled="true" follows="right|bottom" font="SansSerif" + halign="center" height="20" label="Cancel" label_selected="Cancel" + left_delta="93" mouse_opaque="true" name="Cancel" scale_image="true" + width="90" /> + <button bottom_delta="0" enabled="true" follows="right|bottom" font="SansSerif" + halign="center" height="20" label="Apply" label_selected="Apply" + left_delta="93" mouse_opaque="true" name="Apply" scale_image="true" + width="90" /> + <tab_container bottom="-500" enabled="true" follows="left|top|right|bottom" height="485" + left="0" mouse_opaque="false" name="tab_container" tab_group="1" + tab_position="top" tab_width="80" width="365" /> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_sys_well.xml b/indra/newview/skins/default/xui/en/floater_sys_well.xml index 30406cad63..aef5707fd4 100644 --- a/indra/newview/skins/default/xui/en/floater_sys_well.xml +++ b/indra/newview/skins/default/xui/en/floater_sys_well.xml @@ -12,7 +12,7 @@ width="320" min_width="320" height="23" - can_minimize="false" + can_minimize="true" can_tear_off="false" can_resize="false" can_drag_on_left="false" @@ -22,10 +22,10 @@ <flat_list_view color="FloaterDefaultBackgroundColor" follows="all" - layout="topleft" - name="notification_list" - left="1" + layout="topleft" + name="notification_list" + left="1" top="20" - height="0" - width="318"/> + height="0" + width="318"/> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index edbd28cd2d..053215f8ae 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -74,7 +74,11 @@ name="button focus" picture_style="true" tool_tip="Focus" - width="20" /> + width="20"> + <button.commit_callback + function="BuildTool.setTool" + parameter="Focus" /> + </button> <button follows="left|top" height="20" @@ -87,7 +91,11 @@ name="button move" picture_style="true" tool_tip="Move" - width="20" /> + width="20"> + <button.commit_callback + function="BuildTool.setTool" + parameter="Move" /> + </button> <button follows="left|top" height="20" @@ -100,7 +108,11 @@ name="button edit" picture_style="true" tool_tip="Edit" - width="20" /> + width="20"> + <button.commit_callback + function="BuildTool.setTool" + parameter="Edit" /> + </button> <button follows="left|top" height="20" @@ -113,7 +125,11 @@ name="button create" picture_style="true" tool_tip="Create" - width="20" /> + width="20"> + <button.commit_callback + function="BuildTool.setTool" + parameter="Create" /> + </button> <button follows="left|top" height="20" @@ -126,7 +142,11 @@ name="button land" picture_style="true" tool_tip="Land" - width="20" /> + width="20"> + <button.commit_callback + function="BuildTool.setTool" + parameter="Land" /> + </button> <text type="string" text_color="LabelSelectedDisabledColor" @@ -160,6 +180,8 @@ label="Pan (Ctrl-Shift)" layout="topleft" name="radio pan" /> + <radio_group.commit_callback + function="BuildTool.commitRadioFocus"/> </radio_group> <slider_bar follows="left|top" @@ -171,7 +193,10 @@ top_delta="-2" left_delta="100" name="slider zoom" - width="134" /> + width="134"> + <slider_bar.commit_callback + function="BuildTool.commitZoom"/> + </slider_bar> <radio_group left="10" height="70" @@ -193,6 +218,8 @@ label="Spin (Ctrl-Shift)" layout="topleft" name="radio spin" /> + <radio_group.commit_callback + function="BuildTool.commitRadioMove"/> </radio_group> <radio_group follows="left|top" @@ -220,6 +247,8 @@ label="Select Texture" layout="topleft" name="radio select face" /> + <radio_group.commit_callback + function="BuildTool.commitRadioEdit"/> </radio_group> <check_box left="10" @@ -227,7 +256,10 @@ control_name="EditLinkedParts" label="Edit linked" layout="topleft" - name="checkbox edit linked parts" /> + name="checkbox edit linked parts" > + <check_box.commit_callback + function="BuildTool.selectComponent"/> + </check_box> <combo_box height="19" left="10" @@ -248,6 +280,8 @@ label="Reference ruler" name="Reference" value="Reference" /> + <combo_box.commit_callback + function="BuildTool.gridMode"/> </combo_box> <check_box control_name="ScaleUniform" @@ -286,7 +320,10 @@ name="Options..." tool_tip="Set the Grid Options" width="26" - height="22" /> + height="22" > + <button.commit_callback + function="BuildTool.gridOptions"/> + </button> <button follows="left|top" height="20" @@ -597,8 +634,9 @@ name="radio revert" top_delta="15" width="114" /> + <radio_group.commit_callback + function="BuildTool.commitRadioLand"/> </radio_group> - <text type="string" length="1" @@ -624,6 +662,7 @@ Size </text> <slider_bar + control_name ="LandBrushSize" follows="left|top" height="19" initial_value="2.0" @@ -656,7 +695,10 @@ min_val="-1" name="slider force" top_delta="-3" - width="80" /> + width="80" > + <slider_bar.commit_callback + function="BuildTool.LandBrushForce"/> + </slider_bar> <button follows="left|top" font="SansSerifSmall" @@ -668,7 +710,10 @@ left="135" name="button apply to selection" tool_tip="Modify Selected Land" - width="78" /> + width="78"> + <button.commit_callback + function="BuildTool.applyToSelection"/> + </button> <text type="string" text_color="LabelSelectedDisabledColor" @@ -2215,7 +2260,7 @@ left="10" name="texture control" tool_tip="Click to choose a picture" - top="10" + top="8" width="64" /> <color_swatch border_color="0.45098 0.517647 0.607843 1" @@ -2237,7 +2282,7 @@ layout="topleft" left_pad="20" name="color trans" - top="10" + top="6" width="100"> Transparency % </text> @@ -2261,7 +2306,7 @@ layout="topleft" left_delta="0" name="glow label" - top_pad="4" + top_pad="2" width="80"> Glow </text> @@ -2281,7 +2326,7 @@ layout="topleft" left_delta="0" name="checkbox fullbright" - top_pad="7" + top_pad="4" width="81" /> <text type="string" @@ -2291,7 +2336,7 @@ layout="topleft" left="10" name="tex gen" - top_pad="10" + top_pad="5" width="87"> Mapping </text> @@ -2439,6 +2484,40 @@ name="weave" value="weave" /> </combo_box> + <!-- + <line_editor + bevel_style="in" + border_style="line" + border_thickness="1" + follows="left|top" + height="16" + layout="topleft" + left="10" + max_length="63" + name="Home Url" + select_on_focus="true" + top="134" + width="250" /> + <check_box + height="16" + label="Media Face" + layout="topleft" + left_delta="0" + name="has media" + top_pad="6" + width="70" /> + <button + follows="left|top" + font="SansSerifSmall" + height="20" + label="Set Media Info" + label_selected="Set Media Info" + layout="topleft" + left_pad="60" + name="media info set" + top_delta="-4" + width="120" /> +--> <text type="string" length="1" @@ -2447,7 +2526,7 @@ layout="topleft" left="10" name="tex scale" - top_pad="15" + top_pad="5" width="200"> Repeats per Face </text> @@ -2461,7 +2540,7 @@ left="20" max_val="100" name="TexScaleU" - top_pad="10" + top_pad="6" width="160" /> <check_box height="19" @@ -2469,7 +2548,7 @@ layout="topleft" left_pad="10" name="checkbox flip s" - top_delta="1" + top_delta="0" width="70" /> <spinner follows="left|top" @@ -2489,61 +2568,43 @@ layout="topleft" left_pad="10" name="checkbox flip t" - top_delta="1" + top_delta="0" width="70" /> - <text - type="string" - length="1" - follows="left|top" - height="10" - layout="topleft" - left="10" - name="tex rotate" - top_pad="20" - width="102"> - Rotation (degrees) - </text> + <spinner decimal_digits="2" follows="left|top" height="19" increment="1" initial_value="0" + label="Rotation (degrees)" layout="topleft" - left_delta="102" + label_width="100" + left="10" max_val="9999" min_val="-9999" name="TexRot" - top_delta="0" - width="68" /> - <text - type="string" - length="1" - follows="left|top" - height="10" - layout="topleft" - left="10" - name="rpt" - top_pad="0" - width="160"> - Repeats Per Meter - </text> + top_delta="25" + width="170" /> + <spinner decimal_digits="1" follows="left|top" height="19" initial_value="1" + label="Repeats Per Meter" layout="topleft" - left_delta="102" + label_width="100" + left="10" max_val="10" min_val="0.1" name="rptctrl" - top_delta="0" - width="68" /> + top_delta="20" + width="170" /> <button follows="left|top" font="SansSerifSmall" - height="22" + height="18" label="Apply" label_selected="Apply" layout="topleft" @@ -2558,7 +2619,7 @@ layout="topleft" left="10" name="tex offset" - top_pad="20" + top_delta="20" width="200"> Texture Offset </text> @@ -2572,7 +2633,7 @@ left="20" min_val="-1" name="TexOffsetU" - top_pad="10" + top_pad="5" width="160" /> <spinner follows="left|top" @@ -2584,10 +2645,9 @@ left_delta="0" min_val="-1" name="TexOffsetV" - top_pad="2" + top_pad="1" width="160" /> -<!--TODO: KILL THIS--> - <!-- <text + <text type="string" length="1" follows="left|top" @@ -2595,7 +2655,7 @@ layout="topleft" left="10" name="textbox autofix" - top="332" + top_pad="4" width="160"> Align media texture (must load first) @@ -2607,10 +2667,75 @@ label="Align" label_selected="Align" layout="topleft" - left="112" + left="122" name="button align" - top="340" - width="68" />--> + top_pad="-19" + width="68" /> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left="10" + top_pad="0" + name="media_tex" + width="100"> + Media: + </text> + <line_editor + follows="left|top|right" + height="18" + layout="topleft" + left="20" + max_length="63" + name="media_info" + select_on_focus="true" + top_delta="12" + width="230" /> + <button + follows="left|top" + font="SansSerifSmall" + height="13" + width="13" + image_unselected="add_btn.tga" + label="" + layout="topleft" + left="20" + name="add_media" + top_pad="3"> + <button.commit_callback + function="BuildTool.AddMedia"/> + </button> + <button + follows="left|top" + font="SansSerifSmall" + height="13" + width="13" + image_unselected="del_btn.tga" + label="" + layout="topleft" + left_pad="10" + name="delete_media" + top_delta="0" + left_delta="10" > + <button.commit_callback + function="BuildTool.DeleteMedia"/> + </button> + <button + follows="left|top" + font="SansSerifSmall" + height="15" + width="15" + image_unselected="gear.tga" + label="" + layout="topleft" + name="edit_media" + top_delta="0" + left_delta="190"> + <button.commit_callback + function="BuildTool.EditMedia"/> + </button> </panel> <panel border="false" @@ -2642,13 +2767,13 @@ width="130" /> <panel_inventory follows="left|top" - height="310" + height="210" layout="topleft" left="10" name="contents_inventory" top="50" width="260" /> - </panel> + </panel> </tab_container> <panel follows="left|top" diff --git a/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml b/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml new file mode 100644 index 0000000000..0eb2c5e1be --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_minimize="false"
+ height="108"
+ layout="topleft"
+ name="whitelist_entry"
+ width="390">
+
+ <text type="string" length="1" bottom="20" follows="top|left" height="15" layout="topleft"
+ left="10" name="media_label" top="20">
+ Enter a URL or URL pattern to add to the list of allowed domains
+ </text>
+
+ <line_editor bottom_delta="40" enabled="true" follows="left|top" font="SansSerif"
+ height="20" left="10" name="whitelist_entry"
+ tool_tip="Enter a URL or URL pattern to White List"
+ width="350" />
+
+ <button follows="top|left" height="20" font="SansSerifSmall" label="OK"
+ layout="topleft" left="10" name="ok_btn" bottom_delta="28" width="64" />
+
+ <button follows="top|left" height="20" font="SansSerifSmall" label="Cancel"
+ layout="topleft" left_pad="5" name="cancel_btn" bottom_delta="0" width="64" />
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml new file mode 100644 index 0000000000..d9cba27b88 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_teleport_history_item.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Teleport History Item Context Menu"> + <menu_item_call + label="Teleport" + layout="topleft" + name="Teleport"> + <menu_item_call.on_click + function="TeleportHistory.Teleport" /> + </menu_item_call> + <menu_item_call + label="More Information" + layout="topleft" + name="More Information"> + <menu_item_call.on_click + function="TeleportHistory.MoreInformation" /> + </menu_item_call> + <menu_item_call + label="Copy" + layout="topleft" + name="Copy"> + <menu_item_call.on_click + function="TeleportHistory.Copy" /> + </menu_item_call> + <menu_item_call + label="Make Landmark" + layout="topleft" + name="Make Landmark"> + <menu_item_call.on_click + function="TeleportHistory.MakeLandmark" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_teleport_history_tab.xml b/indra/newview/skins/default/xui/en/menu_teleport_history_tab.xml new file mode 100644 index 0000000000..ecc1d8a954 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_teleport_history_tab.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Teleport History Item Context Menu"> + <menu_item_call + label="Open" + layout="topleft" + name="TabOpen"> + <menu_item_call.on_click + function="TeleportHistory.TabOpen" /> + </menu_item_call> + <menu_item_call + label="Close" + layout="topleft" + name="TabClose"> + <menu_item_call.on_click + function="TeleportHistory.TabClose" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 10aa23b715..2c77f61da6 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -128,13 +128,13 @@ function="World.SetAway" /> </menu_item_call> <menu_item_separator - layout="topleft"/> + layout="topleft"/> <menu_item_call label="Set Busy" layout="topleft" name="Set Busy"> <menu_item_call.on_click - function="World.SetBusy"/> + function="World.SetBusy"/> </menu_item_call> </menu> <menu_item_separator @@ -1042,15 +1042,6 @@ <menu_item_separator layout="topleft" /> <menu_item_call - label="Report Bug..." - layout="topleft" - name="ReportBug"> - <menu_item_call.on_click - function="PromptShowURL" - name="ReportBug_url" - parameter="hud,http://help.secondlife.com/en/bugreport/" /> - </menu_item_call> - <menu_item_call label="Report Abuse..." layout="topleft" name="Report Abuse"> @@ -2771,15 +2762,6 @@ function="Advanced.ShowDebugSettings" parameter="skin" /> </menu_item_call> - <menu_item_check - label="Editable UI" - layout="topleft" - name="Editable UI"> - <menu_item_check.on_check - function="Advanced.CheckEditableUI" /> - <menu_item_check.on_click - function="Advanced.ToggleEditableUI" /> - </menu_item_check> <menu_item_call label="Dump SelectMgr" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 044194a4ed..fe088b43be 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -646,6 +646,19 @@ This entire region is damage enabled. Scripts must be allowed to run for weapons to work. </notification> +<notification + icon="alertmodal.tga" + name="MultipleFacesSelected" + type="alertmodal"> + Multiple faces are currently selected. +If you continue this action, separate instances of media will be set on multiple faces of the object. +To place the media on only one face, choose Select Texture and click on the desired face of that object then click Add. + <usetemplate + name="okcancelignore" + notext="Cancel" + yestext="OK"/> + </notification> + <notification icon="alertmodal.tga" name="MustBeInParcel" @@ -783,6 +796,20 @@ There is no reimbursement for fees paid. yestext="OK"/> </notification> + +<notification + icon="alertmodal.tga" + name="DeleteMedia" + type="alertmodal"> +You have selected to delete the media associated with this face. +Are you sure you want to continue? + <usetemplate + ignoretext="Confirm before I delete media from an object" + name="okcancelignore" + notext="No" + yestext="Yes"/> + </notification> + <notification icon="alertmodal.tga" name="ClassifiedSave" @@ -1215,7 +1242,7 @@ Please move all objects to be acquired onto the same region. type="alertmodal"> [EXTRA] -Go to [_URL] for information on purchasing currency? +Go to [_URL] for information on purchasing L$? <url option="0" name="url"> http://secondlife.com/app/currency/ @@ -1691,7 +1718,6 @@ No Group selected. type="alertmodal"> Unable to deed land: Cannot find the region this land is in. -Please use Help > Report Bug to report this. </notification> <notification @@ -1772,8 +1798,6 @@ Parcels you own appear in green. type="alertmodal"> Unable to abandon land: Cannot find the region this land is in. - -Please use Help > Report Bug to report this. </notification> <notification @@ -1846,8 +1870,6 @@ Divide land? type="alertmodal"> Unable to divide land: Cannot find the region this land is in. - -Please use Help > Report Bug to report this. </notification> <notification @@ -1856,8 +1878,6 @@ Please use Help > Report Bug to report this. type="alertmodal"> Unable to join land: Cannot find the region this land is in. - -Please use Help > Report Bug to report this. </notification> <notification @@ -1973,8 +1993,6 @@ Unable to save '[NAME]' to wearable file. You will need to free up so type="alertmodal"> Unable to save [NAME] to central asset store. This is usually a temporary failure. Please customize and save the wearable again in a few minutes. - -If this problem persists, please click on Help > Report Bug and provide details about your network setup. </notification> <notification @@ -2758,18 +2776,6 @@ Go to secondlife.com to manage your account? <notification icon="alertmodal.tga" - name="WebLaunchBugReport101" - type="alertmodal"> -Visit the [SECOND_LIFE] Wiki and learn how to report bugs correctly. - <usetemplate - ignoretext="Launch my browser to learn how to report a Bug" - name="okcancelignore" - notext="Cancel" - yestext="OK"/> - </notification> - - <notification - icon="alertmodal.tga" name="WebLaunchSecurityIssues" type="alertmodal"> Visit the [SECOND_LIFE] Wiki for details of how to report a security issue. @@ -4275,22 +4281,6 @@ The resolution of this report applies only to this Region. Residents' acces <notification icon="alertmodal.tga" - name="HelpReportBug" - type="alertmodal"> -Use this tool to *only* report technical features that do not perform as described or expected, please provide as much detail as possible. -You may reply to the auto-response email to add more details to your report. - -All bug reports are investigated and assessed. No email response will be sent. - -If you are having a technical difficulty, please contact Support at: - -http://secondlife.com/community/support.php - -Note: Incomplete reports will not be investigated - </notification> - - <notification - icon="alertmodal.tga" name="HelpReportAbuseSelectCategory" type="alertmodal"> Please select a category for this abuse report. @@ -4299,14 +4289,6 @@ Selecting a category helps us file and process abuse reports. <notification icon="alertmodal.tga" - name="HelpReportBugSelectCategory" - type="alertmodal"> -Please select a category for this bug. -Selecting a category helps us file and process bug reports. - </notification> - - <notification - icon="alertmodal.tga" name="HelpReportAbuseAbuserNameEmpty" type="alertmodal"> Please enter the name of the abuser. @@ -4331,14 +4313,6 @@ Entering an accurate summary helps us file and process abuse reports. <notification icon="alertmodal.tga" - name="HelpReportBugSummaryEmpty" - type="alertmodal"> -Please enter a summary of the bug. -Entering an accurate summary helps us file and process bug reports. - </notification> - - <notification - icon="alertmodal.tga" name="HelpReportAbuseDetailsEmpty" type="alertmodal"> Please enter a detailed description of the abuse that took place. @@ -4348,15 +4322,6 @@ Entering an accurate description helps us file and process abuse reports. <notification icon="alertmodal.tga" - name="HelpReportBugDetailsEmpty" - type="alertmodal"> -Please enter a detailed description of the bug. -Be as specific as you can, including steps to reproduce the bug if possible. -Entering an accurate description helps us file and process bug reports. - </notification> - - <notification - icon="alertmodal.tga" name="HelpReportAbuseContainsCopyright" type="alertmodal"> Dear Resident, @@ -6547,6 +6512,17 @@ Click Accept to join the chat or Decline to decline the invitation. Click Block Unable to find the help topic for this element. </notification> + <notification + icon="alertmodal.tga" + name="ObjectMediaFailure" + type="alertmodal"> +Server Error: Media update or get failed. +'[ERROR]' + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + <global name="UnsupportedCPU"> - Your CPU speed does not meet the minimum requirements. </global> diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml index 90b331a39f..cd7e340ff1 100644 --- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml +++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml @@ -79,7 +79,6 @@ label="Move" layout="topleft" name="movement_btn" - tab_stop="false" tool_tip="Shows/Hide Movement controls" top="6" width="70"> @@ -117,7 +116,6 @@ label="View" layout="topleft" left="0" - tab_stop="false" tool_tip="Shows/Hide Camera controls" top="6" name="camera_btn" @@ -133,7 +131,6 @@ height="20" width="20" left_pad="0" - tab_stop="false" is_toggle="true" picture_style="true" image_selected="toggle_button_selected" diff --git a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml index c4c8aa24c4..fb4ce436e8 100644 --- a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml +++ b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml @@ -28,7 +28,7 @@ width="25" height="25" label="" - follows="top|left" + follows="top|right" image_overlay="BackArrow_Off" tab_stop="false" /> <text @@ -41,6 +41,7 @@ text_color="white" follows="top|left|right" mouse_opaque="true" + use_ellipses="true" name="group_name">(Loading...)</text> <line_editor follows="left|top" diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index e7fb3fa208..c96c296057 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -26,9 +26,8 @@ layout="topleft" left="0" name="login_html" - hide_loading="true" right="-1" - start_url="data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody bgcolor=%22#000000%22 text=%22ffffff%22%3E%3Ch1%3E%3Ctt%3Eloading...%3C/tt%3E%3C/h1%3E %3C/body%3E %3C/html%3E" + start_url="" top="1" /> <text type="string" @@ -52,7 +51,7 @@ max_length="31" name="first_name_edit" select_on_focus="true" - tool_tip="Second Life First Name" + tool_tip="[SECOND_LIFE] First Name" top_pad="2" width="120" /> <text @@ -78,6 +77,7 @@ max_length="31" name="last_name_edit" select_on_focus="true" + tool_tip="[SECOND_LIFE] Last Name" top_pad="2" width="120" /> <text diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_general.xml b/indra/newview/skins/default/xui/en/panel_media_settings_general.xml new file mode 100644 index 0000000000..b66aad1853 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_media_settings_general.xml @@ -0,0 +1,199 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + border="true" + enabled="true" + follows="left|top|right|bottom" + height="500" + label="General" + left="102" + mouse_opaque="true" + name="Media Settings General" + width="365"> + + <text + bottom_delta="-17" + follows="top|left" + height="15" + left="10" + name=""> + Home URL: + </text> + <line_editor + bottom_delta="-21" + enabled="true" + follows="left|top" + font="SansSerif" + height="20" + left="10" + name="home_url" + tool_tip="The home URL for this media source" + width="340"> + <!-- <line_editor.commit_callback + function="Media.CommitHomeURL"/> --> + </line_editor> + <text + bottom_delta="-20" + follows="top|left" + height="15" + left="10" + name="current_url_label"> + Current URL: + </text> + <line_editor + bottom_delta="-20" + enabled="false" + follows="left|top" + font="SansSerif" + height="20" + left="10" + name="current_url" + tool_tip="The current URL for this media source" + value="" + width="340" /> + <button + bottom_delta="-20" + follows="top|left" + height="20" + label="Reset" + left_delta="233" + name="current_url_reset_btn" + width="110" > + <button.commit_callback + function="Media.ResetCurrentUrl"/> + </button> + + <web_browser + border_visible="false" + bottom_delta="-120" + follows="top|left" + left="120" + name="preview_media" + width="128" + height="128" + start_url="about:blank" + decouple_texture_size="true" /> + + <text + bottom_delta="-15" + follows="top|left" + height="15" + left="164" + name=""> + Preview + </text> + + <text + bottom_delta="-20" + follows="top|left" + height="15" + left="10" + name=""> + Controls: + </text> + <combo_box + allow_text_entry="false" + bottom_delta="-20" + enabled="true" + follows="left|top" + height="18" + left="10" + max_chars="20" + mouse_opaque="true" + name="controls" + width="120"> + <combo_item + type="string" + length="1" + enabled="true" + name="Standard" + value="Standard"> + Standard + </combo_item> + <combo_item + type="string" + length="1" + enabled="true" + name="Mini" + value="Mini"> + Mini + </combo_item> + </combo_box> + + <check_box + bottom_delta="-25" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Auto Loop" + left="10" + mouse_opaque="true" + name="auto_loop" + radio_style="false" + width="150" /> + + <check_box + bottom_delta="-25" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="First Click Interacts" + left_delta="0" + mouse_opaque="true" + name="first_click_interact" + radio_style="false" + width="150" /> + + <check_box + bottom_delta="-25" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Auto Zoom" + left_delta="0" + mouse_opaque="true" + name="auto_zoom" + radio_style="false" + width="150" /> + + <check_box bottom_delta="-25" enabled="true" follows="left|top" font="SansSerifSmall" + height="16" initial_value="false" + label="Use Default Alternative Image" left="10" mouse_opaque="true" + name="alt_image_enable" radio_style="false" width="150" /> + + <check_box bottom_delta="-25" enabled="true" follows="left|top" font="SansSerifSmall" + height="16" initial_value="false" + label="Auto Play Media" left="10" mouse_opaque="true" + name="auto_play" radio_style="false" width="150" /> + <text bottom_delta="-14" follows="top|left" height="15" left="30" width="340" + enabled="false" name=""> + Note: Parcel Owners & Residents can override this setting + </text> + + <check_box bottom_delta="-25" enabled="true" follows="left|top" font="SansSerifSmall" + height="16" initial_value="false" + label="Auto Scale Media on Face of Object" left="10" mouse_opaque="true" + name="auto_scale" radio_style="false" width="150" /> + <text bottom_delta="-20" follows="top|left" height="15" left="30" name=""> + Size: + </text> + <spinner bottom_delta="0" + decimal_digits="0" enabled="true" follows="left|top" height="16" + increment="1" initial_val="256" label="" label_width="0" + left_delta="40" max_val="2000" min_val="0" mouse_opaque="true" + name="width_pixels" width="50" /> + <text bottom_delta="0" follows="top|left" height="15" left_delta="60" name=""> + X + </text> + <spinner bottom_delta="0" + decimal_digits="0" enabled="true" follows="left|top" height="16" + increment="1" initial_val="256" label="" label_width="0" + left_delta="20" max_val="2000" min_val="0" mouse_opaque="true" + name="height_pixels" width="50" /> + +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml b/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml new file mode 100644 index 0000000000..f11364874a --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_media_settings_permissions.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel border="true" enabled="true" follows="left|top|right|bottom" + height="500" label="Controls" left="102" mouse_opaque="true" + name="Media settings for controls" width="365"> + + <text bottom_delta="-50" follows="top|left" height="15" left="10" name="" enabled="false"> + Owner + </text> + <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" + height="16" initial_value="false" + label="Disable Navigation & Interactivity" left="30" mouse_opaque="true" + name="perms_owner_interact" radio_style="false" width="250" /> + + <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" + height="16" initial_value="false" + label="Hide Control Bar" left="30" mouse_opaque="true" + name="perms_owner_control" radio_style="false" width="250" /> + + <text bottom_delta="-36" follows="top|left" height="15" left="10" name="perms_group_name_label" enabled="false"> + Group + </text> + <name_box bottom_delta="-5" enabled="false" follows="left|top" font="SansSerif" + height="20" left="60" name="perms_group_name" + value ="" + width="200" /> + <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" + height="16" initial_value="false" + label="Disable Navigation & Interactivity" left="30" mouse_opaque="true" + name="perms_group_interact" radio_style="false" width="250" /> + + <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" + height="16" initial_value="false" + label="Hide Control Bar" left="30" mouse_opaque="true" + name="perms_group_control" radio_style="false" width="250" /> + + <text bottom_delta="-36" follows="top|left" height="15" left="10" name="" enabled="false"> + Anyone + </text> + <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" + height="16" initial_value="false" + label="Disable Navigation & Interactivity" left="30" mouse_opaque="true" + name="perms_anyone_interact" radio_style="false" width="250" /> + + <check_box bottom_delta="-22" enabled="true" follows="left|top" font="SansSerifSmall" + height="16" initial_value="false" + label="Hide Control Bar" left="30" mouse_opaque="true" + name="perms_anyone_control" radio_style="false" width="250" /> + +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_security.xml b/indra/newview/skins/default/xui/en/panel_media_settings_security.xml new file mode 100644 index 0000000000..695e956e41 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_media_settings_security.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + border="true" + enabled="true" + follows="left|top|right|bottom" + height="500" + label="Security" + left="102" + mouse_opaque="true" + name="Media Settings Security" + width="365"> + <check_box + bottom_delta="-40" + enabled="true" + follows="left|top" + font="SansSerifSmall" + height="16" + initial_value="false" + label="Only Allow Access to Specified URLs (by prefix)" + left="10" + mouse_opaque="true" + name="whitelist_enable" + radio_style="false" + width="250" /> + <scroll_list + follows="top|left" + height="200" + left="30" + name="whitelist" + width="315" + enabled="true" /> + <button + bottom_delta="-30" + follows="top|left" + height="20" + label="Add" + left="30" + name="whitelist_add" + width="70" + enabled="true"> + <button.commit_callback + function="Media.whitelistAdd"/> + </button> + <button + bottom_delta="0" + follows="top|left" + height="20" + label="Delete" + left="275" + name="whitelist_del" + width="70" + enabled="true"> + <button.commit_callback + function="Media.whitelistDelete"/> + </button> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml index 683a54b366..4088d96ebf 100644 --- a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml @@ -35,6 +35,8 @@ follows="right" height="20" speak_button.font="SansSerifMedium" + speak_button.tab_stop="true" + show_button.tab_stop="true" layout="topleft" left_pad="5" name="talk" diff --git a/indra/newview/skins/default/xui/en/panel_notes.xml b/indra/newview/skins/default/xui/en/panel_notes.xml index 58ebac2a84..2056ec14d5 100644 --- a/indra/newview/skins/default/xui/en/panel_notes.xml +++ b/indra/newview/skins/default/xui/en/panel_notes.xml @@ -2,7 +2,7 @@ <panel bevel_style="in" follows="left|top|right|bottom" - height="420" + height="460" label="Notes & Privacy" layout="topleft" left="0" @@ -16,7 +16,7 @@ layout="topleft" left="0" top="0" - height="420" + height="430" width="313" border_size="0"> <panel diff --git a/indra/newview/skins/default/xui/en/panel_picks.xml b/indra/newview/skins/default/xui/en/panel_picks.xml index d0bde77cf2..1bd1953397 100644 --- a/indra/newview/skins/default/xui/en/panel_picks.xml +++ b/indra/newview/skins/default/xui/en/panel_picks.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel follows="left|top|right|bottom" - height="515" + height="555" label="Picks" layout="topleft" left="0" @@ -11,7 +11,7 @@ <flat_list_view color="DkGray2" follows="left|top|right|bottom" - height="495" + height="465" layout="topleft" left="0" name="picks_list" 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 8f710545d5..06ecfdc995 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -261,17 +261,17 @@ My Avatar: label="Show script errors" layout="topleft" left="30" - name="first_person_avatar_visible" + name="show_script_errors" width="256" top_pad="10"/> <radio_group - enabled_control="EnableVoiceChat" - control_name="VoiceEarLocation" + enabled_control="EnableShowScriptErrors" + control_name="ShowScriptErrorsLocation" draw_border="false" height="40" layout="topleft" left_delta="50" - name="ear_location" + name="show_location" top_pad="5" width="364"> <radio_item diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml index 56ba5970f2..02d179d503 100644 --- a/indra/newview/skins/default/xui/en/panel_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_profile.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel follows="all" - height="515" + height="560" label="Profile" layout="topleft" left="0" @@ -25,7 +25,7 @@ <scroll_container color="DkGray2" follows="left|top|right|bottom" - height="515" + height="500" min_height="300" layout="topleft" name="profile_scroll" @@ -265,6 +265,7 @@ left="0" name="profile_buttons_panel" top_pad="0" + height="25" width="313"> <button follows="bottom|left" @@ -316,6 +317,7 @@ name="profile_me_buttons_panel" top_pad="0" visible="false" + height="25" width="313"> <button follows="bottom|left" diff --git a/indra/newview/skins/default/xui/en/panel_profile_view.xml b/indra/newview/skins/default/xui/en/panel_profile_view.xml index cbe646f3cc..606535115d 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_view.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_view.xml @@ -2,7 +2,7 @@ <panel background_visible="true" follows="all" - height="660" + height="570" layout="topleft" min_height="350" min_width="240" @@ -50,7 +50,7 @@ width="25" /> <tab_container follows="left|top|right|bottom" - height="660" + height="560" layout="topleft" left="10" name="tabs" diff --git a/indra/newview/skins/default/xui/en/panel_script_ed.xml b/indra/newview/skins/default/xui/en/panel_script_ed.xml index 5738879c5a..a3c714ce72 100644 --- a/indra/newview/skins/default/xui/en/panel_script_ed.xml +++ b/indra/newview/skins/default/xui/en/panel_script_ed.xml @@ -184,9 +184,9 @@ layout="topleft" name="Help..." /> <menu_item_call - label="LSL Wiki Help..." + label="Keyword Help..." layout="topleft" - name="LSL Wiki Help..." /> + name="Keyword Help..." /> </menu> </menu_bar> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_side_tray_tab_caption.xml b/indra/newview/skins/default/xui/en/panel_side_tray_tab_caption.xml index f25c4bfbba..aa76a61c15 100644 --- a/indra/newview/skins/default/xui/en/panel_side_tray_tab_caption.xml +++ b/indra/newview/skins/default/xui/en/panel_side_tray_tab_caption.xml @@ -19,4 +19,17 @@ top="4" value="Side Panel" width="255" /> + <button + follows="left|right|top" + font="SansSerif" + height="23" + label="?" + layout="topleft" + name="show_help" + top="5" + right="-8" + width="28"> + <button.commit_callback + function="Button.ShowHelp" /> + </button> </panel> 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 c178554287..f6ffd2e4ee 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -52,7 +52,7 @@ left="-210" name="buycurrency" picture_style="true" - tool_tip="My Balance / Buy currency" + tool_tip="My Balance / Buy L$" top="0" width="117" /> <text diff --git a/indra/newview/skins/default/xui/en/panel_teleport_history.xml b/indra/newview/skins/default/xui/en/panel_teleport_history.xml index a0fc986423..aa95a2baef 100644 --- a/indra/newview/skins/default/xui/en/panel_teleport_history.xml +++ b/indra/newview/skins/default/xui/en/panel_teleport_history.xml @@ -111,7 +111,7 @@ width="380"> </flat_list_view> </accordion_tab> - + <accordion_tab can_resize="false" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 13a53a4ce3..1e85cac539 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -93,7 +93,6 @@ <string name="BUTTON_RESTORE">Restore</string> <string name="BUTTON_MINIMIZE">Minimize</string> <string name="BUTTON_TEAR_OFF">Tear Off</string> - <string name="BUTTON_EDIT">Edit</string> <string name="BUTTON_DOCK">Dock</string> <string name="BUTTON_UNDOCK">Undock</string> <string name="BUTTON_HELP">Show Help</string> @@ -308,112 +307,115 @@ Sleeps script for [SLEEP_TIME] seconds. <string name="LSLTipText_llSin"> float llSin(float theta) -theta in radians +Returns the sine of theta (theta in radians) </string> <string name="LSLTipText_llCos"> float llCos(float theta) -theta in radians +Returns the cosine of theta (theta in radians) </string> <string name="LSLTipText_llTan"> float llTan(float theta) -theta radians +Returns the tangent of theta (theta in radians) </string> <string name="LSLTipText_llAtan2"> float llAtan2(float y, float x) +Returns the arctangent2 of y, x </string> <string name="LSLTipText_llSqrt"> float llSqrt(float val) -returns 0 and triggers a Math Error for imaginary results +Returns the square root of val, or returns 0 and triggers a Math Error for imaginary results </string> <string name="LSLTipText_llPow"> float llPow(float base, float exponent) -returns 0 and triggers Math Error for imaginary results +Returns the base raised to the power exponent, or returns 0 and triggers Math Error for imaginary results </string> <string name="LSLTipText_llAbs"> integer llAbs(integer val) +Returns the positive version of val </string> <string name="LSLTipText_llFabs"> float llFabs(float val) +Returns the positive version of val </string> <string name="LSLTipText_llFrand"> float llFrand(float mag) -returns random number in range [0,mag) +Returns a pseudo random number in the range [0,mag) or (mag,0] </string> <string name="LSLTipText_llFloor"> integer llFloor(float val) -returns largest integer value <= val +Returns largest integer value <= val </string> <string name="LSLTipText_llCeil"> integer llCeil(float val) -returns smallest integer value >= val +Returns smallest integer value >= val </string> <string name="LSLTipText_llRound"> integer llRound(float val) -returns val rounded to the nearest integer +Returns val rounded to the nearest integer </string> <string name="LSLTipText_llVecMag"> float llVecMag(vector v) -returns the magnitude of v +Returns the magnitude of v </string> <string name="LSLTipText_llVecNorm"> vector llVecNorm(vector v) -returns the v normalized +Returns the v normalized </string> <string name="LSLTipText_llVecDist"> float llVecDist(vector v1, vector v2) -returns the 3D distance between v1 and v2 +Returns the 3D distance between v1 and v2 </string> <string name="LSLTipText_llRot2Euler"> vector llRot2Euler(rotation q) -returns the Euler representation (roll, pitch, yaw) of q +Returns the Euler representation (roll, pitch, yaw) of q </string> <string name="LSLTipText_llEuler2Rot"> rotation llEuler2Rot(vector v) -returns the rotation representation of Euler Angles v +Returns the rotation representation of Euler Angles v </string> <string name="LSLTipText_llAxes2Rot"> rotation llAxes2Rot(vector fwd, vector left, vector up) -returns the rotation defined by the coordinate axes +Returns the rotation defined by the coordinate axes </string> <string name="LSLTipText_llRot2Fwd"> vector llRot2Fwd(rotation q) -returns the forward vector defined by q +Returns the forward vector defined by q </string> <string name="LSLTipText_llRot2Left"> vector llRot2Left(rotation q) -returns the left vector defined by q +Returns the left vector defined by q </string> <string name="LSLTipText_llRot2Up"> vector llRot2Up(rotation q) -returns the up vector defined by q +Returns the up vector defined by q </string> <string name="LSLTipText_llRotBetween"> rotation llRotBetween(vector v1, vector v2) -returns the rotation to rotate v1 to v2 +Returns the rotation to rotate v1 to v2 </string> <string name="LSLTipText_llWhisper"> llWhisper(integer channel, string msg) -whispers msg on channel +Whispers the text of msg on channel </string> <string name="LSLTipText_llSay"> llSay(integer channel, string msg) -says msg on channel +Says the text of msg on channel </string> <string name="LSLTipText_llShout"> llShout(integer channel, string msg) -shouts msg on channel +Shouts the text of msg on channel </string> <string name="LSLTipText_llListen"> integer llListen(integer channel, string name, key id, string msg) -sets a callback for msg on channel from name and id (name, id, and/or msg can be empty) and returns an identifier that can be used to deactivate or remove the listen +Sets a callback for msg on channel from name and id (name, id, and/or msg can be empty) and returns an identifier that can be used to deactivate or remove the listen </string> <string name="LSLTipText_llListenControl"> llListenControl(integer number, integer active) -makes a listen event callback active or inactive +Makes a listen event callback active or inactive </string> <string name="LSLTipText_llListenRemove"> llListenRemove(integer number) -removes listen event callback number +Removes listen event callback number </string> <string name="LSLTipText_llSensor"> llSensor(string name, key id, integer type, float range, float arc) @@ -421,43 +423,43 @@ Performs a single scan for name and id with type (AGENT, ACTIVE, PASSIVE, and/or </string> <string name="LSLTipText_llSensorRepeat"> llSensorRepeat(string name, key id, integer type, float range, float arc, float rate) -sets a callback for name and id with type (AGENT, ACTIVE, PASSIVE, and/or SCRIPTED) within range meters and arc radians of forward vector (name, id, and/or keytype can be empty or 0) and repeats every rate seconds +Sets a callback for name and id with type (AGENT, ACTIVE, PASSIVE, and/or SCRIPTED) within range meters and arc radians of forward vector (name, id, and/or keytype can be empty or 0) and repeats every rate seconds </string> <string name="LSLTipText_llSensorRemove"> llSensorRemove() -removes sensor +Removes the sensor setup by llSensorRepeat </string> <string name="LSLTipText_llDetectedName"> string llDetectedName(integer number) -returns the name of detected object number (returns empty string if number is not valid sensed object) +Returns the name of detected object number (returns empty string if number is not a valid sensed object) </string> <string name="LSLTipText_llDetectedKey"> key llDetectedKey(integer number) -returns the key of detected object number (returns empty key if number is not valid sensed object) +Returns the key of detected object number (returns empty key if number is not a valid sensed object) </string> <string name="LSLTipText_llDetectedOwner"> key llDetectedOwner(integer number) -returns the key of detected object's owner (returns empty key if number is not valid sensed object) +Returns the key of detected object's owner (returns empty key if number is not a valid sensed object) </string> <string name="LSLTipText_llDetectedType"> integer llDetectedType(integer number) -returns the type (AGENT, ACTIVE, PASSIVE, SCRIPTED) of detected object (returns 0 if number is not valid sensed object) +Returns the type (AGENT, ACTIVE, PASSIVE, SCRIPTED) of detected object (returns 0 if number is not a valid sensed object) </string> <string name="LSLTipText_llDetectedPos"> vector llDetectedPos(integer number) -returns the position of detected object number (returns <0,0,0> if number is not valid sensed object) +Returns the position of detected object number (returns <0,0,0> if number is not a valid sensed object) </string> <string name="LSLTipText_llDetectedVel"> vector llDetectedVel(integer number) -returns the velocity of detected object number (returns <0,0,0> if number is not valid sensed object) +Returns the velocity of detected object number (returns <0,0,0> if number is not a valid sensed object) </string> <string name="LSLTipText_llDetectedGrab"> vector llDetectedGrab(integer number) -returns the grab offset of the user touching object (returns <0,0,0> if number is not valid sensed object) +Returns the grab offset of the user touching object (returns <0,0,0> if number is not a valid sensed object) </string> <string name="LSLTipText_llDetectedRot"> rotation llDetectedRot(integer number) -returns the rotation of detected object number (returns <0,0,0,1> if number is not valid sensed object) +Returns the rotation of detected object number (returns <0,0,0,1> if number is not a valid sensed object) </string> <string name="LSLTipText_llDetectedGroup"> integer llDetectedGroup(integer number) @@ -465,127 +467,127 @@ Returns TRUE if detected object is part of same group as owner </string> <string name="LSLTipText_llDetectedLinkNumber"> integer llDetectedLinkNumber(integer number) -returns the link position of the triggered event for touches and collisions only +Returns the link position of the triggered event for touches and collisions only </string> <string name="LSLTipText_llDie"> llDie() -deletes the object +Deletes the object </string> <string name="LSLTipText_llGround"> -float llGround(vector v) -returns the ground height below the object position + v +float llGround(vector offset) +Returns the ground height below the object position + offset </string> <string name="LSLTipText_llCloud"> -float llCloud(vector v) -returns the cloud density at the object position + v +float llCloud(vector offset) +Returns the cloud density at the object position + offset </string> <string name="LSLTipText_llWind"> -vector llWind(vector v) -returns the wind velocity at the object position + v +vector llWind(vector offset) +Returns the wind velocity at the object position + offset </string> <string name="LSLTipText_llSetStatus"> llSetStatus(integer status, integer value) -sets status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB, STATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) to value +Sets status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB, STATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) to value </string> <string name="LSLTipText_llGetStatus"> integer llGetStatus(integer status) -gets value of status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB, STATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) +Returns value of status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB, STATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) </string> <string name="LSLTipText_llSetScale"> llSetScale(vector scale) -sets the scale +Sets the scale of the prim </string> <string name="LSLTipText_llGetScale"> vector llGetScale() -gets the scale +Returns the scale of the prim </string> <string name="LSLTipText_llSetColor"> llSetColor(vector color, integer face) -sets the color +Sets the color on face of the prim </string> <string name="LSLTipText_llGetAlpha"> float llGetAlpha(integer face) -gets the alpha +Returns the alpha of face </string> <string name="LSLTipText_llSetAlpha"> llSetAlpha(float alpha, integer face) -sets the alpha +Sets the alpha on face </string> <string name="LSLTipText_llGetColor"> vector llGetColor(integer face) -gets the color +Returns the color on face </string> <string name="LSLTipText_llSetTexture"> llSetTexture(string texture, integer face) -sets the texture of face +Sets the texture of face or ALL_SIDES </string> <string name="LSLTipText_llScaleTexture"> -llScaleTexture(float scales, float scalet, integer face) -sets the texture s, t scales for the chosen face +llScaleTexture(float u, float v, integer face) +Sets the texture u & v scales for the chosen face or ALL_SIDES </string> <string name="LSLTipText_llOffsetTexture"> -llOffsetTexture(float offsets, float offsett, integer face) -sets the texture s, t offsets for the chosen face +llOffsetTexture(float u, float v, integer face) +Sets the texture u & v offsets for the chosen face or ALL_SIDES </string> <string name="LSLTipText_llRotateTexture"> llRotateTexture(float rotation, integer face) -sets the texture rotation for the chosen face +Sets the texture rotation for the chosen face </string> <string name="LSLTipText_llGetTexture"> string llGetTexture(integer face) -gets the texture of face (if it's a texture in the object inventory, otherwise the key in a string) +Returns a string that is the texture on face (the inventory name if it is a texture in the prim's inventory, otherwise the key) </string> <string name="LSLTipText_llSetPos"> llSetPos(vector pos) -sets the position (if the script isn't physical) +Moves the object or prim towards pos without using physics (if the script isn't physical) </string> <string name="LSLTipText_llGetPos"> vector llGetPos() -gets the position (if the script isn't physical) +Returns the position of the task in region coordinates </string> <string name="LSLTipText_llGetLocalPos"> vector llGetLocalPos() -gets the position relative to the root (if the script isn't physical) +Returns the position relative to the root </string> <string name="LSLTipText_llSetRot"> llSetRot(rotation rot) -sets the rotation (if the script isn't physical) +Sets the rotation </string> <string name="LSLTipText_llGetRot"> rotation llGetRot() -gets the rotation (if the script isn't physical) +Returns the rotation relative to the region's axes </string> <string name="LSLTipText_llGetLocalRot"> rotation llGetLocalRot() -gets the rotation local to the root (if the script isn't physical) +Returns the rotation local to the root </string> <string name="LSLTipText_llSetForce"> llSetForce(vector force, integer local) -sets force on object, in local coords if local == TRUE (if the script is physical) +Applies force to the object (if the script is physical), in local coords if local == TRUE </string> <string name="LSLTipText_llGetForce"> vector llGetForce() -gets the force (if the script is physical) +Returns the force (if the script is physical) </string> <string name="LSLTipText_llTarget"> integer llTarget(vector position, float range) -set positions within range of position as a target and return an ID for the target +Sets positions within range of position as a target and return an ID for the target </string> <string name="LSLTipText_llTargetRemove"> llTargetRemove(integer number) -removes target number +Removes positional target number registered with llTarget </string> <string name="LSLTipText_llRotTarget"> integer llRotTarget(rotation rot, float error) -set rotations with error of rot as a rotational target and return an ID for the rotational target +Set rotations with error of rot as a rotational target and return an ID for the rotational target </string> <string name="LSLTipText_llRotTargetRemove"> llRotTargetRemove(integer number) -removes rotational target number +Removes rotational target number registered with llRotTarget </string> <string name="LSLTipText_llMoveToTarget"> llMoveToTarget(vector target, float tau) -critically damp to target in tau seconds (if the script is physical) +Critically damps to target in tau seconds (if the script is physical) </string> <string name="LSLTipText_llStopMoveToTarget"> llStopMoveToTarget() @@ -593,83 +595,83 @@ Stops critically damped motion </string> <string name="LSLTipText_llApplyImpulse"> llApplyImpulse(vector force, integer local) -applies impulse to object, in local coords if local == TRUE (if the script is physical) +Applies impulse to object (if the script is physical), in local coords if local == TRUE </string> <string name="LSLTipText_llApplyRotationalImpulse"> llApplyRotationalImpulse(vector force, integer local) -applies rotational impulse to object, in local coords if local == TRUE (if the script is physical) +Applies rotational impulse to object (if the script is physical), in local coords if local == TRUE </string> <string name="LSLTipText_llSetTorque"> llSetTorque(vector torque, integer local) -sets the torque of object, in local coords if local == TRUE (if the script is physical) +Sets the torque of object (if the script is physical), in local coords if local == TRUE </string> <string name="LSLTipText_llGetTorque"> vector llGetTorque() -gets the torque (if the script is physical) +Returns the torque (if the script is physical) </string> <string name="LSLTipText_llSetForceAndTorque"> llSetForceAndTorque(vector force, vector torque, integer local) -sets the force and torque of object, in local coords if local == TRUE (if the script is physical) +Sets the force and torque of object (if the script is physical), in local coords if local == TRUE </string> <string name="LSLTipText_llGetVel"> vector llGetVel() -gets the velocity +Returns the velocity of the object </string> <string name="LSLTipText_llGetAccel"> vector llGetAccel() -gets the acceleration +Returns the acceleration of the object relative to the region's axes </string> <string name="LSLTipText_llGetOmega"> vector llGetOmega() -gets the omega +Returns the rotation velocity in radians per second </string> <string name="LSLTipText_llGetTimeOfDay"> float llGetTimeOfDay() -gets the time in seconds since [SECOND_LIFE] server midnight (or since server up-time; whichever is smaller) +Returns the time in seconds since [SECOND_LIFE] server midnight or since region up-time, whichever is smaller </string> <string name="LSLTipText_llGetWallclock"> float llGetWallclock() -gets the time in seconds since midnight +Returns the time in seconds since midnight California Pacific time (PST/PDT) </string> <string name="LSLTipText_llGetTime"> float llGetTime() -gets the time in seconds since creation +Returns the time in seconds since the last region reset, script reset, or call to either llResetTime or llGetAndResetTime </string> <string name="LSLTipText_llResetTime"> llResetTime() -sets the time to zero +Sets the script timer to zero </string> <string name="LSLTipText_llGetAndResetTime"> float llGetAndResetTime() -gets the time in seconds since creation and sets the time to zero +Returns the script time in seconds and then resets the script timer to zero </string> <string name="LSLTipText_llSound"> llSound(string sound, float volume, integer queue, integer loop) -plays sound at volume and whether it should loop or not +Plays sound at volume and whether it should loop or not </string> <string name="LSLTipText_llPlaySound"> llPlaySound(string sound, float volume) -plays attached sound once at volume (0.0 - 1.0) +Plays attached sound once at volume (0.0 - 1.0) </string> <string name="LSLTipText_llLoopSound"> llLoopSound(string sound, float volume) -plays attached sound looping indefinitely at volume (0.0 - 1.0) +Plays attached sound looping indefinitely at volume (0.0 - 1.0) </string> <string name="LSLTipText_llLoopSoundMaster"> llLoopSoundMaster(string sound, float volume) -plays attached sound looping at volume (0.0 - 1.0), declares it a sync master +Plays attached sound looping at volume (0.0 - 1.0), declares it a sync master </string> <string name="LSLTipText_llLoopSoundSlave"> llLoopSoundSlave(string sound, float volume) -plays attached sound looping at volume (0.0 - 1.0), synced to most audible sync master +Plays attached sound looping at volume (0.0 - 1.0), synced to most audible sync master </string> <string name="LSLTipText_llPlaySoundSlave"> llPlaySoundSlave(string sound, float volume) -plays attached sound once at volume (0.0 - 1.0), synced to next loop of most audible sync master +Plays attached sound once at volume (0.0 - 1.0), synced to next loop of most audible sync master </string> <string name="LSLTipText_llTriggerSound"> llTriggerSound(string sound, float volume) -plays sound at volume (0.0 - 1.0), centered at but not attached to object +Plays sound at volume (0.0 - 1.0), centered at but not attached to object </string> <string name="LSLTipText_llStopSound"> llStopSound() @@ -677,143 +679,143 @@ Stops currently attached sound </string> <string name="LSLTipText_llPreloadSound"> llPreloadSound(string sound) -preloads a sound on viewers within range +Preloads a sound on viewers within range </string> <string name="LSLTipText_llGetSubString"> string llGetSubString(string src, integer start, integer end) -returns the indicated substring +Returns the indicated substring </string> <string name="LSLTipText_llDeleteSubString"> string llDeleteSubString(string src, integer start, integer end) -removes the indicated substring and returns the result +Removes the indicated substring and returns the result </string> <string name="LSLTipText_llInsertString"> string llInsertString(string dst, integer position, string src) -inserts src into dst at position and returns the result +Returns a destination string dst with the string src inserted starting at position pos </string> <string name="LSLTipText_llToUpper"> string llToUpper(string src) -convert src to all upper case and returns the result +Returns a string that is src with all upper-case characters </string> <string name="LSLTipText_llToLower"> string llToLower(string src) -convert src to all lower case and returns the result +Returns a string that is src with all lower-case characters </string> <string name="LSLTipText_llGiveMoney"> llGiveMoney(key destination, integer amount) -transfer amount of money from script owner to destination +Transfers amount of L$ from script owner to destination </string> <string name="LSLTipText_llMakeExplosion"> llMakeExplosion(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset) -Make a round explosion of particles +Makes a round explosion of particles </string> <string name="LSLTipText_llMakeFountain"> llMakeFountain(integer particles, float scale, float vel, float lifetime, float arc, integer bounce, string texture, vector offset, float bounce_offset) -Make a fountain of particles +Makes a fountain of particles </string> <string name="LSLTipText_llMakeSmoke"> llMakeSmoke(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset) -Make smoke like particles +Makes smoke like particles </string> <string name="LSLTipText_llMakeFire"> llMakeFire(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset) -Make fire like particles +Makes fire like particles </string> <string name="LSLTipText_llRezObject"> llRezObject(string inventory, vector pos, vector vel, rotation rot, integer param) -Instanciate owners inventory object at pos with velocity vel and rotation rot with start parameter param +Instantiates owner's inventory object at pos with velocity vel and rotation rot with start parameter param </string> <string name="LSLTipText_llLookAt"> -llLookAt(vector target, F32 strength, F32 damping) -Cause object name to point it's forward axis towards target +llLookAt(vector target, float strength, float damping) +Causes object to point its up axis (positive z) towards target, while keeping its forward axis (positive x) below the horizon </string> <string name="LSLTipText_llStopLookAt"> llStopLookAt() -Stop causing object name to point at a target +Stops causing object to point at a target </string> <string name="LSLTipText_llSetTimerEvent"> llSetTimerEvent(float sec) -Cause the timer event to be triggered every sec seconds +Causes the timer event to be triggered a maximum of once every sec seconds </string> <string name="LSLTipText_llSleep"> llSleep(float sec) -Put script to sleep for sec seconds +Puts the script to sleep for sec seconds </string> <string name="LSLTipText_llGetMass"> float llGetMass() -Get the mass of task name that script is attached to +Returns the mass of object that the script is attached to </string> <string name="LSLTipText_llCollisionFilter"> llCollisionFilter(string name, key id, integer accept) -if accept == TRUE, only accept collisions with objects name and id (either is optional), otherwise with objects not name or id +Sets the collision filter, exclusively or inclusively. If accept == TRUE, only accept collisions with objects name and id (either is optional), otherwise with objects not name or id </string> <string name="LSLTipText_llTakeControls"> llTakeControls(integer controls, integer accept, integer pass_on) -Take controls from agent task has permissions for. If (accept == (controls & input)), send input to task. If pass_on send to agent also. +Allows for intercepting keyboard and mouse clicks from the agent the script has permissions for </string> <string name="LSLTipText_llReleaseControls"> llReleaseControls() -Stop taking inputs +Stops taking inputs that were taken with llTakeControls </string> <string name="LSLTipText_llAttachToAvatar"> -llAttachToAvatar(integer attachment) -Attach to avatar task has permissions for at point attachment +llAttachToAvatar(integer attach_point) +Attaches the object to the avatar who has granted permission to the script </string> <string name="LSLTipText_llDetachFromAvatar"> llDetachFromAvatar() -Drop off of avatar +Detaches object from avatar </string> <string name="LSLTipText_llTakeCamera"> llTakeCamera(key avatar) -Move avatar's viewpoint to task +Moves avatar's viewpoint to task </string> <string name="LSLTipText_llReleaseCamera"> llReleaseCamera(key avatar) -Return camera to agent +Returns camera to agent avatar </string> <string name="LSLTipText_llGetOwner"> key llGetOwner() -Returns the owner of the task +Returns the object owner's UUID </string> <string name="LSLTipText_llInstantMessage"> llInstantMessage(key user, string message) -IMs message to the user +Sends the specified string as an Instant Message to the user </string> <string name="LSLTipText_llEmail"> llEmail(string address, string subject, string message) -Sends email to address with subject and message +Sends an email to address with the subject and message </string> <string name="LSLTipText_llGetNextEmail"> llGetNextEmail(string address, string subject) -Get the next waiting email with appropriate address and/or subject (if blank they are ignored) +Gets the next waiting email that comes from address, with specified subject </string> <string name="LSLTipText_llGetKey"> key llGetKey() -Get the key for the task the script is attached to +Returns the key of the prim the script is attached to </string> <string name="LSLTipText_llSetBuoyancy"> llSetBuoyancy(float buoyancy) -Set the tasks buoyancy (0 is none, < 1.0 sinks, 1.0 floats, > 1.0 rises) +Sets the buoyancy of the task or object (0 is disabled, < 1.0 sinks, 1.0 floats, > 1.0 rises) </string> <string name="LSLTipText_llSetHoverHeight"> llSetHoverHeight(float height, integer water, float tau) -Critically damps to a height (either above ground level or above the higher of land and water if water == TRUE) +Critically damps to a height above the ground (or water) in tau seconds </string> <string name="LSLTipText_llStopHover"> llStopHover() -Stop hovering to a height +Stops hovering to a height </string> <string name="LSLTipText_llMinEventDelay"> llMinEventDelay(float delay) -Set the minimum time between events being handled +Sets the minimum time between events being handled </string> <string name="LSLTipText_llSoundPreload"> llSoundPreload(string sound) -preloads a sound on viewers within range +Preloads a sound on viewers within range </string> <string name="LSLTipText_llRotLookAt"> -llRotLookAt(rotation target, F32 strength, F32 damping) -Cause object name to point it's forward axis towards target +llRotLookAt(rotation target, float strength, float damping) +Causes object name to point its forward axis towards target </string> <string name="LSLTipText_llStringLength"> integer llStringLength(string str) @@ -821,84 +823,83 @@ Returns the length of string </string> <string name="LSLTipText_llStartAnimation"> llStartAnimation(string anim) -Start animation anim for agent that owns object +Starts animation anim for agent that granted PERMISSION_TRIGGER_ANIMATION if the permission has not been revoked </string> <string name="LSLTipText_llStopAnimation"> llStopAnimation(string anim) -Stop animation anim for agent that owns object +Stops animation anim for agent that granted permission </string> <string name="LSLTipText_llPointAt"> llPointAt(vector pos) -Make agent that owns object point at pos +Makes agent that owns object point at pos </string> <string name="LSLTipText_llStopPointAt"> llStopPointAt() -Stop agent that owns object pointing +Stops pointing agent that owns object </string> <string name="LSLTipText_llTargetOmega"> llTargetOmega(vector axis, float spinrate, float gain) -Attempt to spin at spinrate with strength gain +Rotates the object around axis at spinrate with strength gain </string> <string name="LSLTipText_llGetStartParameter"> integer llGetStartParameter() -Get's the start paramter passed to llRezObject +Returns an integer that is the script start/rez parameter </string> <string name="LSLTipText_llGodLikeRezObject"> llGodLikeRezObject(key inventory, vector pos) -rez directly off of a UUID if owner has dog-bit set +Rezzes directly off of UUID if owner is in God Mode </string> <string name="LSLTipText_llRequestPermissions"> llRequestPermissions(key agent, integer perm) -ask agent to allow the script to do perm (NB: Debit, ownership, link, joint, and permission requests can only go to the task's owner) +Asks the agent for permission to run certain classes of functions </string> <string name="LSLTipText_llGetPermissionsKey"> key llGetPermissionsKey() -Return agent that permissions are enabled for. NULL_KEY if not enabled +Returns the key of the avatar that last granted permissions to the script </string> <string name="LSLTipText_llGetPermissions"> integer llGetPermissions() -return what permissions have been enabled +Returns an integer bitfield with the permissions that have been granted </string> <string name="LSLTipText_llGetLinkNumber"> integer llGetLinkNumber() -Returns what number in a link set the script is attached to (0 means no link, 1 the root, 2 for first child, etc) +Returns the link number of the prim containing the script (0 means not linked, 1 the prim is the root, 2 the prim is the first child, etc) </string> <string name="LSLTipText_llSetLinkColor"> llSetLinkColor(integer linknumber, vector color, integer face) -If a task exists in the link chain at linknumber, set face to color +Sets face to color if a task exists in the link chain at linknumber </string> <string name="LSLTipText_llCreateLink"> llCreateLink(key target, integer parent) -Attempt to link task script is attached to and target (requires permission PERMISSION_CHANGE_LINKS be set). If parent == TRUE, task script is attached to is the root +Attempts to link the script's object with the target (requires that PERMISSION_CHANGE_LINKS be granted). If parent == TRUE, then the script's object becomes the root </string> <string name="LSLTipText_llBreakLink"> llBreakLink(integer linknum) -Delinks the task with the given link number (requires permission PERMISSION_CHANGE_LINKS be set) +Delinks the prim with the given link number in a linked object set (requires that PERMISSION_CHANGE_LINKS be granted) </string> <string name="LSLTipText_llBreakAllLinks"> llBreakAllLinks() -Delinks all tasks in the link set (requires permission PERMISSION_CHANGE_LINKS be set) +Delinks all prims in the link set (requires that PERMISSION_CHANGE_LINKS be granted) </string> <string name="LSLTipText_llGetLinkKey"> -key llGetLinkKey(integer linknum) -Get the key of linknumber in link set +key llGetLinkKey(integer linknumber) +Returns the key of the linked prim linknumber </string> <string name="LSLTipText_llGetLinkName"> -string llGetLinkName(integer linknum) -Get the name of linknumber in link set +string llGetLinkName(integer linknumber) +Returns the name of linknumber in a link set </string> <string name="LSLTipText_llGetInventoryNumber"> integer llGetInventoryNumber(integer type) -Get the number of items of a given type in the task's inventory. -Valid types: INVENTORY_TEXTURE, INVENTORY_SOUND, INVENTORY_OBJECT, INVENTORY_SCRIPT, INVENTORY_CLOTHING, INVENTORY_BODYPART, INVENTORY_NOTECARD, INVENTORY_LANDMARK, INVENTORY_ALL +Returns the number of items of a given type (INVENTORY_* flag) in the prim's inventory </string> <string name="LSLTipText_llGetInventoryName"> string llGetInventoryName(integer type, integer number) -Get the name of the inventory item number of type +Returns the name of the inventory item number of a given type </string> <string name="LSLTipText_llSetScriptState"> llSetScriptState(string name, integer run) -Control the state of a script name. +Sets the running state of the specified script </string> <string name="LSLTipText_llGetEnergy"> float llGetEnergy() @@ -906,56 +907,55 @@ Returns how much energy is in the object as a percentage of maximum </string> <string name="LSLTipText_llGiveInventory"> llGiveInventory(key destination, string inventory) -Give inventory to destination +Gives inventory to destination </string> <string name="LSLTipText_llRemoveInventory"> -llRemoveInventory(string inventory) -Remove the named inventory item +llRemoveInventory(string item) +Removes the named inventory item </string> <string name="LSLTipText_llSetText"> llSetText(string text, vector color, float alpha) -Set text floating over object +Displays text that hovers over the prim with specific color and translucency specified with alpha </string> <string name="LSLTipText_llWater"> -float llWater(vector v) -returns the water height below the object position + v +float llWater(vector offset) +Returns the water height below the object position + offset </string> <string name="LSLTipText_llPassTouches"> llPassTouches(integer pass) -if pass == TRUE, touches are passed from children on to parents (default is FALSE) +If pass == TRUE, touches are passed from children on to parents </string> <string name="LSLTipText_llRequestAgentData"> key llRequestAgentData(key id, integer data) -Requests data about agent id. When data is available the dataserver event will be raised +Requests data about agent id. When data is available the dataserver event will be raised. </string> <string name="LSLTipText_llRequestInventoryData"> key llRequestInventoryData(string name) -Requests data from object's inventory object. When data is available the dataserver event will be raised +Requests data from object's inventory object. When data is available the dataserver event will be raised. </string> <string name="LSLTipText_llSetDamage"> llSetDamage(float damage) -Sets the amount of damage that will be done to an object that this task hits. Task will be killed. +Sets the amount of damage that will be done when this object hits an avatar. </string> <string name="LSLTipText_llTeleportAgentHome"> llTeleportAgentHome(key id) -Teleports agent on owner's land to agent's home location +Teleports avatar on the owner's land to their home location without any warning </string> <string name="LSLTipText_llModifyLand"> -llModifyLand(integer action, integer size) -Modify land with action (LAND_LEVEL, LAND_RAISE, LAND_LOWER, LAND_SMOOTH, LAND_NOISE, LAND_REVERT) -on size (LAND_SMALL_BRUSH, LAND_MEDIUM_BRUSH, LAND_LARGE_BRUSH) +llModifyLand(integer action, integer brush) +Modifies land using the specified action on the specified brush size of land </string> <string name="LSLTipText_llCollisionSound"> llCollisionSound(string impact_sound, float impact_volume) -Suppress default collision sounds, replace default impact sounds with impact_sound (empty string to just suppress) +Suppresses default collision sounds, replaces default impact sounds with impact_sound at the volume impact_volume </string> <string name="LSLTipText_llCollisionSprite"> llCollisionSprite(string impact_sprite) -Suppress default collision sprites, replace default impact sprite with impact_sprite (empty string to just suppress) +Suppresses default collision sprites, replaces default impact sprite with impact_sprite (use an empty string to just suppress) </string> <string name="LSLTipText_llGetAnimation"> string llGetAnimation(key id) -Get the currently playing locomotion animation for avatar id +Returns the name of the currently playing locomotion animation for avatar id </string> <string name="LSLTipText_llResetScript"> llResetScript() @@ -963,12 +963,7 @@ Resets the script </string> <string name="LSLTipText_llMessageLinked"> llMessageLinked(integer linknum, integer num, string str, key id) -Sends num, str, and id to members of the link set -(LINK_ROOT sends to root task in a linked set, -LINK_SET sends to all tasks, -LINK_ALL_OTHERS to all other tasks, -LINK_ALL_CHILDREN to all children, -LINK_THIS to the task the script it is in) +Allows scripts in the same object to communicate. Triggers a link_message event with the same parameters num, str, and id in all scripts in the prim(s) described by linknum. </string> <string name="LSLTipText_llPushObject"> llPushObject(key id, vector impulse, vector ang_impulse, integer local) @@ -976,19 +971,19 @@ Applies impulse and ang_impulse to object id </string> <string name="LSLTipText_llPassCollisions"> llPassCollisions(integer pass) -if pass == TRUE, collisions are passed from children on to parents (default is FALSE) +If pass == TRUE, collisions are passed from children on to parents (default is FALSE) </string> <string name="LSLTipText_llGetScriptName"> -llGetScriptName() -Returns the script name +string llGetScriptName() +Returns the name of the script that this function is used in </string> <string name="LSLTipText_llGetNumberOfSides"> integer llGetNumberOfSides() -Returns the number of sides +Returns the number of faces (or sides) of the prim </string> <string name="LSLTipText_llAxisAngle2Rot"> rotation llAxisAngle2Rot(vector axis, float angle) -Returns the rotation generated angle about axis +Returns the rotation that is a generated angle about axis </string> <string name="LSLTipText_llRot2Axis"> vector llRot2Axis(rotation rot) @@ -1012,19 +1007,19 @@ Returns angle between rotation a and b </string> <string name="LSLTipText_llGetInventoryKey"> key llGetInventoryKey(string name) -Returns the key of the inventory name +Returns the key that is the UUID of the inventory name </string> <string name="LSLTipText_llAllowInventoryDrop"> llAllowInventoryDrop(integer add) -If add == TRUE, users without permissions can still drop inventory items onto task +If add == TRUE, users without modify permissions can still drop inventory items onto a prim </string> <string name="LSLTipText_llGetSunDirection"> vector llGetSunDirection() -Returns the sun direction on the simulator +Returns a normalized vector of the direction of the sun in the region </string> <string name="LSLTipText_llGetTextureOffset"> -vector llGetTextureOffset(integer side) -Returns the texture offset of side in the x and y components of a vector +vector llGetTextureOffset(integer face) +Returns the texture offset of face in the x and y components of a vector </string> <string name="LSLTipText_llGetTextureScale"> vector llGetTextureScale(integer side) @@ -1036,55 +1031,57 @@ Returns the texture rotation of side </string> <string name="LSLTipText_llSubStringIndex"> integer llSubStringIndex(string source, string pattern) -Finds index in source where pattern first appears (returns -1 if not found) +Returns an integer that is the index in source where pattern first appears. +(Returns -1 if not found) </string> <string name="LSLTipText_llGetOwnerKey"> key llGetOwnerKey(key id) -Find the owner of id +Returns the owner of object id </string> <string name="LSLTipText_llGetCenterOfMass"> vector llGetCenterOfMass() -Get the object's center of mass +Returns the prim's center of mass (unless called from the root prim, where it returns the object's center of mass) </string> <string name="LSLTipText_llListSort"> list llListSort(list src, integer stride, integer ascending) -Sort the list into blocks of stride in ascending order if ascending == TRUE. Note that sort only works between same types. +Sorts the list into blocks of stride, in ascending order if ascending == TRUE. +The sort order is affected by type. </string> <string name="LSLTipText_llGetListLength"> integer llGetListLength(list src) -Get the number of elements in the list +Returns the number of elements in the list </string> <string name="LSLTipText_llList2Integer"> integer llList2Integer(list src, integer index) -Copy the integer at index in the list +Copies the integer at index in the list </string> <string name="LSLTipText_llList2Float"> float llList2Float(list src, integer index) -Copy the float at index in the list +Copies the float at index in the list </string> <string name="LSLTipText_llList2String"> string llList2String(list src, integer index) -Copy the string at index in the list +Copies the string at index in the list </string> <string name="LSLTipText_llList2Key"> key llList2Key(list src, integer index) -Copy the key at index in the list +Copies the key at index in the list </string> <string name="LSLTipText_llList2Vector"> vector llList2Vector(list src, integer index) -Copy the vector at index in the list +Copies the vector at index in the list </string> <string name="LSLTipText_llList2Rot"> rotation llList2Rot(list src, integer index) -Copy the rotation at index in the list +Copies the rotation at index in the list </string> <string name="LSLTipText_llList2List"> list llList2List(list src, integer start, integer end) -Copy the slice of the list from start to end +Copies the slice of the list from start to end </string> <string name="LSLTipText_llDeleteSubList"> list llDeleteSubList(list src, integer start, integer end) -Remove the slice from the list and return the remainder +Removes the slice from start to end and returns the remainder of the list </string> <string name="LSLTipText_llGetListEntryType"> integer llGetListEntryType(list src, integer index) @@ -1093,11 +1090,11 @@ Returns the type of the index entry in the list </string> <string name="LSLTipText_llList2CSV"> string llList2CSV(list src) -Create a string of comma separated values from list +Creates a string of comma separated values from list </string> <string name="LSLTipText_llCSV2List"> list llCSV2List(string src) -Create a list from a string of comma separated values +Creates a list from a string of comma separated values </string> <string name="LSLTipText_llListRandomize"> list llListRandomize(list src, integer stride) @@ -1105,80 +1102,83 @@ Returns a randomized list of blocks of size stride </string> <string name="LSLTipText_llList2ListStrided"> list llList2ListStrided(list src, integer start, integer end, integer stride) -Copy the strided slice of the list from start to end +Copies the strided slice of the list from start to end </string> <string name="LSLTipText_llGetRegionCorner"> vector llGetRegionCorner() -Returns a vector with the south west corner x,y position of the region the object is in +Returns a vector in meters that is the global location of the south-west corner of the region which the object is in </string> <string name="LSLTipText_llListInsertList"> list llListInsertList(list dest, list src, integer start) -Inserts src into dest at position start +Returns a list that contains all the elements from dest but with the elements from src inserted at position start </string> <string name="LSLTipText_llListFindList"> integer llListFindList(list src, list test) -Returns the start of the first instance of test in src, -1 if not found +Returns the index of the first instance of test in src. +(Returns -1 if not found) </string> <string name="LSLTipText_llGetObjectName"> string llGetObjectName() -Returns the name of the object script is attached to +Returns the name of the prim which the script is attached to </string> <string name="LSLTipText_llSetObjectName"> llSetObjectName(string name) -Sets the objects name +Sets the prim's name to the name parameter </string> <string name="LSLTipText_llGetDate"> string llGetDate() -Gets the date as YYYY-MM-DD +Returns the current date in the UTC time zone in the format YYYY-MM-DD </string> <string name="LSLTipText_llEdgeOfWorld"> integer llEdgeOfWorld(vector pos, vector dir) -Checks to see whether the border hit by dir from pos is the edge of the world (has no neighboring simulator) +Checks to see whether the border hit by dir from pos is the edge of the world (has no neighboring region) </string> <string name="LSLTipText_llGetAgentInfo"> integer llGetAgentInfo(key id) -Gets information about agent ID. -Returns AGENT_FLYING, AGENT_ATTACHMENTS, AGENT_SCRIPTED, AGENT_SITTING, AGENT_ON_OBJECT, AGENT_MOUSELOOK, AGENT_AWAY, AGENT_BUSY, AGENT_TYPING, AGENT_CROUCHING, AGENT_ALWAYS_RUN, AGENT_WALKING, AGENT_IN_AIR and/or AGENT_AUTOPILOT. +Returns an integer bitfield containing the agent information about id. +Returns AGENT_FLYING, AGENT_ATTACHMENTS, AGENT_SCRIPTED, AGENT_SITTING, AGENT_ON_OBJECT, AGENT_MOUSELOOK, AGENT_AWAY, AGENT_BUSY, AGENT_TYPING, AGENT_CROUCHING, AGENT_ALWAYS_RUN, AGENT_WALKING and/or AGENT_IN_AIR. </string> <string name="LSLTipText_llAdjustSoundVolume"> llAdjustSoundVolume(float volume) -adjusts volume of attached sound (0.0 - 1.0) +Adjusts volume of attached sound (0.0 - 1.0) </string> <string name="LSLTipText_llSetSoundQueueing"> llSetSoundQueueing(integer queue) -determines whether attached sound calls wait for the current sound to finish (0 = no [default], nonzero = yes) +Sets whether attached sounds wait for the current sound to finish (If queue == TRUE then queuing is enabled, if FALSE queuing is disabled [default]) </string> <string name="LSLTipText_llSetSoundRadius"> llSetSoundRadius(float radius) -establishes a hard cut-off radius for audibility of scripted sounds (both attached and triggered) +Establishes a hard cut-off radius for audibility of scripted sounds (both attached and triggered) </string> <string name="LSLTipText_llKey2Name"> string llKey2Name(key id) -Returns the name of the object key, iff the object is in the current simulator, otherwise the empty string +Returns the name of the prim or avatar specified by id. +(The id must be a valid rezzed prim or avatar key in the current simulator, otherwise an empty string is returned.) </string> <string name="LSLTipText_llSetTextureAnim"> llSetTextureAnim(integer mode, integer face, integer sizex, integer sizey, float start, float length, float rate) -Animate the texture on the specified face/faces +Animates the texture on the specified face/faces </string> <string name="LSLTipText_llTriggerSoundLimited"> -llTriggerSoundLimited(string sound, float volume, vector tne, vector bsw) -plays sound at volume (0.0 - 1.0), centered at but not attached to object, limited to AABB defined by vectors top-north-east and bottom-south-west +llTriggerSoundLimited(string sound, float volume, vector top_north_east, vector bottom_south_west) +Plays sound at volume (0.0 - 1.0), centered at but not attached to object, limited to the box defined by vectors top_north_east and bottom_south_west </string> <string name="LSLTipText_llEjectFromLand"> -llEjectFromLand(key pest) -Ejects pest from land that you own +llEjectFromLand(key avatar) +Ejects avatar from the parcel </string> <string name="LSLTipText_llParseString2List"> list llParseString2List(string src, list separators, list spacers) -Breaks src into a list, discarding separators, keeping spacers (separators and spacers must be lists of strings, maximum of 8 each) +Breaks src into a list, discarding separators, keeping spacers +(separators and spacers must be lists of strings, maximum of 8 each) </string> <string name="LSLTipText_llOverMyLand"> integer llOverMyLand(key id) -Returns TRUE if id is over land owner of object owns, FALSE otherwise +Returns TRUE if id is over land owned by the script owner, otherwise FALSE </string> <string name="LSLTipText_llGetLandOwnerAt"> key llGetLandOwnerAt(vector pos) -Returns the key of the land owner, NULL_KEY if public +Returns the key of the land owner, returns NULL_KEY if public </string> <string name="LSLTipText_llGetNotecardLine"> key llGetNotecardLine(string name, integer line) @@ -1186,131 +1186,130 @@ Returns line line of notecard name via the dataserver event </string> <string name="LSLTipText_llGetAgentSize"> vector llGetAgentSize(key id) -If the agent is in the same sim as the object, returns the size of the avatar +If the avatar is in the same region, returns the size of the bounding box of the requested avatar by id, otherwise returns ZERO_VECTOR </string> <string name="LSLTipText_llSameGroup"> integer llSameGroup(key id) -Returns TRUE if ID is in the same sim and has the same active group, otherwise FALSE +Returns TRUE if avatar id is in the same region and has the same active group, otherwise FALSE </string> <string name="LSLTipText_llUnSit"> key llUnSit(key id) -If agent identified by id is sitting on the object the script is attached to or is over land owned by the objects owner, the agent is forced to stand up +If avatar identified by id is sitting on the object the script is attached to or is over land owned by the object's owner, the avatar is forced to stand up </string> <string name="LSLTipText_llGroundSlope"> -vector llGroundSlope(vector v) -returns the ground slope below the object position + v +vector llGroundSlope(vector offset) +Returns the ground slope below the object position + offset </string> <string name="LSLTipText_llGroundNormal"> -vector llGroundNormal(vector v) -returns the ground normal below the object position + v +vector llGroundNormal(vector offset) +Returns the ground normal below the object position + offset </string> <string name="LSLTipText_llGroundContour"> -vector llGroundCountour(vector v) -returns the ground contour below the object position + v +vector llGroundCountour(vector offset) +Returns the ground contour direction below the object position + offset </string> <string name="LSLTipText_llGetAttached"> integer llGetAttached() -returns the object attachment point or 0 if not attached +Returns the object's attachment point, or 0 if not attached </string> <string name="LSLTipText_llGetFreeMemory"> integer llGetFreeMemory() -returns the available heap space for the current script +Returns the number of free bytes of memory the script can use </string> <string name="LSLTipText_llGetRegionName"> string llGetRegionName() -returns the current region name +Returns the current region name </string> <string name="LSLTipText_llGetRegionTimeDilation"> float llGetRegionTimeDilation() -returns the current time dilation as a float between 0 and 1 +Returns the current time dilation as a float between 0.0 (full dilation) and 1.0 (no dilation) </string> <string name="LSLTipText_llGetRegionFPS"> float llGetRegionFPS() -returns the mean region frames per second +Returns the mean region frames per second </string> <string name="LSLTipText_llParticleSystem"> llParticleSystem(list rules) -Creates a particle system based on rules. Empty list removes particle system from object. +Creates a particle system based on rules. An empty list removes the particle system. List format is [ rule1, data1, rule2, data2 . . . rulen, datan ] </string> <string name="LSLTipText_llGroundRepel"> llGroundRepel(float height, integer water, float tau) -Critically damps to height if within height*0.5 of level (either above ground level or above the higher of land and water if water == TRUE) +Critically damps to height if within height*0.5 of level (either above ground level, or above the higher of land and water if water == TRUE) </string> <string name="LSLTipText_llGiveInventoryList"> -llGiveInventoryList(key destination, string category, list inventory) -Give inventory to destination in a new category +llGiveInventoryList(key target, string folder, list inventory) +Gives inventory items to target, creating a new folder to put them in </string> <string name="LSLTipText_llSetVehicleType"> llSetVehicleType(integer type) -sets vehicle to one of the default types +Sets the vehicle to one of the default types </string> <string name="LSLTipText_llSetVehicleFloatParam"> llSetVehicleFloatParam(integer param, float value) -sets the specified vehicle float parameter +Sets the specified vehicle float parameter </string> <string name="LSLTipText_llSetVehicleVectorParam"> llSetVehicleVectorParam(integer param, vector vec) -sets the specified vehicle vector parameter +Sets the specified vehicle vector parameter </string> <string name="LSLTipText_llSetVehicleRotationParam"> llSetVehicleVectorParam(integer param, rotation rot) -sets the specified vehicle rotation parameter +Sets the specified vehicle rotation parameter </string> <string name="LSLTipText_llSetVehicleFlags"> llSetVehicleFlags(integer flags) -sets the enabled bits in 'flags' +Sets the enabled bits in 'flags' </string> <string name="LSLTipText_llRemoveVehicleFlags"> llRemoveVehicleFlags(integer flags) -removes the enabled bits in 'flags' +Removes the enabled bits in 'flags' </string> <string name="LSLTipText_llSitTarget"> llSitTarget(vector offset, rotation rot) -Set the sit location for this object (if offset == <0,0,0> clear it) +Sets the sit location for the prim. If offset == <0,0,0> then the sit target is removed. </string> <string name="LSLTipText_llAvatarOnSitTarget"> key llAvatarOnSitTarget() -If an avatar is sitting on the sit target, return the avatar's key, NULL_KEY otherwise +If an avatar is seated on the sit target, returns the avatar's key, otherwise NULL_KEY </string> <string name="LSLTipText_llAddToLandPassList"> llAddToLandPassList(key avatar, float hours) -Add avatar to the land pass list for hours +Adds avatar to the land pass list for hours, or indefinitely if hours is 0 </string> <string name="LSLTipText_llSetTouchText"> llSetTouchText(string text) -Displays text in pie menu that acts as a touch +Displays text rather than the default 'Touch' in the pie menu </string> <string name="LSLTipText_llSetSitText"> llSetSitText(string text) -Displays text rather than sit in pie menu +Displays text rather than the default 'Sit Here' in the pie menu </string> <string name="LSLTipText_llSetCameraEyeOffset"> llSetCameraEyeOffset(vector offset) -Sets the camera eye offset used in this object if an avatar sits on it +Sets the camera eye offset for avatars that sit on the object </string> <string name="LSLTipText_llSetCameraAtOffset"> llSetCameraAtOffset(vector offset) -Sets the camera at offset used in this object if an avatar sits on it +Sets the point the camera is looking at to offset for avatars that sit on the object </string> <string name="LSLTipText_llDumpList2String"> string llDumpList2String(list src, string separator) -Write the list out in a single string using separator between values +Returns the list in a single string, using separator between the entries </string> <string name="LSLTipText_llScriptDanger"> integer llScriptDanger(vector pos) -Returns true if pos is over public land, sandbox land, land that doesn't allow everyone to edit and build, or land that doesn't allow outside scripts +Returns TRUE if pos is over public land, sandbox land, land that doesn't allow everyone to edit and build, or land that doesn't allow outside scripts </string> <string name="LSLTipText_llDialog"> llDialog(key avatar, string message, list buttons, integer chat_channel -Shows a dialog box on the avatar's screen with the message. -Up to 12 strings in the list form buttons. -If a button is clicked, the name is chatted on chat_channel. +Shows a dialog box on the avatar's screen with a message and up to 12 buttons. +If a button is pressed, the avatar says the text of the button label on chat_channel. </string> <string name="LSLTipText_llVolumeDetect"> llVolumeDetect(integer detect) -If detect = TRUE, object becomes phantom but triggers collision_start and collision_end events when other objects start and stop interpenetrating. -Must be applied to the root object. +If detect = TRUE, object works much like Phantom, but triggers collision_start and collision_end events when other objects start and stop interpenetrating. +Must be applied to the root prim. </string> <string name="LSLTipText_llResetOtherScript"> llResetOtherScript(string name) @@ -1318,110 +1317,107 @@ Resets script name </string> <string name="LSLTipText_llGetScriptState"> integer llGetScriptState(string name) -Resets TRUE if script name is running +Returns TRUE if the script name is running </string> <string name="LSLTipText_llRemoteLoadScript"> -Deprecated. Please use llRemoteLoadScriptPin instead. +DEPRECATED! Please use llRemoteLoadScriptPin instead. </string> <string name="LSLTipText_llSetRemoteScriptAccessPin"> llSetRemoteScriptAccessPin(integer pin) -If pin is set to a non-zero number, the task will accept remote script loads via llRemoteLoadScriptPin if it passes in the correct pin. -Othersise, llRemoteLoadScriptPin is ignored. +If pin is set to a non-zero number, allows a prim to have scripts remotely loaded via llRemoteLoadScriptPin when it passes in the correct pin. Otherwise, llRemoteLoadScriptPin is ignored. </string> <string name="LSLTipText_llRemoteLoadScriptPin"> llRemoteLoadScriptPin(key target, string name, integer pin, integer running, integer start_param) -If the owner of the object this script is attached can modify target, -they are in the same region, and the matching pin is used, -copy script name onto target, -if running == TRUE, start the script with param. +Copies script name onto target, if the owner of this scripted object can modify target and is in the same region, and the matching pin is used. +If running == TRUE, starts the script with start_param </string> <string name="LSLTipText_llOpenRemoteDataChannel"> llOpenRemoteDataChannel() -Creates a channel to listen for XML-RPC calls. Will trigger a remote_data event with channel id once it is available. +Creates a channel to listen for XML-RPC calls, and will trigger a remote_data event with channel id once it is available </string> <string name="LSLTipText_llSendRemoteData"> key llSendRemoteData(key channel, string dest, integer idata, string sdata) -Send an XML-RPC request to dest through channel with payload of channel (in a string), integer idata and string sdata. -A message identifier key is returned. -An XML-RPC reply will trigger a remote_data event and reference the message id. -The message_id is returned. +Sends an XML-RPC request to dest through channel with payload of channel (in a string), integer idata and string sdata. +Returns a key that is the message_id for the resulting remote_data events. </string> <string name="LSLTipText_llRemoteDataReply"> llRemoteDataReply(key channel, key message_id, string sdata, integer idata) -Send an XML-RPC reply to message_id on channel with payload of string sdata and integer idata +Sends an XML-RPC reply to message_id on channel with payload of string sdata and integer idata </string> <string name="LSLTipText_llCloseRemoteDataChannel"> llCloseRemoteDataChannel(key channel) -Closes XML-RPC channel. +Closes XML-RPC channel </string> <string name="LSLTipText_llMD5String"> string llMD5String(string src, integer nonce) -Performs a RSA Data Security, Inc. MD5 Message-Digest Algorithm on string with nonce. Returns a 32 character hex string. +Returns a string of 32 hex characters that is a RSA Data Security, Inc. MD5 Message-Digest Algorithm of src with nonce </string> <string name="LSLTipText_llSetPrimitiveParams"> llSetPrimitiveParams(list rules) -Set primitive parameters based on rules. +Sets the prim's parameters according to rules </string> <string name="LSLTipText_llStringToBase64"> string llStringToBase64(string str) -Converts a string to the Base 64 representation of the string. +Converts a string to the Base64 representation of the string </string> <string name="LSLTipText_llBase64ToString"> string llBase64ToString(string str) -Converts a Base 64 string to a conventional string. If the conversion creates any unprintable characters, they are converted to spaces. +Converts a Base64 string to a conventional string. +If the conversion creates any unprintable characters, they are converted to spaces. </string> <string name="LSLTipText_llXorBase64Strings"> string llXorBase64Strings(string s1, string s2) -DEPRECATED! Please use llXorBase64StringsCorrect instead!! Incorrectly performs an exclusive or on two Base 64 strings and returns a Base 64 string. s2 repeats if it is shorter than s1. Retained for backwards compatability. +DEPRECATED! Please use llXorBase64StringsCorrect instead. +Incorrectly performs an exclusive or on two Base64 strings and returns a Base64 string. s2 repeats if it is shorter than s1. Retained for backwards compatability. </string> <string name="LSLTipText_llRemoteDataSetRegion"> llRemoteDataSetRegion() -If an object using remote data channels changes regions, you must call this function to reregister the remote data channels. -You do not need to make this call if you don't change regions. +DEPRECATED! Please use llOpenRemoteDataChannel instead. +If an object using remote data channels changes regions, you must call this function to reregister the remote data channels. This call is not needed if the prim does not change regions. </string> <string name="LSLTipText_llLog10"> float llLog10(float val) -Returns the base 10 log of val if val > 0, otherwise returns 0. +Returns the base 10 logarithm of val. Returns zero if val <= 0. </string> <string name="LSLTipText_llLog"> float llLog(float val) -Returns the base e log of val if val > 0, otherwise returns 0. +Returns the natural logarithm of val. Returns zero if val <= 0. </string> <string name="LSLTipText_llGetAnimationList"> list llGetAnimationList(key id) -Gets a list of all playing animations for avatar id +Returns a list of keys of playing animations for avatar described by id </string> <string name="LSLTipText_llSetParcelMusicURL"> llSetParcelMusicURL(string url) -Sets the streaming audio URL for the parcel object is on +Sets the streaming audio URL for the parcel which the object is on </string> <string name="LSLTipText_llGetRootPosition"> vector llGetRootPosition() -Gets the global position of the root object of the object script is attached to +Returns the position (in region coordinates) of the root prim of the object which the script is attached to </string> <string name="LSLTipText_llGetRootRotation"> rotation llGetRootRotation() -Gets the global rotation of the root object of the object script is attached to +Returns the rotation (relative to the region) of the root prim of the object which the script is attached to </string> <string name="LSLTipText_llGetObjectDesc"> string llGetObjectDesc() -Returns the description of the object the script is attached to +Returns the description of the prim the script is attached to </string> <string name="LSLTipText_llSetObjectDesc"> llSetObjectDesc(string name) -Sets the object's description +Sets the prim's description </string> <string name="LSLTipText_llGetCreator"> key llGetCreator() -Returns the creator of the object +Returns a key for the creator of the prim </string> <string name="LSLTipText_llGetTimestamp"> string llGetTimestamp() -Gets the timestamp in the format: YYYY-MM-DDThh:mm:ss.ff..fZ +Returns the timestamp in the UTC time zone in the format: YYYY-MM-DDThh:mm:ss.ff..fZ </string> <string name="LSLTipText_llSetLinkAlpha"> llSetLinkAlpha(integer linknumber, float alpha, integer face) -If a prim exists in the link chain at linknumber, set face to alpha +If a prim exists in the link chain at linknumber, sets face to alpha </string> <string name="LSLTipText_llGetNumberOfPrims"> integer llGetNumberOfPrims() @@ -1429,11 +1425,11 @@ Returns the number of prims in a link set the script is attached to </string> <string name="LSLTipText_llGetNumberOfNotecardLines"> key llGetNumberOfNotecardLines(string name) -Returns number of lines in notecard 'name' via the dataserver event (cast return value to integer) +Returns number of lines in notecard name via the dataserver event (cast return value to integer) </string> <string name="LSLTipText_llGetBoundingBox"> list llGetBoundingBox(key object) -Returns the bounding box around an object (including any linked prims) relative to the root prim, in a list: [ (vector) min_corner, (vector) max_corner ] +Returns the bounding box around the object (including any linked prims) relative to its root prim, in a list in the format [ (vector) min_corner, (vector) max_corner ] </string> <string name="LSLTipText_llGetGeometricCenter"> vector llGetGeometricCenter() @@ -1441,142 +1437,143 @@ Returns the geometric center of the linked set the script is attached to. </string> <string name="LSLTipText_llGetPrimitiveParams"> list llGetPrimitiveParams(list params) -Gets primitive parameters specified in the params list. +Returns the primitive parameters specified in the params list. </string> <string name="LSLTipText_llIntegerToBase64"> string llIntegerToBase64(integer number) -Big endian encode of of integer as a Base64 string. +Returns a string that is a Base64 big endian encode of number </string> <string name="LSLTipText_llBase64ToInteger"> integer llBase64ToInteger(string str) -Big endian decode of a Base64 string into an integer. +Returns an integer that is the str Base64 decoded as a big endian integer </string> <string name="LSLTipText_llGetGMTclock"> float llGetGMTclock() -Gets the time in seconds since midnight in GMT +Returns the time in seconds since midnight GMT </string> <string name="LSLTipText_llGetSimulatorHostname"> string llGetSimulatorHostname() -Gets the hostname of the machine script is running on (same as string in viewer Help dialog) +Returns the hostname of the machine which the script is running on (same as string in viewer Help dialog) </string> <string name="LSLTipText_llSetLocalRot"> llSetLocalRot(rotation rot) -sets the rotation of a child prim relative to the root prim +Sets the rotation of a child prim relative to the root prim </string> <string name="LSLTipText_llParseStringKeepNulls"> list llParseStringKeepNulls(string src, list separators, list spacers) -Breaks src into a list, discarding separators, keeping spacers (separators and spacers must be lists of strings, maximum of 8 each), keeping any null values generated. +Breaks src into a list, discarding separators, keeping spacers, keeping any null values generated. +(separators and spacers must be lists of strings, maximum of 8 each) </string> <string name="LSLTipText_llRezAtRoot"> llRezAtRoot(string inventory, vector pos, vector vel, rotation rot, integer param) -Instantiate owner's inventory object at pos with velocity vel and rotation rot with start parameter param. -The last selected root object's location will be set to pos +Instantiates owner's inventory object rotated to rot with its root at pos, moving at vel, using param as the start parameter </string> <string name="LSLTipText_llGetObjectPermMask"> integer llGetObjectPermMask(integer mask) -Returns the requested permission mask for the root object the task is attached to. +Returns the requested permission mask for the root object the task is attached to </string> <string name="LSLTipText_llSetObjectPermMask"> llSetObjectPermMask(integer mask, integer value) -Sets the given permission mask to the new value on the root object the task is attached to. +Sets the given permission mask to the new value on the root object the task is attached to </string> <string name="LSLTipText_llGetInventoryPermMask"> integer llGetInventoryPermMask(string item, integer mask) -Returns the requested permission mask for the inventory item. +Returns the requested permission mask for the inventory item </string> <string name="LSLTipText_llSetInventoryPermMask"> llSetInventoryPermMask(string item, integer mask, integer value) -Sets the given permission mask to the new value on the inventory item. +Sets the given permission mask to the new value on the inventory item </string> <string name="LSLTipText_llGetInventoryCreator"> key llGetInventoryCreator(string item) -Returns the key for the creator of the inventory item. +Returns a key for the creator of the inventory item </string> <string name="LSLTipText_llOwnerSay"> llOwnerSay(string msg) -says msg to owner only (if owner in sim) +Says msg to owner only. (Owner must be in the same region.) </string> <string name="LSLTipText_llRequestSimulatorData"> key llRequestSimulatorData(string simulator, integer data) -Requests data about simulator. When data is available the dataserver event will be raised +Requests data about simulator. When data is available the dataserver event will be raised. </string> <string name="LSLTipText_llForceMouselook"> llForceMouselook(integer mouselook) -If mouselook is TRUE any avatar that sits on this object is forced into mouselook mode +If mouselook is TRUE, any avatar that sits upon the prim will be forced into mouselook mode </string> <string name="LSLTipText_llGetObjectMass"> float llGetObjectMass(key id) -Get the mass of the object with key id +Returns the mass of the avatar or object in the region </string> <string name="LSLTipText_llListReplaceList"> list llListReplaceList(list dest, list src, integer start, integer end) -Replaces start through end of dest with src. +Returns a list that is dest with start through end removed and src inserted at start </string> <string name="LSLTipText_llLoadURL"> -llLoadURL(key avatar_id, string message, string url) -Shows dialog to avatar avatar_id offering to load web page at URL. If user clicks yes, launches their web browser. +llLoadURL(key avatar, string message, string url) +Shows a dialog to avatar offering to load the web page at url with a message. +If user clicks yes, launches the page in their web browser. </string> <string name="LSLTipText_llParcelMediaCommandList"> llParcelMediaCommandList(list command) -Sends a list of commands, some with arguments, to a parcel. +Sends a list of commands, some with arguments, to a parcel to control the playback of movies and other media </string> <string name="LSLTipText_llParcelMediaQuery"> list llParcelMediaQuery(list query) -Sends a list of queries, returns a list of results. +Returns a list containing results of the sent query </string> <string name="LSLTipText_llModPow"> integer llModPow(integer a, integer b, integer c) -Returns a raised to the b power, mod c. ( (a**b)%c ). b is capped at 0xFFFF (16 bits). +Returns a raised to the b power, mod c. ( (a**b)%c ) +b is capped at 0xFFFF (16 bits). </string> <string name="LSLTipText_llGetInventoryType"> integer llGetInventoryType(string name) -Returns the type of the inventory name +Returns the type of the inventory item name </string> <string name="LSLTipText_llSetPayPrice"> llSetPayPrice(integer price, list quick_pay_buttons) -Sets the default amount when someone chooses to pay this object. +Sets the default amount on the dialog that appears when someone chooses to pay this prim </string> <string name="LSLTipText_llGetCameraPos"> vector llGetCameraPos() -Gets current camera position for agent task has permissions for. +Returns the current camera position for the agent the task has permissions for </string> <string name="LSLTipText_llGetCameraRot"> rotation llGetCameraRot() -Gets current camera orientation for agent task has permissions for. +Returns the current camera orientation for the agent the task has permissions for </string> <string name="LSLTipText_llSetPrimURL"> llSetPrimURL(string url) -Updates the URL for the web page shown on the sides of the object. +Updates the URL for the web page shown on the sides of the object </string> <string name="LSLTipText_llRefreshPrimURL"> llRefreshPrimURL() -Reloads the web page shown on the sides of the object. +Reloads the web page shown on the sides of the object </string> <string name="LSLTipText_llEscapeURL"> string llEscapeURL(string url) -Returns and escaped/encoded version of url, replacing spaces with %20 etc. +Returns an escaped/encoded version of url, replacing spaces with %20 etc. </string> <string name="LSLTipText_llUnescapeURL"> string llUnescapeURL(string url) -Returns and unescaped/unencoded version of url, replacing %20 with spaces etc. +Returns an unescaped/ unencoded version of url, replacing %20 with spaces etc. </string> <string name="LSLTipText_llMapDestination"> llMapDestination(string simname, vector pos, vector look_at) -Opens world map centered on region with pos highlighted. +Opens the World Map centered on the region simname with pos highlighted. (NOTE: look_at currently does nothing.) Only works for scripts attached to avatar, or during touch events. -(NOTE: look_at currently does nothing) </string> <string name="LSLTipText_llAddToLandBanList"> llAddToLandBanList(key avatar, float hours) -Add avatar to the land ban list for hours +Adds avatar to the land ban list for hours, or indefinitely if hours is 0 </string> <string name="LSLTipText_llRemoveFromLandPassList"> llRemoveFromLandPassList(key avatar) -Remove avatar from the land pass list +Removes avatar from the land pass list </string> <string name="LSLTipText_llRemoveFromLandBanList"> llRemoveFromLandBanList(key avatar) -Remove avatar from the land ban list +Removes avatar from the land ban list </string> <string name="LSLTipText_llSetCameraParams"> llSetCameraParams(list rules) @@ -1585,158 +1582,174 @@ List format is [ rule1, data1, rule2, data2 . . . rulen, datan ] </string> <string name="LSLTipText_llClearCameraParams"> llClearCameraParams() -Resets all camera parameters to default values and turns off scripted camera control. +Resets all camera parameters to default values and turns off scripted camera control </string> <string name="LSLTipText_llListStatistics"> -float llListStatistics(integer operation, list l) -Perform statistical aggregate functions on list l using LIST_STAT_* operations. +float llListStatistics(integer operation, list src) +Performs statistical aggregate functions on list src using LIST_STAT_* operations </string> <string name="LSLTipText_llGetUnixTime"> integer llGetUnixTime() -Get the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC from the system clock. +Returns the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC from the system clock </string> <string name="LSLTipText_llGetParcelFlags"> integer llGetParcelFlags(vector pos) -Get the parcel flags (PARCEL_FLAG_*) for the parcel including the point pos. +Returns a mask of the parcel flags (PARCEL_FLAG_*) for the parcel that includes the point pos </string> <string name="LSLTipText_llGetRegionFlags"> integer llGetRegionFlags() -Get the region flags (REGION_FLAG_*) for the region the object is in. +Returns the region flags (REGION_FLAG_*) for the region the object is in </string> <string name="LSLTipText_llXorBase64StringsCorrect"> string llXorBase64StringsCorrect(string s1, string s2) -Correctly performs an exclusive or on two Base 64 strings and returns a Base 64 string. s2 repeats if it is shorter than s1. +Correctly performs an exclusive or on two Base64 strings and returns a Base64 string. +s2 repeats if it is shorter than s1. </string> <string name="LSLTipText_llHTTPRequest"> llHTTPRequest(string url, list parameters, string body) -Send an HTTP request. +Sends an HTTP request to the specified url with the body of the request and parameters </string> <string name="LSLTipText_llResetLandBanList"> llResetLandBanList() -Removes all residents from the land ban list. +Removes all residents from the land ban list </string> <string name="LSLTipText_llResetLandPassList"> llResetLandPassList() -Removes all residents from the land access/pass list. +Removes all residents from the land access/pass list </string> <string name="LSLTipText_llGetObjectPrimCount"> integer llGetObjectPrimCount(key object_id) -Returns the total number of prims for an object. +Returns the total number of prims for an object in the region </string> <string name="LSLTipText_llGetParcelPrimOwners"> list llGetParcelPrimOwners(vector pos) -Returns a list of all residents who own objects on the parcel and the number of objects they own. +Returns a list of all residents who own objects on the parcel at pos and with individual prim counts. Requires owner-like permissions for the parcel. </string> <string name="LSLTipText_llGetParcelPrimCount"> integer llGetParcelPrimCount(vector pos, integer category, integer sim_wide) -Gets the number of prims on the parcel of the given category. -Categories: PARCEL_COUNT_TOTAL, _OWNER, _GROUP, _OTHER, _SELECTED, _TEMP. +Returns the number of prims on the parcel at pos of the given category. +Categories: PARCEL_COUNT_TOTAL, _OWNER, _GROUP, _OTHER, _SELECTED, _TEMP </string> <string name="LSLTipText_llGetParcelMaxPrims"> integer llGetParcelMaxPrims(vector pos, integer sim_wide) -Gets the maximum number of prims allowed on the parcel at pos. +Returns the maximum number of prims allowed on the parcel at pos </string> <string name="LSLTipText_llGetParcelDetails"> list llGetParcelDetails(vector pos, list params) -Gets the parcel details specified in params for the parcel at pos. +Returns the parcel details specified in params for the parcel at pos. Params is one or more of: PARCEL_DETAILS_NAME, _DESC, _OWNER, _GROUP, _AREA </string> <string name="LSLTipText_llSetLinkPrimitiveParams"> llSetLinkPrimitiveParams(integer linknumber, list rules) -Set primitive parameters for linknumber based on rules. +Sets primitive parameters for linknumber based on rules </string> <string name="LSLTipText_llSetLinkTexture"> -llSetLinkTexture(integer link_pos, string texture, integer face) -Sets the texture of face for link_pos +llSetLinkTexture(integer linknumber, string texture, integer face) +Sets the texture of face for a task that exists in the link chain at linknumber </string> <string name="LSLTipText_llStringTrim"> string llStringTrim(string src, integer trim_type) -Trim leading and/or trailing spaces from a string. -Uses trim_type of STRING_TRIM, STRING_TRIM_HEAD or STRING_TRIM_TAIL. +Trims the leading and/or trailing white spaces from a string. +trim_type can be STRING_TRIM, STRING_TRIM_HEAD or STRING_TRIM_TAIL. </string> <string name="LSLTipText_llRegionSay"> llRegionSay(integer channel, string msg) -broadcasts msg to entire region on channel (not 0.) +Broadcasts msg on channel (not 0) that can be heard anywhere in the region by a script listening on channel </string> <string name="LSLTipText_llGetObjectDetails"> list llGetObjectDetails(key id, list params) -Gets the object details specified in params for the object with key id. -Details are OBJECT_NAME, _DESC, _POS, _ROT, _VELOCITY, _OWNER, _GROUP, _CREATOR. +Returns the object details specified in params for the object with key id. +Params are OBJECT_NAME, _DESC, _POS, _ROT, _VELOCITY, _OWNER, _GROUP, _CREATOR </string> <string name="LSLTipText_llSetClickAction"> llSetClickAction(integer action) -Sets the action performed when a prim is clicked upon. +Sets the action performed when a prim is clicked upon </string> <string name="LSLTipText_llGetRegionAgentCount"> -int llGetRegionAgentCount() -returns the number of agents in a region +integer llGetRegionAgentCount() +Returns the number of avatars in the region </string> <string name="LSLTipText_llTextBox"> llTextBox(key avatar, string message, integer chat_channel -Shows a dialog box on the avatar's screen with the message. -A text box asks for input, and if entered the text is chatted on chat_channel. +Shows a dialog box on the avatar's screen with the message. +It contains a text box for input, and if entered that text is chatted on chat_channel. </string> <string name="LSLTipText_llGetAgentLanguage"> -string llGetAgentLanguage(key id) -Gets the agents preferred language.. +string llGetAgentLanguage(key avatar) +Returns the language code of the preferred interface language of the avatar </string> <string name="LSLTipText_llDetectedTouchUV"> -vector llDetectedTouchUV(integer number) -returns the u and v coordinates in the first two components of a vector, for a triggered touch event +vector llDetectedTouchUV(integer index) +Returns the u and v coordinates in the first two components of a vector, for the texture coordinates where the prim was touched in a triggered touch event </string> <string name="LSLTipText_llDetectedTouchFace"> -integer llDetectedTouchFace(integer number) -returns the index of the face on the object for a triggered touch event +integer llDetectedTouchFace(integer index) +Returns the index of the face where the avatar clicked in a triggered touch event </string> <string name="LSLTipText_llDetectedTouchPos"> -vector llDetectedTouchPos(integer number) -returns the position touched for a triggered touch event +vector llDetectedTouchPos(integer index) +Returns the position where the object was touched in a triggered touch event </string> <string name="LSLTipText_llDetectedTouchNormal"> -vector llDetectedTouchNormal(integer number) -returns the surface normal for a triggered touch event +vector llDetectedTouchNormal(integer index) +Returns the surface normal for a triggered touch event </string> <string name="LSLTipText_llDetectedTouchBinormal"> -vector llDetectedTouchBinormal(integer number) -returns the surface binormal for a triggered touch event +vector llDetectedTouchBinormal(integer index) +Returns the surface binormal for a triggered touch event </string> <string name="LSLTipText_llDetectedTouchST"> -vector llDetectedTouchST(integer number) -returns the s and t coordinates in the first two components of a vector, for a triggered touch event +vector llDetectedTouchST(integer index) +Returns the s and t coordinates in the first two components of a vector, for the surface coordinates where the prim was touched in a triggered touch event </string> <string name="LSLTipText_llSHA1String"> -string llSHA1String(string sr) -Performs a SHA1 security Hash. Returns a 40 character hex string. +string llSHA1String(string src) +Returns a string of 40 hex characters that is the SHA1 security Hash of src </string> <string name="LSLTipText_llGetFreeURLs"> integer llGetFreeURLs() -returns the available urls for the current script +Returns the number of available URLs for the current script </string> <string name="LSLTipText_llRequestURL"> key llRequestURL() -Requests one HTTP:// url for use by this object -Triggers an http_server event with results. +Requests one HTTP:// url for use by this object. +An http_request event is triggered with the results. </string> <string name="LSLTipText_llRequestSecureURL"> key llRequestSecureURL() -Requests one HTTPS:// (SSL) url for use by this object -Triggers an http_server event with results. +Requests one HTTPS:// (SSL) url for use by this object. +An http_request event is triggered with the results. </string> <string name="LSLTipText_llReleaseURL"> llReleaseURL(string url) -Releases the specified URL, it will no longer be usable. +Releases the specified URL, it will no longer be usable </string> <string name="LSLTipText_llHTTPResponse"> -llHTTPResponse(key id, integer status, string body) -Responds to request id with status and body. - </string> +llHTTPResponse(key request_id, integer status, string body) +Responds to request_id with status and body + </string> <string name="LSLTipText_llGetHTTPHeader"> -string llGetHTTPHeader(key id, string header) -Get the value for header for request id. - </string> - - <!-- Avatar busy/away mode --> +string llGetHTTPHeader(key request_id, string header) +Returns the value for header for request_id + </string> + <string name="LSLTipText_llSetPrimMediaParams"> +llSetPrimMediaParams(integer face, list params) +Sets the media params for a particular face on an object. If media is not already on this object, add it. +List is a set of name/value pairs in no particular order. Params not specified are unchanged, or if new media is added then set to the default specified. +The possible names are below, along with the types of values and what they mean. + </string> + <string name="LSLTipText_llGetPrimMediaParams"> +list llGetPrimMediaParams(integer face, list params) +Returns the media params for a particular face on an object, given the desired list of names, in the order requested. +(Returns an empty list if no media exists on the face.) + </string> + <string name="LSLTipText_llClearPrimMedia"> +llClearPrimMedia(integer face) +Clears (deletes) the media and all params from the given face. + </string> + + <!-- Avatar busy/away mode --> <string name="AvatarSetNotAway">Set Not Away</string> <string name="AvatarSetAway">Set Away</string> <string name="AvatarSetNotBusy">Set Not Busy</string> diff --git a/indra/newview/skins/default/xui/en/widgets/scroll_list.xml b/indra/newview/skins/default/xui/en/widgets/scroll_list.xml index cb876da8d8..824a815a99 100644 --- a/indra/newview/skins/default/xui/en/widgets/scroll_list.xml +++ b/indra/newview/skins/default/xui/en/widgets/scroll_list.xml @@ -10,9 +10,9 @@ highlighted_color="ScrollHighlightedColor" column_padding="5" draw_stripes="true" + scroll_bar_bg_visible="false" + scroll_bar_bg_color="black" background_visible="false" heading_height="23" draw_border="false" - draw_heading="false" - scroll_bar_bg_visible="false" - scroll_bar_bg_color="black" /> + draw_heading="false" /> diff --git a/indra/newview/skins/default/xui/en/widgets/search_combo_box.xml b/indra/newview/skins/default/xui/en/widgets/search_combo_box.xml index 6e73e997e0..e998635d20 100644 --- a/indra/newview/skins/default/xui/en/widgets/search_combo_box.xml +++ b/indra/newview/skins/default/xui/en/widgets/search_combo_box.xml @@ -12,17 +12,20 @@ <combo_editor select_on_focus="true" text_pad_left="20" + tool_tip="Search" background_image="TextField_Search_Off" background_image_disabled="TextField_Search_Disabled" background_image_focused="TextField_Search_Active"/> <combo_list multi_select="false" - page_lines="10" /> + page_lines="10" + scroll_bar_bg_visible="true" /> <search_button label="" top_pad="4" left_pad="4" width="13" height="13" + tool_tip="Search" image_unselected="Search" image_selected="Search" /> </search_combo_box>
\ No newline at end of file diff --git a/indra/newview/tests/llviewerhelputil_test.cpp b/indra/newview/tests/llviewerhelputil_test.cpp new file mode 100644 index 0000000000..40f7d532bc --- /dev/null +++ b/indra/newview/tests/llviewerhelputil_test.cpp @@ -0,0 +1,127 @@ +/** + * @file llviewerhelputil_test.cpp + * @brief LLViewerHelpUtil tests + * @author Tofu Linden + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "../test/lltut.h" + +#include "../llviewerhelputil.h" +#include "llcontrol.h" +#include "llsys.h" + +#include <iostream> + +//---------------------------------------------------------------------------- +// Implementation of enough of LLControlGroup to support the tests: + +static std::map<std::string,std::string> test_stringvec; + +LLControlGroup::LLControlGroup(const std::string& name) + : LLInstanceTracker<LLControlGroup, std::string>(name) +{ +} + +LLControlGroup::~LLControlGroup() +{ +} + +// Implementation of just the LLControlGroup methods we requre +BOOL LLControlGroup::declareString(const std::string& name, + const std::string& initial_val, + const std::string& comment, + BOOL persist) +{ + test_stringvec[name] = initial_val; + return true; +} + +void LLControlGroup::setString(const std::string& name, const std::string& val) +{ + test_stringvec[name] = val; +} + +std::string LLControlGroup::getString(const std::string& name) +{ + return test_stringvec[name]; +} + +//---------------------------------------------------------------------------- + +namespace tut +{ + struct viewerhelputil + { + }; + + typedef test_group<viewerhelputil> viewerhelputil_t; + typedef viewerhelputil_t::object viewerhelputil_object_t; + tut::viewerhelputil_t tut_viewerhelputil("viewerhelputil"); + + template<> template<> + void viewerhelputil_object_t::test<1>() + { + LLOSInfo osinfo; + LLControlGroup cgr("test"); + cgr.declareString("HelpURLFormat", "fooformat", "declared_for_test", FALSE); + cgr.declareString("VersionChannelName", "foochannelname", "declared_for_test", FALSE); + cgr.declareString("Language", "foolanguage", "declared_for_test", FALSE); + std::string topic("test_topic"); + + std::string subresult; + + cgr.setString("HelpURLFormat", "fooformat"); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("no substitution tags", subresult, "fooformat"); + + cgr.setString("HelpURLFormat", ""); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("blank substitution format", subresult, ""); + + cgr.setString("HelpURLFormat", "[LANGUAGE]"); + cgr.setString("Language", ""); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("simple substitution with blank", subresult, ""); + + cgr.setString("HelpURLFormat", "[LANGUAGE]"); + cgr.setString("Language", "Esperanto"); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("simple substitution", subresult, "Esperanto"); + + cgr.setString("HelpURLFormat", "[XXX]"); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("unknown substitution", subresult, "[XXX]"); + + cgr.setString("HelpURLFormat", "[LANGUAGE]/[LANGUAGE]"); + cgr.setString("Language", "Esperanto"); + subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo); + ensure_equals("multiple substitution", subresult, "Esperanto/Esperanto"); + } + +} diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index e85fddbc99..036fa4923f 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -169,6 +169,12 @@ class WindowsManifest(ViewerManifest): # the final exe is complicated because we're not sure where it's coming from, # nor do we have a fixed name for the executable self.path(self.find_existing_file('debug/secondlife-bin.exe', 'release/secondlife-bin.exe', 'relwithdebinfo/secondlife-bin.exe'), dst=self.final_exe()) + + # Plugin host application + self.path(os.path.join(os.pardir, + 'llplugin', 'slplugin', self.args['configuration'], "slplugin.exe"), + "slplugin.exe") + # need to get the kdu dll from any of the build directories as well try: self.path(self.find_existing_file('../llkdu/%s/llkdu.dll' % self.args['configuration'], @@ -193,11 +199,6 @@ class WindowsManifest(ViewerManifest): self.path("openjpeg.dll") self.end_prefix() - # Plugin host application - if self.prefix(src='../llplugin/slplugin/%s' % self.args['configuration'], dst="llplugin"): - self.path("slplugin.exe") - self.end_prefix() - # Media plugins - QuickTime if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): self.path("media_plugin_quicktime.dll") @@ -248,10 +249,12 @@ class WindowsManifest(ViewerManifest): # Vivox runtimes if self.prefix(src="vivox-runtime/i686-win32", dst=""): self.path("SLVoice.exe") - self.path("alut.dll") + self.path("libsndfile-1.dll") + self.path("zlib1.dll") self.path("vivoxsdk.dll") + self.path("vivoxplatform.dll") self.path("ortp.dll") - self.path("wrap_oal.dll") + self.path("vivoxoal.dll") self.end_prefix() # pull in the crash logger and updater from other projects @@ -461,10 +464,11 @@ class DarwinManifest(ViewerManifest): self.path("zh-Hans.lproj") # SLVoice and vivox lols - self.path("vivox-runtime/universal-darwin/libalut.dylib", "libalut.dylib") - self.path("vivox-runtime/universal-darwin/libopenal.dylib", "libopenal.dylib") + self.path("vivox-runtime/universal-darwin/libsndfile.dylib", "libsndfile.dylib") + self.path("vivox-runtime/universal-darwin/libvivoxoal.dylib", "libvivoxoal.dylib") self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib") self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib") + self.path("vivox-runtime/universal-darwin/libvivoxplatform.dylib", "libvivoxplatform.dylib") self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice") # need to get the kdu dll from any of the build directories as well @@ -484,9 +488,11 @@ class DarwinManifest(ViewerManifest): self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app") self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app") + # plugin launcher + self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin", "SLPlugin") + # plugins if self.prefix(src="", dst="llplugin"): - self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin", "SLPlugin") self.path("../media_plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib") self.path("../media_plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib") self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib") @@ -677,6 +683,7 @@ class Linux_i686Manifest(LinuxManifest): self.path("secondlife-stripped","bin/do-not-directly-run-secondlife-bin") self.path("../linux_crash_logger/linux-crash-logger-stripped","bin/linux-crash-logger.bin") self.path("../linux_updater/linux-updater-stripped", "bin/linux-updater.bin") + self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin") if self.prefix("res-sdl"): self.path("*") # recurse @@ -684,7 +691,6 @@ class Linux_i686Manifest(LinuxManifest): # plugins if self.prefix(src="", dst="bin/llplugin"): - self.path("../llplugin/slplugin/SLPlugin", "SLPlugin") self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so") self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_quicktime.so") self.end_prefix("bin/llplugin") @@ -715,7 +721,10 @@ class Linux_i686Manifest(LinuxManifest): self.end_prefix() if self.prefix(src="vivox-runtime/i686-linux", dst="lib"): self.path("libortp.so") + self.path("libsndfile.so.1") + self.path("libvivoxoal.so.1") self.path("libvivoxsdk.so") + self.path("libvivoxplatform.so") self.end_prefix("lib") class Linux_x86_64Manifest(LinuxManifest): diff --git a/install.xml b/install.xml index 225dc76a9a..0f8b4ac465 100644 --- a/install.xml +++ b/install.xml @@ -1334,23 +1334,23 @@ anguage Infrstructure (CLI) international standard</string> <key>darwin</key> <map> <key>md5sum</key> - <string>8675b5eedef038b514338b17f0e55961</string> + <string>3eb4b31e92e16567e2fa967df9f9b845</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-darwin-20090309.tar.bz2</uri> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-3.0.0006.7278-darwin-20090930a.tar.bz2</uri> </map> <key>linux</key> <map> <key>md5sum</key> - <string>01573510dce7f380f44e561ef2f3dd9f</string> + <string>61ab6acd1f4736c5260c492bb60c26af</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-linux-20090309.tar.bz2</uri> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-3.0.0006.7278-linux-20090930a.tar.bz2</uri> </map> <key>windows</key> <map> <key>md5sum</key> - <string>752daa90e07c05202d1f76980cb955eb</string> + <string>ad5737dbfab87a13b23451b68248b22a</string> <key>url</key> - <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-windows-20090309.tar.bz2</uri> + <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-3.0.0006.7278-windows-20090930a.tar.bz2</uri> </map> </map> </map> |