From 55c887225f230822f5ffcd1b1a01a87d17653bd7 Mon Sep 17 00:00:00 2001 From: Andrew Dyukov Date: Mon, 9 Aug 2010 15:14:45 +0300 Subject: EXT-8010 ADDITIONAL FIX Fixed problems with avatar links underlining. There were two problems: 1. Underlining broke when avatar's first and second name were on different lines. 2. There was no underline on hover for avatar miniinspector links in plaintext IM. - First problem was caused by calling LLOnHoverChangeableTextSegment::draw() for the same segment twice- for first and second name that were on different lines, while handleHover() was called only once. So handleHover() was called -> text was underlined -> first part of segment was drawn underlined -> its draw set style back to normal -> second part of segment was drawn without underlining. Fixed this by setting style back to normal only when drawing the last part of the segment. - Second problem was caused by unusual way of appending link to text in chat history. Changed it so that LLTextBase::appendText() now receives link not inside style params, but directly. Also added "/inspect" ending to check in LLUrlEntryAgent::underlineOnHoverOnly(). Reviewed by Richard Nelson at https://codereview.productengine.com/secondlife/r/833/ --HG-- branch : product-engine --- indra/llui/lltextbase.cpp | 5 ++++- indra/llui/llurlentry.cpp | 2 +- indra/newview/llchathistory.cpp | 5 +++-- indra/newview/llstylemap.cpp | 12 ++---------- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index cde08c7b19..3792f18c97 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -2723,7 +2723,10 @@ LLOnHoverChangeableTextSegment::LLOnHoverChangeableTextSegment( LLStyleConstSP s F32 LLOnHoverChangeableTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) { F32 result = LLNormalTextSegment::draw(start, end, selection_start, selection_end, draw_rect); - mStyle = mNormalStyle; + if (end == mEnd - mStart) + { + mStyle = mNormalStyle; + } return result; } diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 17d211fb36..bf7b25910f 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -366,7 +366,7 @@ std::string LLUrlEntryAgent::getTooltip(const std::string &string) const bool LLUrlEntryAgent::underlineOnHoverOnly(const std::string &string) const { std::string url = getUrl(string); - return LLStringUtil::endsWith(url, "/about"); + return LLStringUtil::endsWith(url, "/about") || LLStringUtil::endsWith(url, "/inspect"); } std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCallback &cb) diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 7c33923f04..7204e6c39c 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -699,8 +699,9 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL { LLStyle::Params link_params(style_params); link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID)); - // Convert the name to a hotlink and add to message. - mEditor->appendText(chat.mFromName + delimiter, false, link_params); + // Add link to avatar's inspector and delimiter to message. + mEditor->appendText(link_params.link_href, false, style_params); + mEditor->appendText(delimiter, false, style_params); } else { diff --git a/indra/newview/llstylemap.cpp b/indra/newview/llstylemap.cpp index 8fab3bb361..b3d7dddde8 100644 --- a/indra/newview/llstylemap.cpp +++ b/indra/newview/llstylemap.cpp @@ -46,20 +46,12 @@ const LLStyle::Params &LLStyleMap::lookupAgent(const LLUUID &source) if (mMap.find(source) == mMap.end()) { LLStyle::Params style_params; - if (source != LLUUID::null && source != gAgent.getID() ) + if (source != LLUUID::null) { style_params.color.control = "HTMLLinkColor"; style_params.readonly_color.control = "HTMLLinkColor"; - style_params.link_href = - LLSLURL("agent", source, "inspect").getSLURLString(); + style_params.link_href = LLSLURL("agent", source, "inspect").getSLURLString(); } - else - { - // Make the resident's own name white and don't make the name clickable. - style_params.color = LLColor4::white; - style_params.readonly_color = LLColor4::white; - } - mMap[source] = style_params; } return mMap[source]; -- cgit v1.2.3 From 7bce6580dc2849b99ae6eedd5c373b653ab5186d Mon Sep 17 00:00:00 2001 From: Sergei Litovchuk Date: Mon, 9 Aug 2010 15:23:00 +0300 Subject: EXT-7593 FIXED Added passing focus to the selected outfit tab when My Outfits tab is open. - Removed "tab_stop" from outfit tabs to prevent passing focus to a tab chosen by default from LLUICtrl::focusFirstItem(). Besides the order of passing focus between outfit tabs by pressing "Tab" was undetermined. - Had to remove const from the return of LLAccordionCtrl::getSelectedTab() to use the returned pointer for setting focus. Reviewed by Neal Orman at https://codereview.productengine.com/secondlife/r/846/. --HG-- branch : product-engine --- indra/llui/llaccordionctrl.h | 2 +- indra/newview/lloutfitslist.cpp | 6 ++++++ indra/newview/skins/default/xui/en/outfit_accordion_tab.xml | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index f26a380e5f..6fc9ca86a3 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -139,7 +139,7 @@ public: */ const LLAccordionCtrlTab* getExpandedTab() const; - const LLAccordionCtrlTab* getSelectedTab() const { return mSelectedTab; } + LLAccordionCtrlTab* getSelectedTab() const { return mSelectedTab; } bool getFitParent() const {return mFitParent;} diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index f921bca623..8422b97b3a 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -403,6 +403,12 @@ void LLOutfitsList::onOpen(const LLSD& /*info*/) mIsInitialized = true; } + + LLAccordionCtrlTab* selected_tab = mAccordion->getSelectedTab(); + if (!selected_tab) return; + + // Pass focus to the selected outfit tab. + selected_tab->showAndFocusHeader(); } void LLOutfitsList::refreshList(const LLUUID& category_id) diff --git a/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml index 06bd1e9ff4..20ff492c0f 100644 --- a/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml +++ b/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml @@ -9,6 +9,7 @@ layout="topleft" name="Mockup Tab" selection_enabled="true" + tab_stop="false" title="Mockup Tab" translate="false" width="0"> -- cgit v1.2.3 From 554d543b020cfd8e99322c57806b19247bce2f8b Mon Sep 17 00:00:00 2001 From: Vadim Savchuk Date: Mon, 9 Aug 2010 18:10:36 +0300 Subject: EXT-8577 FIXED Context menu items for multi-attachments Changes: * Implemented bulk-add from My Appearance SP. * Made sure there's no memleak when you click Wear/Attach in the in-world object context menu and the callback isn't invoked (because e.g. avatar fails to get close enough to the object). I stated that in comments. Reviewed by Seraph at https://codereview.productengine.com/secondlife/r/844/ --HG-- branch : product-engine --- indra/newview/llviewermenu.cpp | 3 +- indra/newview/llvoavatar.cpp | 9 ++++++ indra/newview/llvoavatar.h | 1 + indra/newview/llwearableitemslist.cpp | 56 +++++++++++++++++++++++++++-------- indra/newview/llwearableitemslist.h | 2 +- 5 files changed, 56 insertions(+), 15 deletions(-) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 92195f0a4d..a289a0eb7a 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -5950,7 +5950,8 @@ void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointA delta = delta * 0.5f; walkToSpot -= delta; - CallbackData* user_data = new CallbackData(attachment_point, mReplace); // *TODO: leak if the callback isn't called? + // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak. + CallbackData* user_data = new CallbackData(attachment_point, mReplace); gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance); gAgentCamera.clearFocusObject(); } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 298ac28ca8..6392aad248 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -5641,6 +5641,15 @@ BOOL LLVOAvatar::canAttachMoreObjects() const return (getNumAttachments() < MAX_AGENT_ATTACHMENTS); } +//----------------------------------------------------------------------------- +// canAttachMoreObjects() +// Returns true if we can attach more objects. +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const +{ + return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS; +} + //----------------------------------------------------------------------------- // lazyAttach() //----------------------------------------------------------------------------- diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 5de08e8e27..3f603dda8b 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -687,6 +687,7 @@ public: void rebuildHUD(); void resetHUDAttachments(); BOOL canAttachMoreObjects() const; + BOOL canAttachMoreObjects(U32 n) const; protected: U32 getNumAttachments() const; // O(N), not O(1) diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 194213f880..e2a5489fcf 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -869,7 +869,7 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu setMenuItemVisible(menu, "wear_wear", n_already_worn == 0 && n_worn == 0 && can_be_worn); setMenuItemEnabled(menu, "wear_wear", n_already_worn == 0 && n_worn == 0); setMenuItemVisible(menu, "wear_add", wear_add_visible); - setMenuItemEnabled(menu, "wear_add", n_items == 1 && canAddWearable(ids.front())); + setMenuItemEnabled(menu, "wear_add", canAddWearables(ids)); setMenuItemVisible(menu, "wear_replace", n_worn == 0 && n_already_worn != 0 && can_be_worn); //visible only when one item selected and this item is worn setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART) && n_worn == n_items && n_worn == 1); @@ -978,31 +978,61 @@ void LLWearableItemsList::ContextMenu::createNewWearable(const LLUUID& item_id) LLAgentWearables::createWearable(item->getWearableType(), true); } -// Can we wear another wearable of the given item's wearable type? +// Returns true if all the given objects and clothes can be added. // static -bool LLWearableItemsList::ContextMenu::canAddWearable(const LLUUID& item_id) +bool LLWearableItemsList::ContextMenu::canAddWearables(const uuid_vec_t& item_ids) { // TODO: investigate wearables may not be loaded at this point EXT-8231 - LLViewerInventoryItem* item = gInventory.getItem(item_id); - if (!item) + U32 n_objects = 0; + boost::unordered_map clothes_by_type; + + // Count given clothes (by wearable type) and objects. + for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it) { - return false; + LLViewerInventoryItem* item = gInventory.getItem(*it); + if (!item) + { + return false; + } + + if (item->getType() == LLAssetType::AT_OBJECT) + { + ++n_objects; + } + else if (item->getType() == LLAssetType::AT_CLOTHING) + { + ++clothes_by_type[item->getWearableType()]; + } + else + { + llwarns << "Unexpected wearable type" << llendl; + return false; + } } - if (item->getType() == LLAssetType::AT_OBJECT) + // Check whether we can add all the objects. + if (!isAgentAvatarValid() || !gAgentAvatarp->canAttachMoreObjects(n_objects)) { - // *TODO: is this the right check? - return isAgentAvatarValid() && gAgentAvatarp->canAttachMoreObjects(); + return false; } - if (item->getType() != LLAssetType::AT_CLOTHING) + // Check whether we can add all the clothes. + boost::unordered_map::const_iterator m_it; + for (m_it = clothes_by_type.begin(); m_it != clothes_by_type.end(); ++m_it) { - return false; + LLWearableType::EType w_type = m_it->first; + U32 n_clothes = m_it->second; + + U32 wearable_count = gAgentWearables.getWearableCount(w_type); + if ((wearable_count + n_clothes) > LLAgentWearables::MAX_CLOTHING_PER_TYPE) + { + return false; + } + } - U32 wearable_count = gAgentWearables.getWearableCount(item->getWearableType()); - return wearable_count < LLAgentWearables::MAX_CLOTHING_PER_TYPE; + return true; } // EOF diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index 81f1cd1b40..d7970e0838 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -431,7 +431,7 @@ public: static void setMenuItemEnabled(LLContextMenu* menu, const std::string& name, bool val); static void updateMask(U32& mask, LLAssetType::EType at); static void createNewWearable(const LLUUID& item_id); - static bool canAddWearable(const LLUUID& item_id); + static bool canAddWearables(const uuid_vec_t& item_ids); LLWearableItemsList* mParent; }; -- cgit v1.2.3 From 2f2a0ad38aecc1e9118cb51b86de578d56853311 Mon Sep 17 00:00:00 2001 From: Vadim Savchuk Date: Mon, 9 Aug 2010 21:14:07 +0300 Subject: EXT-8628 FIXED Crash in LLVOAvatarSelf::getAttachedPointName(). The crash was reproducible only on startup. Apparently, gAgentAvatarp was not valid at that point. Worked around by checking gAgentAvatarp for being valid. I didn't investigate what the root cause of the problem was (probably the new multi-attachments implementation), I just needed my viewer to work. Reviewed by Seraph at https://codereview.productengine.com/secondlife/r/847/ --HG-- branch : product-engine --- indra/newview/llinventorybridge.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 7e710ce8e1..53622f7188 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -3989,6 +3989,11 @@ std::string LLObjectBridge::getLabelSuffix() const { if (get_is_item_worn(mUUID)) { + if (!isAgentAvatarValid()) + { + return LLItemBridge::getLabelSuffix() + LLTrans::getString("worn"); + } + std::string attachment_point_name = gAgentAvatarp->getAttachedPointName(mUUID); // e.g. "(worn on ...)" / "(attached to ...)" -- cgit v1.2.3