diff options
-rw-r--r-- | indra/llui/llaccordionctrl.cpp | 24 | ||||
-rw-r--r-- | indra/llui/llaccordionctrl.h | 1 | ||||
-rw-r--r-- | indra/llui/llaccordionctrltab.cpp | 29 | ||||
-rw-r--r-- | indra/llui/llaccordionctrltab.h | 7 | ||||
-rw-r--r-- | indra/newview/llinventoryitemslist.h | 3 | ||||
-rw-r--r-- | indra/newview/lloutfitslist.cpp | 78 | ||||
-rw-r--r-- | indra/newview/lloutfitslist.h | 7 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/outfit_accordion_tab.xml | 2 |
8 files changed, 134 insertions, 17 deletions
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index 5d1d57cbb2..8e0245c451 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -65,6 +65,7 @@ LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params) , mFitParent(params.fit_parent) , mAutoScrolling( false ) , mAutoScrollRate( 0.f ) + , mSelectedTab( NULL ) { mSingleExpansion = params.single_expansion; if(mFitParent && !mSingleExpansion) @@ -76,6 +77,7 @@ LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params) LLAccordionCtrl::LLAccordionCtrl() : LLPanel() , mAutoScrolling( false ) , mAutoScrollRate( 0.f ) + , mSelectedTab( NULL ) { mSingleExpansion = false; mFitParent = false; @@ -689,6 +691,28 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info) } return 0; } + else if(str_action == "select_current") + { + for(size_t i=0;i<mAccordionTabs.size();++i) + { + // Set selection to the currently focused tab. + if(mAccordionTabs[i]->hasFocus()) + { + if (mAccordionTabs[i] != mSelectedTab) + { + if (mSelectedTab) + { + mSelectedTab->setSelected(false); + } + mSelectedTab = mAccordionTabs[i]; + mSelectedTab->setSelected(true); + } + + return 1; + } + } + return 0; + } } else if (info.has("scrollToShowRect")) { diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index ab7d6548ca..a029201c90 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -130,6 +130,7 @@ private: bool mFitParent; bool mAutoScrolling; F32 mAutoScrollRate; + LLAccordionCtrlTab* mSelectedTab; }; diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index b09c108ec3..83e67980a3 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -76,6 +76,8 @@ public: std::string getTitle(); void setTitle(const std::string& title, const std::string& hl); + void setSelected(bool is_selected) { mIsSelected = is_selected; } + virtual void onMouseEnter(S32 x, S32 y, MASK mask); virtual void onMouseLeave(S32 x, S32 y, MASK mask); virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); @@ -103,6 +105,7 @@ private: LLUIColor mHeaderBGColor; bool mNeedsHighlight; + bool mIsSelected; LLFrameTimer mAutoOpenTimer; }; @@ -115,7 +118,8 @@ LLAccordionCtrlTab::LLAccordionCtrlTabHeader::LLAccordionCtrlTabHeader( const LLAccordionCtrlTabHeader::Params& p) : LLUICtrl(p) , mHeaderBGColor(p.header_bg_color()) -,mNeedsHighlight(false), +, mNeedsHighlight(false) +, mIsSelected(false), mImageCollapsed(p.header_collapse_img), mImageCollapsedPressed(p.header_collapse_img_pressed), mImageExpanded(p.header_expand_img), @@ -187,7 +191,7 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw() // Only show green "focus" background image if the accordion is open, // because the user's mental model of focus is that it goes away after // the accordion is closed. - if (getParent()->hasFocus() + if (getParent()->hasFocus() || mIsSelected /*&& !(collapsible && !expanded)*/ // WHY?? ) { @@ -301,6 +305,7 @@ LLAccordionCtrlTab::Params::Params() ,header_image_focused("header_image_focused") ,header_text_color("header_text_color") ,fit_panel("fit_panel",true) + ,selection_enabled("selection_enabled", false) { mouse_opaque(false); } @@ -331,6 +336,11 @@ LLAccordionCtrlTab::LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&p) mHeader = LLUICtrlFactory::create<LLAccordionCtrlTabHeader>(headerParams); addChild(mHeader, 1); + if (p.selection_enabled) + { + LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLAccordionCtrlTab::selectOnFocusReceived, this)); + } + reshape(100, 200,FALSE); } @@ -498,6 +508,15 @@ boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus return boost::signals2::connection(); } +void LLAccordionCtrlTab::setSelected(bool is_selected) +{ + LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME); + if (header) + { + header->setSelected(is_selected); + } +} + LLView* LLAccordionCtrlTab::findContainerView() { for(child_list_const_iter_t it = getChildList()->begin(); @@ -513,6 +532,11 @@ LLView* LLAccordionCtrlTab::findContainerView() return NULL; } +void LLAccordionCtrlTab::selectOnFocusReceived() +{ + if (getParent()) // A parent may not be set if tabs are added dynamically. + getParent()->notifyParent(LLSD().with("action", "select_current")); +} S32 LLAccordionCtrlTab::getHeaderHeight() { @@ -713,6 +737,7 @@ void LLAccordionCtrlTab::showAndFocusHeader() { LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME); header->setFocus(true); + header->setSelected(true); LLRect screen_rc; LLRect selected_rc = header->getRect(); diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index f5b7fd0af6..83a9024a74 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -88,6 +88,8 @@ public: Optional<bool> fit_panel; + Optional<bool> selection_enabled; + Optional<S32> padding_left; Optional<S32> padding_right; Optional<S32> padding_top; @@ -121,6 +123,8 @@ public: boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb); boost::signals2::connection setFocusLostCallback(const focus_signal_t::slot_type& cb); + void setSelected(bool is_selected); + bool getCollapsible() {return mCollapsible;}; void setCollapsible(bool collapsible) {mCollapsible = collapsible;}; @@ -199,6 +203,9 @@ protected: void drawChild(const LLRect& root_rect,LLView* child); LLView* findContainerView (); + + void selectOnFocusReceived(); + private: class LLAccordionCtrlTabHeader; diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h index 807952948b..03ad7c2184 100644 --- a/indra/newview/llinventoryitemslist.h +++ b/indra/newview/llinventoryitemslist.h @@ -133,6 +133,9 @@ public: /** Get the description of a corresponding inventory item */ const std::string& getDescription() const { return mItem->getDescription(); } + /** Get the associated inventory item */ + LLViewerInventoryItem* getItem() const { return mItem; } + virtual ~LLPanelInventoryListItemBase(){} protected: diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 17a2db7a43..8f189a1e9f 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -82,7 +82,6 @@ LLOutfitsList::LLOutfitsList() : LLPanel() , mAccordion(NULL) , mListCommands(NULL) - , mSelectedList(NULL) { mCategoriesObserver = new LLInventoryCategoriesObserver(); gInventory.addObserver(mCategoriesObserver); @@ -208,6 +207,8 @@ void LLOutfitsList::refreshList(const LLUUID& category_id) // Setting list refresh callback to apply filter on list change. list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1)); + list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3)); + // Fetch the new outfit contents. cat->fetch(); @@ -237,23 +238,27 @@ void LLOutfitsList::refreshList(const LLUUID& category_id) outfits_map_t::iterator outfits_iter = mOutfitsMap.find((*iter)); if (outfits_iter != mOutfitsMap.end()) { - // An outfit is removed from the list. Do the following: - // 1. Remove outfit accordion tab from accordion. - mAccordion->removeCollapsibleCtrl(outfits_iter->second); - const LLUUID& outfit_id = outfits_iter->first; + LLAccordionCtrlTab* tab = outfits_iter->second; - // 2. Remove outfit category from observer to stop monitoring its changes. + // An outfit is removed from the list. Do the following: + // 1. Remove outfit category from observer to stop monitoring its changes. mCategoriesObserver->removeCategory(outfit_id); - // 3. Reset selection if selected outfit is being removed. - if (mSelectedOutfitUUID == outfit_id) + // 2. Remove selected lists map entry. + mSelectedListsMap.erase(outfit_id); + + // 3. Reset currently selected outfit id if it is being removed. + if (outfit_id == mSelectedOutfitUUID) { - changeOutfitSelection(NULL, LLUUID()); + mSelectedOutfitUUID = LLUUID(); } // 4. Remove category UUID to accordion tab mapping. mOutfitsMap.erase(outfits_iter); + + // 5. Remove outfit tab from accordion. + mAccordion->removeCollapsibleCtrl(tab); } } @@ -283,6 +288,8 @@ void LLOutfitsList::onSelectionChange(LLUICtrl* ctrl) void LLOutfitsList::performAction(std::string action) { + if (mSelectedOutfitUUID.isNull()) return; + LLViewerInventoryCategory* cat = gInventory.getCategory(mSelectedOutfitUUID); if (!cat) return; @@ -367,14 +374,28 @@ void LLOutfitsList::updateOutfitTab(const LLUUID& category_id) void LLOutfitsList::changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id) { - // Reset selection in previously selected tab - // if a new one is selected. - if (list && mSelectedList && mSelectedList != list) + MASK mask = gKeyboard->currentMask(TRUE); + + // Reset selection in all previously selected tabs except for the current + // if new selection is started. + if (list && !(mask & MASK_CONTROL)) { - mSelectedList->resetSelection(); + for (wearables_lists_map_t::iterator iter = mSelectedListsMap.begin(); + iter != mSelectedListsMap.end(); + ++iter) + { + LLWearableItemsList* selected_list = (*iter).second; + if (selected_list != list) + { + selected_list->resetSelection(); + } + } + + // Clear current selection. + mSelectedListsMap.clear(); } - mSelectedList = list; + mSelectedListsMap.insert(wearables_lists_map_value_t(category_id, list)); mSelectedOutfitUUID = category_id; } @@ -494,6 +515,13 @@ void LLOutfitsList::onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const S32 header_bottom = tab->getLocalRect().getHeight() - tab->getHeaderHeight(); if(y >= header_bottom) { + // Focus tab header to trigger tab selection change. + LLUICtrl* header = tab->findChild<LLUICtrl>("dd_header"); + if (header) + { + header->setFocus(TRUE); + } + uuid_vec_t selected_uuids; selected_uuids.push_back(cat_id); mOutfitMenu->show(ctrl, selected_uuids, x, y); @@ -501,4 +529,26 @@ void LLOutfitsList::onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const } } +void LLOutfitsList::onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y) +{ + LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(ctrl); + if (!list) return; + + uuid_vec_t selected_uuids; + + // Collect seleted items from all selected lists. + for (wearables_lists_map_t::iterator iter = mSelectedListsMap.begin(); + iter != mSelectedListsMap.end(); + ++iter) + { + uuid_vec_t uuids; + (*iter).second->getSelectedUUIDs(uuids); + + S32 prev_size = selected_uuids.size(); + selected_uuids.resize(prev_size + uuids.size()); + std::copy(uuids.begin(), uuids.end(), selected_uuids.begin() + prev_size); + } + + LLWearableItemsList::ContextMenu::instance().show(list, selected_uuids, x, y); +} // EOF diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index b6b3d6ae46..1da7360c2e 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -108,12 +108,17 @@ private: void onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id); + void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y); + LLInventoryCategoriesObserver* mCategoriesObserver; LLAccordionCtrl* mAccordion; LLPanel* mListCommands; - LLWearableItemsList* mSelectedList; + typedef std::map<LLUUID, LLWearableItemsList*> wearables_lists_map_t; + typedef wearables_lists_map_t::value_type wearables_lists_map_value_t; + wearables_lists_map_t mSelectedListsMap; + LLUUID mSelectedOutfitUUID; std::string mFilterSubString; 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 066992b25d..44437d01eb 100644 --- a/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml +++ b/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml @@ -8,6 +8,7 @@ height="45" layout="topleft" name="Mockup Tab" + selection_enabled="true" title="Mockup Tab" translate="false" width="0"> @@ -18,5 +19,6 @@ multi_select="true" name="wearable_items_list" translate="false" + use_internal_context_menu="false" /> </accordion_tab> |