diff options
Diffstat (limited to 'indra/newview')
46 files changed, 557 insertions, 280 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 92f701551b..65502209f7 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1321,8 +1321,6 @@ set(viewer_APPSETTINGS_FILES ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg ) -use_prebuilt_binary(artwork-common) - source_group("App Settings" FILES ${viewer_APPSETTINGS_FILES}) set_source_files_properties(${viewer_APPSETTINGS_FILES} diff --git a/indra/newview/app_settings/static_data.db2 b/indra/newview/app_settings/static_data.db2 Binary files differnew file mode 100644 index 0000000000..f85aa81601 --- /dev/null +++ b/indra/newview/app_settings/static_data.db2 diff --git a/indra/newview/app_settings/static_index.db2 b/indra/newview/app_settings/static_index.db2 Binary files differnew file mode 100644 index 0000000000..a5440f96f2 --- /dev/null +++ b/indra/newview/app_settings/static_index.db2 diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index ec3c7452e5..c70bbb985f 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -2310,6 +2310,7 @@ void LLAgentCamera::changeCameraToCustomizeAvatar() setAnimationDuration(turn_motion->getDuration() + CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP); } + gAgentAvatarp->invalidateAll(); gAgentAvatarp->updateMeshTextures(); } } diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index e70511ce6e..efa5eca217 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -511,7 +511,11 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U32 index) { LLWearable* wearable = getWearable(type, index); - wearable->revertValues(); + llassert(wearable); + if (wearable) + { + wearable->revertValues(); + } gAgent.sendAgentSetAppearance(); } @@ -543,6 +547,7 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string& { LLWearable* old_wearable = getWearable((LLWearableType::EType)i,j); llassert(old_wearable); + if (!old_wearable) continue; std::string old_name = old_wearable->getName(); old_wearable->setName(new_name); @@ -1940,7 +1945,11 @@ void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake) for (S32 count = 0; count < (S32)getWearableCount((LLWearableType::EType)type); ++count) { LLWearable *wearable = getWearable((LLWearableType::EType)type,count); - wearable->animateParams(delta, upload_bake); + llassert(wearable); + if (wearable) + { + wearable->animateParams(delta, upload_bake); + } } } } diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index b5ad5c7a11..f8cff42412 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -989,22 +989,15 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up { removeCOFItemLinks(gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1), false); } + addCOFItemLink(item_to_wear, do_update); } + break; case LLAssetType::AT_BODYPART: - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); - return false; - } - + // TODO: investigate wearables may not be loaded at this point EXT-8231 + // Remove the existing wearables of the same type. // Remove existing body parts anyway because we must not be able to wear e.g. two skins. - if (item_to_wear->getType() == LLAssetType::AT_BODYPART) - { - removeCOFLinksOfType(item_to_wear->getWearableType(), false); - } + removeCOFLinksOfType(item_to_wear->getWearableType(), false); addCOFItemLink(item_to_wear, do_update); break; @@ -2596,7 +2589,7 @@ void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items, { asset_id = linked_item->getAssetUUID(); } - llinfos << msg << " " << i <<" " << item->getName() << " " << asset_id.asString() << llendl; + llinfos << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << llendl; } llinfos << llendl; } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index dc514eafe7..682e3eb874 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -82,6 +82,8 @@ #include "llvoavatarself.h" #include "llsidetray.h" #include "llfeaturemanager.h" +#include "llurlmatch.h" +#include "lltextutil.h" #include "llweb.h" #include "llsecondlifeurls.h" @@ -192,6 +194,7 @@ #include "llviewerthrottle.h" #include "llparcel.h" #include "llavatariconctrl.h" +#include "llgroupiconctrl.h" // Include for security api initialization #include "llsecapi.h" @@ -351,6 +354,45 @@ static void ui_audio_callback(const LLUUID& uuid) } } +bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base) +{ + if(!match || !base) + return false; + + LLUUID match_id = match->getID(); + + LLIconCtrl* icon; + + if(gAgent.isInGroup(match_id, TRUE)) + { + LLGroupIconCtrl::Params icon_params = LLUICtrlFactory::instance().getDefaultParams<LLGroupIconCtrl>(); + icon_params.group_id = match_id; + icon_params.rect = LLRect(0, 16, 16, 0); + icon_params.visible = true; + icon = LLUICtrlFactory::instance().createWidget<LLGroupIconCtrl>(icon_params); + } + else + { + LLAvatarIconCtrl::Params icon_params = LLUICtrlFactory::instance().getDefaultParams<LLAvatarIconCtrl>(); + icon_params.avatar_id = match_id; + icon_params.rect = LLRect(0, 16, 16, 0); + icon_params.visible = true; + icon = LLUICtrlFactory::instance().createWidget<LLAvatarIconCtrl>(icon_params); + } + + LLInlineViewSegment::Params params; + params.force_newline = false; + params.view = icon; + params.left_pad = 4; + params.right_pad = 4; + params.top_pad = 2; + params.bottom_pad = 2; + + base->appendWidget(params," ",false); + + return true; +} + void request_initial_instant_messages() { static BOOL requested = FALSE; @@ -887,6 +929,7 @@ bool LLAppViewer::init() } LLViewerMedia::initClass(); + LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match; //EXT-7013 - On windows for some locale (Japanese) standard //datetime formatting functions didn't support some parameters such as "weekday". diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index 60a2392d87..b494470cbc 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -449,7 +449,7 @@ void LLCallFloater::updateAgentModeratorState() if(gAgent.isInGroup(mSpeakerManager->getSessionID())) { // This method can be called when LLVoiceChannel.mState == STATE_NO_CHANNEL_INFO - // in this case there are no any speakers yet. + // in this case there are not any speakers yet. if (mSpeakerManager->findSpeaker(gAgentID)) { // Agent is Moderator diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index ac12bffdfb..c0fa910f86 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -557,11 +557,14 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL { bool use_plain_text_chat_history = args["use_plain_text_chat_history"].asBoolean(); - if(mEditor) + llassert(mEditor); + if (!mEditor) { - mEditor->setPlainText(use_plain_text_chat_history); + return; } + mEditor->setPlainText(use_plain_text_chat_history); + if (!mEditor->scrolledToEnd() && chat.mFromID != gAgent.getID() && !chat.mFromName.empty()) { mUnreadChatSources.insert(chat.mFromName); @@ -740,7 +743,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL mIsLastMessageFromLog = message_from_log; } - if (chat.mNotifId.notNull()) + if (chat.mNotifId.notNull()) { LLNotificationPtr notification = LLNotificationsUtil::find(chat.mNotifId); if (notification != NULL) @@ -832,6 +835,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL mEditor->appendText(message, FALSE, style_params); } + mEditor->blockUndo(); // automatically scroll to end when receiving chat from myself diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp index 472d2ccf24..d83706de52 100644 --- a/indra/newview/llcofwearables.cpp +++ b/indra/newview/llcofwearables.cpp @@ -281,7 +281,11 @@ LLCOFWearables::LLCOFWearables() : LLPanel(), mAttachments(NULL), mClothing(NULL), mBodyParts(NULL), - mLastSelectedList(NULL) + mLastSelectedList(NULL), + mClothingTab(NULL), + mAttachmentsTab(NULL), + mBodyPartsTab(NULL), + mLastSelectedTab(NULL) { mClothingMenu = new CofClothingContextMenu(this); mAttachmentMenu = new CofAttachmentContextMenu(this); @@ -319,6 +323,16 @@ BOOL LLCOFWearables::postBuild() mAttachments->setComparator(&WEARABLE_NAME_COMPARATOR); mBodyParts->setComparator(&WEARABLE_NAME_COMPARATOR); + + mClothingTab = getChild<LLAccordionCtrlTab>("tab_clothing"); + mClothingTab->setDropDownStateChangedCallback(boost::bind(&LLCOFWearables::onAccordionTabStateChanged, this, _1, _2)); + + mAttachmentsTab = getChild<LLAccordionCtrlTab>("tab_attachments"); + mAttachmentsTab->setDropDownStateChangedCallback(boost::bind(&LLCOFWearables::onAccordionTabStateChanged, this, _1, _2)); + + mBodyPartsTab = getChild<LLAccordionCtrlTab>("tab_body_parts"); + mBodyPartsTab->setDropDownStateChangedCallback(boost::bind(&LLCOFWearables::onAccordionTabStateChanged, this, _1, _2)); + return LLPanel::postBuild(); } @@ -338,6 +352,28 @@ void LLCOFWearables::onSelectionChange(LLFlatListView* selected_list) onCommit(); } +void LLCOFWearables::onAccordionTabStateChanged(LLUICtrl* ctrl, const LLSD& expanded) +{ + bool had_selected_items = mClothing->numSelected() || mAttachments->numSelected() || mBodyParts->numSelected(); + mClothing->resetSelection(true); + mAttachments->resetSelection(true); + mBodyParts->resetSelection(true); + + bool tab_selection_changed = false; + LLAccordionCtrlTab* tab = dynamic_cast<LLAccordionCtrlTab*>(ctrl); + if (tab && tab != mLastSelectedTab) + { + mLastSelectedTab = tab; + tab_selection_changed = true; + } + + if (had_selected_items || tab_selection_changed) + { + //sending commit signal to indicate selection changes + onCommit(); + } +} + void LLCOFWearables::refresh() { typedef std::vector<LLSD> values_vector_t; @@ -372,6 +408,11 @@ void LLCOFWearables::refresh() iter != iter_end; ++iter) { LLFlatListView* list = iter->first; + if (!list) continue; + + //restoring selection should not fire commit callbacks + list->setCommitOnSelectionChange(false); + const values_vector_t& values = iter->second; for (values_vector_t::const_iterator value_it = values.begin(), @@ -385,6 +426,8 @@ void LLCOFWearables::refresh() list->selectItemByValue(*value_it); } } + + list->setCommitOnSelectionChange(true); } } @@ -610,6 +653,30 @@ LLAssetType::EType LLCOFWearables::getExpandedAccordionAssetType() return result; } +LLAssetType::EType LLCOFWearables::getSelectedAccordionAssetType() +{ + //*TODO share the code with ::getExpandedAccordionAssetType(...) + static LLAccordionCtrl* accordion_ctrl = getChild<LLAccordionCtrl>("cof_wearables_accordion"); + const LLAccordionCtrlTab* selected_tab = accordion_ctrl->getSelectedTab(); + + if (selected_tab == mClothingTab) + { + return LLAssetType::AT_CLOTHING; + } + else if (selected_tab == mAttachmentsTab) + { + return LLAssetType::AT_OBJECT; + } + else if (selected_tab == mBodyPartsTab) + { + return LLAssetType::AT_BODYPART; + } + else + { + return LLAssetType::AT_NONE; + } +} + void LLCOFWearables::onListRightClick(LLUICtrl* ctrl, S32 x, S32 y, LLListContextMenu* menu) { if(menu) diff --git a/indra/newview/llcofwearables.h b/indra/newview/llcofwearables.h index 62f4cfc692..de148e0d46 100644 --- a/indra/newview/llcofwearables.h +++ b/indra/newview/llcofwearables.h @@ -40,6 +40,7 @@ #include "llappearancemgr.h" #include "llinventorymodel.h" +class LLAccordionCtrlTab; class LLListContextMenu; class LLPanelClothingListItem; class LLPanelBodyPartsListItem; @@ -84,6 +85,7 @@ public: void clear(); LLAssetType::EType getExpandedAccordionAssetType(); + LLAssetType::EType getSelectedAccordionAssetType(); LLCOFCallbacks& getCOFCallbacks() { return mCOFCallbacks; } @@ -94,6 +96,7 @@ protected: void addClothingTypesDummies(const LLAppearanceMgr::wearables_by_type_t& clothing_by_type); void onSelectionChange(LLFlatListView* selected_list); + void onAccordionTabStateChanged(LLUICtrl* ctrl, const LLSD& expanded); LLPanelClothingListItem* buildClothingListItem(LLViewerInventoryItem* item, bool first, bool last); LLPanelBodyPartsListItem* buildBodypartListItem(LLViewerInventoryItem* item); @@ -107,6 +110,12 @@ protected: LLFlatListView* mLastSelectedList; + LLAccordionCtrlTab* mClothingTab; + LLAccordionCtrlTab* mAttachmentsTab; + LLAccordionCtrlTab* mBodyPartsTab; + + LLAccordionCtrlTab* mLastSelectedTab; + LLCOFCallbacks mCOFCallbacks; LLListContextMenu* mClothingMenu; diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 4792d761d8..0a5499b166 100644 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -557,8 +557,6 @@ BOOL LLPanelScriptLimitsRegionMemory::getLandScriptResources() void LLPanelScriptLimitsRegionMemory::processParcelInfo(const LLParcelData& parcel_data) { - mParcelId = parcel_data.parcel_id; - if(!getLandScriptResources()) { std::string msg_error = LLTrans::getString("ScriptLimitsRequestError"); @@ -580,6 +578,7 @@ void LLPanelScriptLimitsRegionMemory::setParcelID(const LLUUID& parcel_id) LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); mParcelId.setNull(); } + mParcelId = parcel_id; LLRemoteParcelInfoProcessor::getInstance()->addObserver(parcel_id, this); LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id); } diff --git a/indra/newview/llfloatervoiceeffect.cpp b/indra/newview/llfloatervoiceeffect.cpp index ca1f142760..61fe50e301 100644 --- a/indra/newview/llfloatervoiceeffect.cpp +++ b/indra/newview/llfloatervoiceeffect.cpp @@ -199,7 +199,12 @@ void LLFloaterVoiceEffect::refreshEffectList() if(sl_item) { LLFontGL::StyleFlags style = is_template_only ? LLFontGL::NORMAL : LLFontGL::BOLD; - dynamic_cast<LLScrollListText*>(sl_item->getColumn(0))->setFontStyle(style); + LLScrollListText* slt = dynamic_cast<LLScrollListText*>(sl_item->getColumn(0)); + llassert(slt); + if (slt) + { + slt->setFontStyle(style); + } } } } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 96dba5717a..9e7224d9b8 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1619,85 +1619,71 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, BOOL drop) { - // This should never happen, but if an inventory item is incorrectly parented, - // the UI will get confused and pass in a NULL. - if(!inv_cat) return FALSE; LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; + if (!inv_cat) return FALSE; // shouldn't happen, but in case item is incorrectly parented in which case inv_cat will be NULL + if (!model) return FALSE; if (!isAgentAvatarValid()) return FALSE; + if (!isAgentInventory()) return FALSE; // cannot drag categories into library - // cannot drag categories into library - if(!isAgentInventory()) - { - return FALSE; - } // check to make sure source is agent inventory, and is represented there. LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); - BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL) + const BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL) && (LLToolDragAndDrop::SOURCE_AGENT == source); BOOL accept = FALSE; - S32 i; - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - if(is_agent_inventory) + if (is_agent_inventory) { - const LLUUID& cat_id = inv_cat->getUUID(); + const LLUUID &cat_id = inv_cat->getUUID(); + const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false); + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + + const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); + const BOOL move_is_into_outfit = getCategory() && (getCategory()->getPreferredType() == LLFolderType::FT_OUTFIT); + const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - // Is the destination the trash? - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - BOOL move_is_into_trash = (mUUID == trash_id) - || model->isObjectDescendentOf(mUUID, trash_id); - BOOL is_movable = (!LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())); - const LLUUID current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - if (move_is_into_current_outfit || move_is_into_outfit) - { - // BAP - restrictions? - is_movable = true; - } + //-------------------------------------------------------------------------------- + // Determine if folder can be moved. + // + BOOL is_movable = TRUE; + if (LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())) + is_movable = FALSE; + if (move_is_into_outfit) + is_movable = FALSE; if (mUUID == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE)) + is_movable = FALSE; + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + gInventory.collectDescendents(cat_id, descendent_categories, descendent_items, FALSE); + for (S32 i=0; i < descendent_categories.count(); ++i) { - is_movable = FALSE; // It's generally movable but not into Favorites folder. EXT-1604 + LLInventoryCategory* category = descendent_categories[i]; + if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) + { + // Can't move "special folders" (e.g. Textures Folder). + is_movable = FALSE; + break; + } } - - if( is_movable ) + if (move_is_into_trash) { - gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE ); - - for( i = 0; i < descendent_categories.count(); i++ ) + for (S32 i=0; i < descendent_items.count(); ++i) { - LLInventoryCategory* category = descendent_categories[i]; - if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) + LLInventoryItem* item = descendent_items[i]; + if (get_is_item_worn(item->getUUID())) { - // ...can't move "special folders" like Textures is_movable = FALSE; - break; - } - } - - if( is_movable ) - { - if( move_is_into_trash ) - { - for( i = 0; i < descendent_items.count(); i++ ) - { - LLInventoryItem* item = descendent_items[i]; - if (get_is_item_worn(item->getUUID())) - { - is_movable = FALSE; - break; // It's generally movable, but not into the trash! - } - } + break; // It's generally movable, but not into the trash. } } } + // + //-------------------------------------------------------------------------------- + accept = is_movable && (mUUID != cat_id) // Can't move a folder into itself && (mUUID != inv_cat->getParentUUID()) // Avoid moves that would change nothing @@ -1707,7 +1693,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, // Look for any gestures and deactivate them if (move_is_into_trash) { - for (i = 0; i < descendent_items.count(); i++) + for (S32 i=0; i < descendent_items.count(); i++) { LLInventoryItem* item = descendent_items[i]; if (item->getType() == LLAssetType::AT_GESTURE @@ -2617,11 +2603,6 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) gInventory.addObserver(fetch); } } - else - { - mItems.push_back(std::string("--no options--")); - mDisabledItems.push_back(std::string("--no options--")); - } // Preemptively disable system folder removal if more than one item selected. if ((flags & FIRST_SELECTED_ITEM) == 0) @@ -2635,6 +2616,12 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) mDisabledItems.push_back(std::string("Share")); } + if (mItems.empty()) + { + mItems.push_back(std::string("--no options--")); + mDisabledItems.push_back(std::string("--no options--")); + } + hide_context_entries(menu, mItems, mDisabledItems); } @@ -2847,18 +2834,16 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response return false; } +// This is used both for testing whether an item can be dropped +// into the folder, as well as performing the actual drop, depending +// if drop == TRUE. BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop) { LLInventoryModel* model = getInventoryModel(); - if(!model || !inv_item) return FALSE; - - // cannot drag into library - if(!isAgentInventory()) - { - return FALSE; - } + if(!model || !inv_item) return FALSE; + if(!isAgentInventory()) return FALSE; // cannot drag into library if (!isAgentAvatarValid()) return FALSE; LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); @@ -2866,8 +2851,23 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, LLViewerObject* object = NULL; if(LLToolDragAndDrop::SOURCE_AGENT == source) { + const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false); + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false); + + const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); + const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); + const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID()); + const BOOL folder_allows_reorder = (mUUID == favorites_id); + + //-------------------------------------------------------------------------------- + // Determine if item can be moved. + // + BOOL is_movable = TRUE; - switch( inv_item->getActualType() ) + + switch (inv_item->getActualType()) { case LLAssetType::AT_CATEGORY: is_movable = !LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)inv_item)->getPreferredType()); @@ -2875,41 +2875,50 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, default: break; } - - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); - const LLUUID current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID()); - // Can't explicitly drag things out of the COF. if (move_is_outof_current_outfit) { is_movable = FALSE; } - - if(is_movable && move_is_into_trash) + if (move_is_into_trash) { - is_movable = inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID()); + is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID()); } - - if ( is_movable ) + if (is_movable) { // Don't allow creating duplicates in the Calling Card/Friends // subfolders, see bug EXT-1599. Check is item direct descendent // of target folder and forbid item's movement if it so. // Note: isItemDirectDescendentOfCategory checks if // passed category is in the Calling Card/Friends folder - is_movable = ! LLFriendCardsManager::instance() - .isObjDirectDescendentOfCategory (inv_item, getCategory()); + is_movable &= !LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(inv_item, getCategory()); + } + + // + //-------------------------------------------------------------------------------- + + //-------------------------------------------------------------------------------- + // Determine if item can be moved & dropped + // + + accept = TRUE; + + if (!is_movable) + accept = FALSE; + if ((mUUID == inv_item->getParentUUID()) && !folder_allows_reorder) + accept = FALSE; + if (move_is_into_current_outfit || move_is_into_outfit) + { + if ((inv_item->getInventoryType() != LLInventoryType::IT_WEARABLE) && + (inv_item->getInventoryType() != LLInventoryType::IT_GESTURE) && + (inv_item->getInventoryType() != LLInventoryType::IT_OBJECT)) + accept = FALSE; + } + if (move_is_into_current_outfit && get_is_item_worn(inv_item->getUUID())) + { + accept = FALSE; } - const LLUUID& favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - const BOOL folder_allows_reorder = (mUUID == favorites_id); - - // we can move item inside a folder only if this folder is Favorites. See EXT-719 - accept = is_movable && ((mUUID != inv_item->getParentUUID()) || folder_allows_reorder); if(accept && drop) { if (inv_item->getType() == LLAssetType::AT_GESTURE @@ -2917,10 +2926,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { LLGestureMgr::instance().deactivateGesture(inv_item->getUUID()); } - // If an item is being dragged between windows, unselect - // everything in the active window so that we don't follow - // the selection to its new location (which is very - // annoying). + // If an item is being dragged between windows, unselect everything in the active window + // so that we don't follow the selection to its new location (which is very annoying). LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); if (active_panel) { @@ -2931,7 +2938,12 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } } - // if dragging from/into favorites folder only reorder items + //-------------------------------------------------------------------------------- + // Destination folder logic + // + + // REORDER + // (only reorder the item) if ((mUUID == inv_item->getParentUUID()) && folder_allows_reorder) { LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get()); @@ -2943,7 +2955,10 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, gInventory.rearrangeFavoriteLandmarks(srcItemId, destItemId); } } - else if (favorites_id == mUUID) // if target is the favorites folder we use copy + + // FAVORITES folder + // (copy the item) + else if (favorites_id == mUUID) { // use callback to rearrange favorite landmarks after adding // to have new one placed before target (on which it was dropped). See EXT-4312. @@ -2963,38 +2978,50 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, std::string(), cb); } + // CURRENT OUTFIT or OUTFIT folder + // (link the item) else if (move_is_into_current_outfit || move_is_into_outfit) { - // BAP - should skip if dup. - if (move_is_into_current_outfit) + if ((inv_item->getInventoryType() == LLInventoryType::IT_WEARABLE) || + (inv_item->getInventoryType() == LLInventoryType::IT_GESTURE) || + (inv_item->getInventoryType() == LLInventoryType::IT_OBJECT)) { - LLAppearanceMgr::instance().addCOFItemLink(inv_item); - } - else - { - LLPointer<LLInventoryCallback> cb = NULL; - link_inventory_item( - gAgent.getID(), - inv_item->getLinkedUUID(), - mUUID, - inv_item->getName(), - inv_item->getDescription(), - LLAssetType::AT_LINK, - cb); + // BAP - should skip if dup. + if (move_is_into_current_outfit) + { + LLAppearanceMgr::instance().addCOFItemLink(inv_item); + } + else + { + LLPointer<LLInventoryCallback> cb = NULL; + link_inventory_item( + gAgent.getID(), + inv_item->getLinkedUUID(), + mUUID, + inv_item->getName(), + inv_item->getDescription(), + LLAssetType::AT_LINK, + cb); + } } } + // NORMAL or TRASH folder + // (move the item, restamp if into trash) else { - // restamp if the move is into the trash. LLInvFVBridge::changeItemParent( model, (LLViewerInventoryItem*)inv_item, mUUID, move_is_into_trash); } + + // + //-------------------------------------------------------------------------------- + } } - else if(LLToolDragAndDrop::SOURCE_WORLD == source) + else if (LLToolDragAndDrop::SOURCE_WORLD == source) { // Make sure the object exists. If we allowed dragging from // anonymous objects, it would be possible to bypass @@ -3012,7 +3039,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, BOOL is_move = FALSE; if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) && perm.allowTransferTo(gAgent.getID()))) -// || gAgent.isGodlike()) + // || gAgent.isGodlike()) { accept = TRUE; @@ -4482,13 +4509,7 @@ void LLWearableBridge::onWearOnAvatar(void* user_data) void LLWearableBridge::wearOnAvatar() { - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); - return; - } + // TODO: investigate wearables may not be loaded at this point EXT-8231 LLViewerInventoryItem* item = getItem(); if(item) @@ -4499,13 +4520,7 @@ void LLWearableBridge::wearOnAvatar() void LLWearableBridge::wearAddOnAvatar() { - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); - return; - } + // TODO: investigate wearables may not be loaded at this point EXT-8231 LLViewerInventoryItem* item = getItem(); if(item) @@ -5063,13 +5078,7 @@ BOOL LLWearableBridgeAction::isAgentInventory() const void LLWearableBridgeAction::wearOnAvatar() { - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); - return; - } + // TODO: investigate wearables may not be loaded at this point EXT-8231 LLViewerInventoryItem* item = getItem(); if(item) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 7463658003..2d11337955 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -433,13 +433,12 @@ void show_item_original(const LLUUID& item_uuid) LLPanelMainInventory* main_inventory = floater_inventory->getMainInventoryPanel(); main_inventory->onFilterEdit(""); - } - if(floater_inventory->getVisible()) - { - floater_inventory_visible = true; + if(floater_inventory->getVisible()) + { + floater_inventory_visible = true; + } } - } if(sidepanel_inventory && !floater_inventory_visible) { diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index b9e9f0fc0b..236ed9bbd1 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1660,6 +1660,17 @@ bool LLInventoryModel::loadSkeleton( } } + // Invalidate all categories that failed fetching descendents for whatever + // reason (e.g. one of the descendents was a broken link). + for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); + invalid_cat_it != invalid_categories.end(); + invalid_cat_it++) + { + LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); + cat->setVersion(NO_VERSION); + llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl; + } + // At this point, we need to set the known descendents for each // category which successfully cached so that we do not // needlessly fetch descendents for categories which we have. @@ -1682,17 +1693,6 @@ bool LLInventoryModel::loadSkeleton( } } - // Invalidate all categories that failed fetching descendents for whatever - // reason (e.g. one of the descendents was a broken link). - for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); - invalid_cat_it != invalid_categories.end(); - invalid_cat_it++) - { - LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); - cat->setVersion(NO_VERSION); - llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl; - } - if(remove_inventory_file) { // clean up the gunzipped file. diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 53a11eff04..b8590d838e 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -231,7 +231,7 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) params.rect(text_entry_rect); params.default_text(LLStringUtil::null); params.max_length_bytes(p.max_chars); - params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); + params.keystroke_callback(boost::bind(&LLLocationInputCtrl::onTextEntry, this, _1)); params.commit_on_focus_lost(false); params.follows.flags(FOLLOWS_ALL); mTextEntry = LLUICtrlFactory::create<LLURLLineEditor>(params); @@ -484,13 +484,16 @@ void LLLocationInputCtrl::onTextEntry(LLLineEditor* line_editor) KEY key = gKeyboard->currentKey(); MASK mask = gKeyboard->currentMask(TRUE); + // Typing? (moving cursor should not affect showing the list) + bool typing = mask != MASK_CONTROL && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END; + bool pasting = mask == MASK_CONTROL && key == 'V'; + if (line_editor->getText().empty()) { prearrangeList(); // resets filter hideList(); } - // Typing? (moving cursor should not affect showing the list) - else if (mask != MASK_CONTROL && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END) + else if (typing || pasting) { prearrangeList(line_editor->getText()); if (mList->getItemCount() != 0) @@ -966,7 +969,12 @@ void LLLocationInputCtrl::focusTextEntry() // if the "select_on_focus" parameter is true it places the cursor // at the beginning (after selecting text), thus screwing up updateSelection(). if (mTextEntry) + { gFocusMgr.setKeyboardFocus(mTextEntry); + + // Enable the text entry to handle accelerator keys (EXT-8104). + LLEditMenuHandler::gEditMenuHandler = mTextEntry; + } } void LLLocationInputCtrl::enableAddLandmarkButton(bool val) diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index fce666c9d4..67295179b2 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -776,7 +776,7 @@ void LLNavigationBar::showNavigationPanel(BOOL visible) { // Navigation Panel must be shown. Favorites Panel is hidden. - S32 height = mDefaultNbRect.getHeight() - mDefaultFpRect.getHeight(); + S32 height = mDefaultNbRect.getHeight() - mDefaultFpRect.getHeight() - FAVBAR_TOP_PADDING; nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), height); reshape(nbRect.getWidth(), nbRect.getHeight()); @@ -790,8 +790,11 @@ void LLNavigationBar::showNavigationPanel(BOOL visible) { // Navigation Panel must be hidden. Favorites Panel is visible. - nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), fbRect.getHeight()); - fbRect.setLeftTopAndSize(fbRect.mLeft, fbRect.getHeight(), fbRect.getWidth(), fbRect.getHeight()); + S32 fpHeight = mDefaultFpRect.getHeight() + FAVBAR_TOP_PADDING; + S32 fpTop = fpHeight - (mDefaultFpRect.getHeight() / 2) + 1; + + nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), fpHeight); + fbRect.setLeftTopAndSize(fbRect.mLeft, fpTop, fbRect.getWidth(), mDefaultFpRect.getHeight()); // this is duplicated in 'else' section because it should be called BEFORE fb->reshape reshape(nbRect.getWidth(), nbRect.getHeight()); @@ -813,8 +816,9 @@ void LLNavigationBar::showNavigationPanel(BOOL visible) } } - childSetVisible("bg_icon", fpVisible); - childSetVisible("bg_icon_no_fav", !fpVisible); + childSetVisible("bg_icon", visible && fpVisible); + childSetVisible("bg_icon_no_fav_bevel", visible && !fpVisible); + childSetVisible("bg_icon_no_nav_bevel", !visible && fpVisible); } void LLNavigationBar::showFavoritesPanel(BOOL visible) @@ -833,7 +837,7 @@ void LLNavigationBar::showFavoritesPanel(BOOL visible) // Favorites Panel must be shown. Navigation Panel is visible. S32 fbHeight = fbRect.getHeight(); - S32 newHeight = nbRect.getHeight() + fbHeight; + S32 newHeight = nbRect.getHeight() + fbHeight + FAVBAR_TOP_PADDING; nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), newHeight); fbRect.setLeftTopAndSize(mDefaultFpRect.mLeft, mDefaultFpRect.mTop, fbRect.getWidth(), fbRect.getHeight()); @@ -842,9 +846,11 @@ void LLNavigationBar::showFavoritesPanel(BOOL visible) { // Favorites Panel must be shown. Navigation Panel is hidden. - S32 fpHeight = mDefaultFpRect.getHeight(); + S32 fpHeight = mDefaultFpRect.getHeight() + FAVBAR_TOP_PADDING; + S32 fpTop = fpHeight - (mDefaultFpRect.getHeight() / 2) + 1; + nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), fpHeight); - fbRect.setLeftTopAndSize(fbRect.mLeft, fpHeight, fbRect.getWidth(), fpHeight); + fbRect.setLeftTopAndSize(fbRect.mLeft, fpTop, fbRect.getWidth(), mDefaultFpRect.getHeight()); } reshape(nbRect.getWidth(), nbRect.getHeight()); @@ -861,7 +867,7 @@ void LLNavigationBar::showFavoritesPanel(BOOL visible) // Favorites Panel must be hidden. Navigation Panel is visible. S32 fbHeight = fbRect.getHeight(); - S32 newHeight = nbRect.getHeight() - fbHeight; + S32 newHeight = nbRect.getHeight() - fbHeight - FAVBAR_TOP_PADDING; nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), newHeight); } @@ -877,8 +883,9 @@ void LLNavigationBar::showFavoritesPanel(BOOL visible) getParent()->reshape(nbRect.getWidth(), nbRect.getHeight()); } - childSetVisible("bg_icon", visible); - childSetVisible("bg_icon_no_fav", !visible); + childSetVisible("bg_icon", npVisible && visible); + childSetVisible("bg_icon_no_fav_bevel", npVisible && !visible); + childSetVisible("bg_icon_no_nav_bevel", !npVisible && visible); fb->setVisible(visible); } diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h index 03f17af09b..d21d86456e 100644 --- a/indra/newview/llnavigationbar.h +++ b/indra/newview/llnavigationbar.h @@ -111,6 +111,8 @@ public: int getDefFavBarHeight(); private: + // the distance between navigation panel and favorites panel in pixels + const static S32 FAVBAR_TOP_PADDING = 10; void rebuildTeleportHistoryMenu(); void showTeleportHistoryMenu(LLUICtrl* btn_ctrl); diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index dddfd9106f..63ffb80ff2 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -453,6 +453,12 @@ void LLOutfitsList::refreshList(const LLUUID& category_id) { // Remove accordion tab if category could not be added to observer. mAccordion->removeCollapsibleCtrl(tab); + + // kill removed tab + if (tab != NULL) + { + tab->die(); + } continue; } @@ -523,6 +529,12 @@ void LLOutfitsList::refreshList(const LLUUID& category_id) // 4. Remove outfit tab from accordion. mAccordion->removeCollapsibleCtrl(tab); + + // kill removed tab + if (tab != NULL) + { + tab->die(); + } } } @@ -889,18 +901,6 @@ void LLOutfitsList::applyFilter(const std::string& new_filter_substring) if (!new_filter_substring.empty()) { applyFilterToTab(iter->first, tab, new_filter_substring); - - if (tab->getVisible()) - { - // Open tab if it has passed the filter. - tab->setDisplayChildren(true); - } - else - { - // Set force refresh flag to refresh not visible list - // when some changes occur in it. - list->setForceRefresh(true); - } } else { @@ -953,6 +953,18 @@ void LLOutfitsList::applyFilterToTab( // Try restoring the tab selection. restoreOutfitSelection(tab, category_id); } + + if (tab->getVisible()) + { + // Open tab if it has passed the filter. + tab->setDisplayChildren(true); + } + else + { + // Set force refresh flag to refresh not visible list + // when some changes occur in it. + list->setForceRefresh(true); + } } bool LLOutfitsList::canTakeOffSelected() diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 323a07a9ab..26f0b3f48f 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1005,6 +1005,7 @@ void LLPanelEditWearable::revertChanges() mWearablePtr->revertValues(); mNameEditor->setText(mWearablePtr->getName()); updatePanelPickerControls(mWearablePtr->getType()); + updateTypeSpecificControls(mWearablePtr->getType()); gAgentAvatarp->wearableUpdated(mWearablePtr->getType(), FALSE); } diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index 709bb83fe4..b79a4f359a 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -37,6 +37,7 @@ #include "llpanelimcontrolpanel.h" #include "llagent.h" +#include "llappviewer.h" // for gDisconnected #include "llavataractions.h" #include "llavatariconctrl.h" #include "llbutton.h" @@ -163,7 +164,7 @@ BOOL LLPanelIMControlPanel::postBuild() childSetAction("pay_btn", boost::bind(&LLPanelIMControlPanel::onPayButtonClicked, this)); childSetEnabled("add_friend_btn", !LLAvatarActions::isFriend(getChild<LLAvatarIconCtrl>("avatar_icon")->getAvatarId())); - + setFocusReceivedCallback(boost::bind(&LLPanelIMControlPanel::onFocusReceived, this)); return LLPanelChatControlPanel::postBuild(); } @@ -194,6 +195,15 @@ void LLPanelIMControlPanel::onShareButtonClicked() LLAvatarActions::share(mAvatarID); } +void LLPanelIMControlPanel::onFocusReceived() +{ + // Disable all the buttons (Call, Teleport, etc) if disconnected. + if (gDisconnected) + { + setAllChildrenEnabled(FALSE); + } +} + void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id) { LLPanelChatControlPanel::setSessionId(session_id); diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h index ce8fc58e56..0a1fd70c08 100644 --- a/indra/newview/llpanelimcontrolpanel.h +++ b/indra/newview/llpanelimcontrolpanel.h @@ -95,6 +95,7 @@ private: void onShareButtonClicked(); void onTeleportButtonClicked(); void onPayButtonClicked(); + void onFocusReceived(); LLUUID mAvatarID; }; diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index fa7e06d323..29ce3449d1 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -53,6 +53,8 @@ #include "lltooldraganddrop.h" #include "llviewermenu.h" #include "llviewertexturelist.h" +#include "llsidepanelinventory.h" +#include "llsidetray.h" const std::string FILTERS_FILENAME("filters.xml"); @@ -1163,6 +1165,12 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata) return FALSE; } + if (command_name == "share") + { + LLSidepanelInventory* parent = dynamic_cast<LLSidepanelInventory*>(LLSideTray::getInstance()->getPanel("sidepanel_inventory")); + return parent ? parent->canShare() : FALSE; + } + return TRUE; } diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index ffd879dfd7..c397dd5092 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -331,6 +331,8 @@ BOOL LLPanelOutfitEdit::postBuild() childSetCommitCallback("shop_btn_1", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL); childSetCommitCallback("shop_btn_2", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL); + setVisibleCallback(boost::bind(&LLPanelOutfitEdit::onVisibilityChange, this)); + mCOFWearables = getChild<LLCOFWearables>("cof_wearables_list"); mCOFWearables->setCommitCallback(boost::bind(&LLPanelOutfitEdit::filterWearablesBySelectedItem, this)); @@ -405,10 +407,6 @@ void LLPanelOutfitEdit::onOpen(const LLSD& key) displayCurrentOutfit(); mInitialized = true; } - - showAddWearablesPanel(false); - mWearableItemsList->resetSelection(); - mInventoryItemsPanel->clearSelection(); } void LLPanelOutfitEdit::moveWearable(bool closer_to_body) @@ -578,6 +576,13 @@ void LLPanelOutfitEdit::onPlusBtnClicked(void) LLAppearanceMgr::getInstance()->wearItemOnAvatar(selected_id, true, true); } +void LLPanelOutfitEdit::onVisibilityChange() +{ + showAddWearablesPanel(false); + mWearableItemsList->resetSelection(); + mInventoryItemsPanel->clearSelection(); +} + void LLPanelOutfitEdit::onAddWearableClicked(void) { LLPanelDummyClothingListItem* item = dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem()); @@ -726,24 +731,43 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void) bool more_than_one_selected = ids.size() > 1; bool is_dummy_item = (ids.size() && dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem())); - //resetting selection if no item is selected or than one item is selected - if (nothing_selected || more_than_one_selected) + //selected and expanded accordion tabs determine filtering when no item is selected + if (nothing_selected) { - if (nothing_selected) + showWearablesListView(); + + //selected accordion tab is more priority than expanded tab when determining filtering + LLAssetType::EType type = mCOFWearables->getSelectedAccordionAssetType(); + if (type == LLAssetType::AT_NONE) { - showWearablesFolderView(); - applyFolderViewFilter(FVIT_ALL); + type = mCOFWearables->getExpandedAccordionAssetType(); } - if (more_than_one_selected) + switch (type) { - showWearablesListView(); - applyListViewFilter(LVIT_ALL); + case LLAssetType::AT_OBJECT: + applyListViewFilter(LVIT_ATTACHMENT); + break; + case LLAssetType::AT_BODYPART: + applyListViewFilter(LVIT_BODYPART); + break; + case LLAssetType::AT_CLOTHING: + default: + applyListViewFilter(LVIT_CLOTHING); + break; } return; } + //resetting selection if more than one item is selected + if (more_than_one_selected) + { + showWearablesListView(); + applyListViewFilter(LVIT_ALL); + return; + } + //filter wearables by a type represented by a dummy item if (one_selected && is_dummy_item) @@ -761,7 +785,7 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void) return; } - if (one_selected && !is_dummy_item) + if (item && one_selected && !is_dummy_item) { if (item->isWearableType()) { @@ -914,6 +938,9 @@ void LLPanelOutfitEdit::showFilteredWearablesListView(LLWearableType::EType type showAddWearablesPanel(true); showWearablesListView(); + // Reset mWearableItemsList position to top. See EXT-8180. + mWearableItemsList->goToTop(); + //e_list_view_item_type implicitly contains LLWearableType::EType starting from LVIT_SHAPE applyListViewFilter((EListViewItemType) (LVIT_SHAPE + type)); } diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index de1bf87fb3..fb9a35411c 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -148,6 +148,8 @@ public: void onInventorySelectionChange(); void onPlusBtnClicked(void); + void onVisibilityChange(); + void applyFolderViewFilter(EFolderViewItemType type); void applyListViewFilter(EListViewItemType type); diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index c5d259e517..ca5679d5b0 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -282,10 +282,17 @@ void LLPanelOutfitsInventory::showGearMenu() void LLPanelOutfitsInventory::onTrashButtonClick() { - mMyOutfitsPanel->removeSelected(); + LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(&LLPanelOutfitsInventory::onOutfitsRemovalConfirmation, this, _1, _2)); +} - updateListCommands(); - updateVerbs(); +void LLPanelOutfitsInventory::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return; // canceled + + mMyOutfitsPanel->removeSelected(); + updateListCommands(); + updateVerbs(); } bool LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata) diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index a50e047140..5c397e9c29 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -94,6 +94,7 @@ protected: void onWearButtonClick(); void showGearMenu(); void onTrashButtonClick(); + void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response); bool isActionEnabled(const LLSD& userdata); void setWearablesLoading(bool val); void onWearablesLoaded(); diff --git a/indra/newview/llpanelvoiceeffect.cpp b/indra/newview/llpanelvoiceeffect.cpp index fd470798ee..68fa9d1e5e 100644 --- a/indra/newview/llpanelvoiceeffect.cpp +++ b/indra/newview/llpanelvoiceeffect.cpp @@ -129,6 +129,8 @@ void LLPanelVoiceEffect::update(bool list_updated) if (mVoiceEffectCombo) { LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); + llassert(effect_interface); + if (!effect_interface) return; if (list_updated) { // Add the default "No Voice Morph" entry. diff --git a/indra/newview/llsidepanelinventory.h b/indra/newview/llsidepanelinventory.h index 951fdd630c..f2f2509f9a 100644 --- a/indra/newview/llsidepanelinventory.h +++ b/indra/newview/llsidepanelinventory.h @@ -58,6 +58,9 @@ public: void showTaskInfoPanel(); void showInventoryPanel(); + // checks can share selected item(s) + bool canShare(); + protected: // Tracks highlighted (selected) item in inventory panel. LLInventoryItem *getSelectedItem(); @@ -65,8 +68,6 @@ protected: void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action); // "wear", "teleport", etc. void performActionOnSelection(const std::string &action); - bool canShare(); - void updateVerbs(); // diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index cb65756764..e6b4aeb6c2 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -582,8 +582,6 @@ LLIMWellWindow::LLIMWellWindow(const LLSD& key) : LLSysWellWindow(key) { LLIMMgr::getInstance()->addSessionObserver(this); - LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLIMWellWindow::findIMChiclet, this, _1)); - LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLIMWellWindow::findObjectChiclet, this, _1)); } LLIMWellWindow::~LLIMWellWindow() @@ -601,6 +599,10 @@ BOOL LLIMWellWindow::postBuild() { BOOL rv = LLSysWellWindow::postBuild(); setTitle(getString("title_im_well_window")); + + LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLIMWellWindow::findIMChiclet, this, _1)); + LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLIMWellWindow::findObjectChiclet, this, _1)); + return rv; } @@ -641,6 +643,8 @@ void LLIMWellWindow::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID LLChiclet* LLIMWellWindow::findObjectChiclet(const LLUUID& notification_id) { + if (!mMessageList) return NULL; + LLChiclet* res = NULL; ObjectRowPanel* panel = mMessageList->getTypedItemByValue<ObjectRowPanel>(notification_id); if (panel != NULL) @@ -655,6 +659,8 @@ LLChiclet* LLIMWellWindow::findObjectChiclet(const LLUUID& notification_id) // PRIVATE METHODS LLChiclet* LLIMWellWindow::findIMChiclet(const LLUUID& sessionId) { + if (!mMessageList) return NULL; + LLChiclet* res = NULL; RowPanel* panel = mMessageList->getTypedItemByValue<RowPanel>(sessionId); if (panel != NULL) diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index c862c02b82..3f34fc174c 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1871,13 +1871,8 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( if (drop) { - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); - return ACCEPT_NO; - } + // TODO: investigate wearables may not be loaded at this point EXT-8231 + LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(),true, !(mask & MASK_CONTROL)); } return ACCEPT_YES_MULTI; @@ -1949,13 +1944,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( if (drop) { - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); - return ACCEPT_NO; - } + // TODO: investigate wearables may not be loaded at this point EXT-8231 } if (mSource == SOURCE_AGENT) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 9027caa4ce..9a2866832a 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -762,7 +762,17 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Coordinates of objects on simulators are region-local. U64 region_handle; mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); - mRegionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); + + { + LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); + if(regionp != mRegionp && regionp && mRegionp) + { + LLVector3 delta_pos = mRegionp->getOriginAgent() - regionp->getOriginAgent(); + setPosition(getPosition() + delta_pos) ; //update the region position immediately. + } + mRegionp = regionp ; + } + if (!mRegionp) { U32 x, y; diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 868322699e..9f9a9bef35 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -269,13 +269,13 @@ LLPanelAttachmentListItem* LLPanelAttachmentListItem::create(LLViewerInventoryIt void LLPanelAttachmentListItem::updateItem(const std::string& name, EItemState item_state) { - std::string title_joint; + std::string title_joint = name; LLViewerInventoryItem* inv_item = getItem(); if (inv_item && isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(inv_item->getLinkedUUID())) { std::string joint = LLTrans::getString(gAgentAvatarp->getAttachedPointName(inv_item->getLinkedUUID())); - title_joint = name + " (" + joint + ")"; + title_joint = title_joint + " (" + joint + ")"; } LLPanelInventoryListItemBase::updateItem(title_joint, item_state); @@ -783,10 +783,7 @@ void LLWearableItemsList::ContextMenu::createNewWearable(const LLUUID& item_id) // static bool LLWearableItemsList::ContextMenu::canAddWearable(const LLUUID& item_id) { - if (!gAgentWearables.areWearablesLoaded()) - { - return false; - } + // TODO: investigate wearables may not be loaded at this point EXT-8231 LLViewerInventoryItem* item = gInventory.getItem(item_id); if (!item || item->getType() != LLAssetType::AT_CLOTHING) diff --git a/indra/newview/skins/default/textures/navbar/NavBar_BG_NoFav_Bevel.png b/indra/newview/skins/default/textures/navbar/NavBar_BG_NoFav_Bevel.png Binary files differnew file mode 100644 index 0000000000..a79d999932 --- /dev/null +++ b/indra/newview/skins/default/textures/navbar/NavBar_BG_NoFav_Bevel.png diff --git a/indra/newview/skins/default/textures/navbar/NavBar_BG_NoNav_Bevel.png b/indra/newview/skins/default/textures/navbar/NavBar_BG_NoNav_Bevel.png Binary files differnew file mode 100644 index 0000000000..b692ed92da --- /dev/null +++ b/indra/newview/skins/default/textures/navbar/NavBar_BG_NoNav_Bevel.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 40e882757f..082b37d80b 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -276,9 +276,9 @@ with the same filename but different name <texture name="Movement_Up_Off" file_name="bottomtray/Movement_Up_Off.png" preload="false" /> <texture name="Movement_Up_On" file_name="bottomtray/Movement_Up_On.png" preload="false" /> - <texture name="NavBar_BG_NoFav" file_name="navbar/NavBar_BG_NoFav.png" preload="true" scale.left="1" scale.top="1" scale.right="0" scale.bottom="0" /> <texture name="NavBar_BG" file_name="navbar/NavBar_BG.png" preload="true" scale.left="1" scale.top="1" scale.right="0" scale.bottom="0" /> - + <texture name="NavBar_BG_NoFav_Bevel" file_name="navbar/NavBar_BG_NoFav_Bevel.png" preload="true" scale.left="1" scale.top="1" scale.right="0" scale.bottom="0" /> + <texture name="NavBar_BG_NoNav_Bevel" file_name="navbar/NavBar_BG_NoNav_Bevel.png" preload="true" scale.left="1" scale.top="1" scale.right="0" scale.bottom="0" /> <texture name="Notices_Unread" file_name="bottomtray/Notices_Unread.png" preload="true" /> diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 34c1b25f8c..194a93977f 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -823,7 +823,7 @@ height="10" left="10" name="Name:" - top="0" + top="5" width="90"> Name: </text> diff --git a/indra/newview/skins/default/xui/en/main_view.xml b/indra/newview/skins/default/xui/en/main_view.xml index 72ab6195bc..a1ca910cbb 100644 --- a/indra/newview/skins/default/xui/en/main_view.xml +++ b/indra/newview/skins/default/xui/en/main_view.xml @@ -199,7 +199,15 @@ mouse_opaque="false" name="popup_holder" class="popup_holder" - width="1024"/> + width="1024"> + <icon follows="right|bottom" + image_name="Resize_Corner" + right="-1" + name="resize_corner" + width="11" + bottom="-1" + height="11" /> + </panel> <menu_holder top="0" follows="all" height="768" diff --git a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml index 62365f7cc2..c394700081 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml @@ -81,6 +81,17 @@ function="Inventory.GearDefault.Enable" parameter="save_texture" /> </menu_item_call> + <menu_item_call + label="Share" + layout="topleft" + name="Share" + visible="true"> + <on_click + function="Inventory.Share" /> + <on_enable + function="Inventory.GearDefault.Enable" + parameter="share" /> + </menu_item_call> <menu_item_call label="Find Original" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 290c8c55a9..04a8a02ecd 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -817,6 +817,17 @@ Delete pick <nolink>[PICK]</nolink>? <notification icon="alertmodal.tga" + name="DeleteOutfits" + type="alertmodal"> + Delete the selected outfit/s? + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="PromptGoToEventsPage" type="alertmodal"> Go to the [SECOND_LIFE] events web page? diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml index 4eff5bc48a..4b622691b3 100644 --- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml +++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml @@ -503,5 +503,17 @@ image_pressed_selected "Lit" + "Selected" - there are new messages and the Well </button> </chiclet_notification> </layout_panel> + <icon + auto_resize="false" + color="0 0 0 0" + follows="left|right" + height="10" + image_name="spacer24.tga" + layout="topleft" + left="0" + min_width="4" + name="DUMMY2" + top="0" + width="8" /> </layout_stack> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml index d5943ea156..f438e3d42d 100644 --- a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml +++ b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml @@ -22,40 +22,40 @@ width="311"> <accordion_tab layout="topleft" - name="tab_attachments" - title="Attachments"> + name="tab_clothing" + title="Clothing"> <flat_list_view allow_select="true" follows="all" height="10" item_pad="3" + keep_selection_visible_on_reshape="true" layout="topleft" left="0" - keep_selection_visible_on_reshape="true" multi_select="true" - name="list_attachments" + name="list_clothing" top="0" - width="311"> - <flat_list_view.no_items_text - value="No attachments worn" /> - </flat_list_view> + width="311" /> </accordion_tab> <accordion_tab layout="topleft" - name="tab_clothing" - title="Clothing"> + name="tab_attachments" + title="Attachments"> <flat_list_view allow_select="true" follows="all" height="10" item_pad="3" - keep_selection_visible_on_reshape="true" layout="topleft" left="0" + keep_selection_visible_on_reshape="true" multi_select="true" - name="list_clothing" + name="list_attachments" top="0" - width="311" /> + width="311"> + <flat_list_view.no_items_text + value="No attachments worn" /> + </flat_list_view> </accordion_tab> <accordion_tab layout="topleft" diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml index 00b1fdd843..2c9d7e4b6a 100644 --- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml @@ -22,14 +22,25 @@ width="600"/> <icon follows="all" - image_name="NavBar_BG_NoFav" + image_name="NavBar_BG_NoFav_Bevel" mouse_opaque="false" - name="bg_icon_no_fav" + name="bg_icon_no_fav_bevel" scale_image="true" visible="false" left="0" top="0" - height="50" + height="60" + width="600"/> + <icon + follows="all" + image_name="NavBar_BG_NoNav_Bevel" + mouse_opaque="false" + name="bg_icon_no_nav_bevel" + scale_image="true" + visible="false" + left="0" + top="0" + height="60" width="600"/> <panel background_visible="false" diff --git a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml index 0fc945126b..adc38b966c 100644 --- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml +++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml @@ -290,7 +290,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap <layout_panel - background_visible="true" + background_visible="false" bg_alpha_color="DkGray2" auto_resize="true" default_tab_group="3" @@ -317,7 +317,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap background_visible="false" border="false" follows="left|top|right|bottom" - height="449" + height="418" layout="topleft" left="0" mouse_opaque="false" @@ -332,7 +332,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap layout="topleft" follows="left|top|right|bottom" border="false" - height="449" + height="418" left="0" mouse_opaque="false" width="310" @@ -346,10 +346,19 @@ It is calculated as border_size + 2*UIResizeBarOverlap follows="all" multi_select="true" width="313" - height="449" + height="418" left="0" top="0"/> </panel> + <button + follows="bottom|left" + height="22" + left="2" + label="Wear Item" + layout="topleft" + name="plus_btn" + top_pad="5" + width="130" /> </layout_panel> </layout_stack> @@ -451,19 +460,6 @@ It is calculated as border_size + 2*UIResizeBarOverlap name="list_view_btn" top="1" width="31" /> - <button - follows="bottom|left" - height="25" - image_hover_unselected="Toolbar_Middle_Over" - image_overlay="AddItem_Off" - image_selected="Toolbar_Middle_Selected" - image_unselected="Toolbar_Middle_Off" - label="" - layout="topleft" - left_pad="1" - name="plus_btn" - top="1" - width="31" /> <icon follows="bottom|left|right" height="25" @@ -471,7 +467,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap layout="topleft" left_pad="1" name="dummy_right_icon" - width="154" > + width="186" > </icon> <button follows="bottom|right" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index f7611b6833..1e8d0d2fe5 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2159,6 +2159,7 @@ Clears (deletes) the media and all params from the given face. <string name="ATTACH_HUD_BOTTOM_LEFT">HUD Bottom Left</string> <string name="ATTACH_HUD_BOTTOM">HUD Bottom</string> <string name="ATTACH_HUD_BOTTOM_RIGHT">HUD Bottom Right</string> + <string name="Bad attachment point">Invalid Attachment Point</string> <!-- script editor --> <string name="CursorPos">Line [LINE], Column [COLUMN]</string> |