diff options
Diffstat (limited to 'indra/newview/llsidetray.cpp')
-rw-r--r-- | indra/newview/llsidetray.cpp | 1313 |
1 files changed, 916 insertions, 397 deletions
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index e7008abe60..81b2fc0ae0 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -2,31 +2,25 @@ * @file llsidetray.cpp * @brief SideBar implementation * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * 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 + * Copyright (C) 2010, Linden Research, Inc. * - * 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 + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,25 +28,40 @@ #include "lltextbox.h" +#include "llagentcamera.h" +#include "llappviewer.h" +#include "llbottomtray.h" +#include "llfloaterreg.h" +#include "llfirstuse.h" +#include "llhints.h" #include "llsidetray.h" #include "llviewerwindow.h" -#include "llaccordionpanel.h" +#include "llaccordionctrl.h" #include "llfocusmgr.h" #include "llrootview.h" +#include "llnavigationbar.h" -#include "llcollapsiblectrl.h" +#include "llaccordionctrltab.h" #include "llfloater.h" //for gFloaterView -#include "lliconctrl.h"//for Home tab icon +#include "lliconctrl.h"//for OpenClose tab icon +#include "llsidetraypanelcontainer.h" +#include "llscreenchannel.h" +#include "llchannelmanager.h" #include "llwindow.h"//for SetCursor -#include "llbottomtray.h"//for reshape +#include "lltransientfloatermgr.h" + +#include "llsidepanelappearance.h" //#include "llscrollcontainer.h" using namespace std; +using namespace LLNotificationsUI; static LLRootViewRegistry::Register<LLSideTray> t1("side_tray"); -static LLDefaultWidgetRegistry::Register<LLSideTrayTab> t2("sidetray_tab"); +static LLDefaultChildRegistry::Register<LLSideTrayTab> t2("sidetray_tab"); + +static const S32 BOTTOM_BAR_PAD = 5; static const std::string COLLAPSED_NAME = "<<"; static const std::string EXPANDED_NAME = ">>"; @@ -62,93 +71,108 @@ static const std::string TAB_PANEL_CAPTION_TITLE_BOX = "sidetray_tab_title"; LLSideTray* LLSideTray::sInstance = 0; -class LLSideTrayInfoPanel: public LLPanel -{ -protected: - LLSideTrayInfoPanel(){} -public: - static LLSideTrayInfoPanel* createInstance(const string& image, const string& name,const string& description) - { - LLSideTrayInfoPanel* panel = new LLSideTrayInfoPanel(); - LLUICtrlFactory::getInstance()->buildPanel(panel,"panel_sidetray_tab_info.xml"); - if(panel) - panel->setData(image, name,description); - panel->setBorderVisible(true); - return panel; - - } - void setData(const string& image, const string& name,const string& description) - { - getChild<LLTextBox>("tab_name",false,false)->setValue(name); - getChild<LLTextBox>("tab_description",false,false)->setValue(description); - getChild<LLIconCtrl>("tab_icon",false,false)->setValue(image); - } - - BOOL handleHover(S32 x, S32 y, MASK mask) - { - getWindow()->setCursor(UI_CURSOR_HAND); - return TRUE; - } - - BOOL handleMouseUp(S32 x, S32 y, MASK mask) - { - onCommit(); - return LLPanel::handleMouseUp(x,y,mask); - } - -}; - - +// static LLSideTray* LLSideTray::getInstance() { if (!sInstance) { - sInstance = LLUICtrlFactory::createFromFile<LLSideTray>("panel_side_tray.xml",gViewerWindow->getRootView()); + sInstance = LLUICtrlFactory::createFromFile<LLSideTray>("panel_side_tray.xml",NULL, LLRootView::child_registry_t::instance()); + sInstance->setXMLFilename("panel_side_tray.xml"); } return sInstance; } +// static bool LLSideTray::instanceCreated () { return sInstance!=0; } -LLSideTrayTab::LLSideTrayTab(const Params& params):mAccordionPanel(0) - +////////////////////////////////////////////////////////////////////////////// +// LLSideTrayTab +// Represents a single tab in the side tray, only used by LLSideTray +////////////////////////////////////////////////////////////////////////////// + +class LLSideTrayTab: public LLPanel { - mImagePath = params.image_path; - mTabTitle = params.tab_title; - mDescription = params.tab_description; -} -LLSideTrayTab::~LLSideTrayTab() + friend class LLUICtrlFactory; + friend class LLSideTray; +public: + + struct Params + : public LLInitParam::Block<Params, LLPanel::Params> + { + // image name + Optional<std::string> image; + Optional<std::string> image_selected; + Optional<std::string> tab_title; + Optional<std::string> description; + Params() + : image("image"), + image_selected("image_selected"), + tab_title("tab_title","no title"), + description("description","no description") + {}; + }; +protected: + LLSideTrayTab(const Params& params); + + void dock(); + void undock(LLFloater* floater_tab); + + LLSideTray* getSideTray(); + +public: + virtual ~LLSideTrayTab(); + + /*virtual*/ BOOL postBuild (); + /*virtual*/ bool addChild (LLView* view, S32 tab_group); + + + void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE); + + static LLSideTrayTab* createInstance (); + + const std::string& getDescription () const { return mDescription;} + const std::string& getTabTitle() const { return mTabTitle;} + + void onOpen (const LLSD& key); + + void toggleTabDocked(); + + LLPanel *getPanel(); +private: + std::string mTabTitle; + std::string mImage; + std::string mImageSelected; + std::string mDescription; + + LLView* mMainPanel; +}; + +LLSideTrayTab::LLSideTrayTab(const Params& p) +: LLPanel(), + mTabTitle(p.tab_title), + mImage(p.image), + mImageSelected(p.image_selected), + mDescription(p.description), + mMainPanel(NULL) { + // Necessary for focus movement among child controls + setFocusRoot(TRUE); } -void LLSideTrayTab::addPanel(LLPanel* panel) +LLSideTrayTab::~LLSideTrayTab() { - //addChild(panel,false); } bool LLSideTrayTab::addChild(LLView* view, S32 tab_group) { - if(mAccordionPanel == 0) - { - mAccordionPanel = new LLAccordionPanel(); - mAccordionPanel->setVisible(TRUE); - LLPanel::addChild(mAccordionPanel,tab_group); - } - - - bool res = true; - if(TAB_PANEL_CAPTION_NAME != view->getName())//skip our caption panel - { - mAccordionPanel->addCollapsibleCtrl(view); - } - else - res = LLPanel::addChild(view,tab_group); - - return res; + if(mMainPanel == 0 && TAB_PANEL_CAPTION_NAME != view->getName())//skip our caption panel + mMainPanel = view; + return LLPanel::addChild(view,tab_group); + //return res; } @@ -156,174 +180,478 @@ bool LLSideTrayTab::addChild(LLView* view, S32 tab_group) //virtual BOOL LLSideTrayTab::postBuild() { - LLPanel* title_panel = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>("panel_side_tray_tab_caption.xml",this); + LLPanel* title_panel = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>("panel_side_tray_tab_caption.xml",this, child_registry_t::instance()); string name = title_panel->getName(); LLPanel::addChild(title_panel); title_panel->getChild<LLTextBox>(TAB_PANEL_CAPTION_TITLE_BOX)->setValue(mTabTitle); - static LLUICachedControl<LLColor4> default_background_color ("FloaterDefaultBackgroundColor", *(new LLColor4)); - static LLUICachedControl<LLColor4> focus_background_color ("FloaterFocusBackgroundColor", *(new LLColor4)); - - setTransparentColor(default_background_color); - setBackgroundColor(focus_background_color); - + getChild<LLButton>("undock")->setCommitCallback(boost::bind(&LLSideTrayTab::toggleTabDocked, this)); + getChild<LLButton>("dock")->setCommitCallback(boost::bind(&LLSideTrayTab::toggleTabDocked, this)); + return true; } -S32 LLSideTrayTab::getMaxSideBarTabWidth() +static const S32 splitter_margin = 1; + +void LLSideTrayTab::reshape (S32 width, S32 height, BOOL called_from_parent ) { - return (mAccordionPanel)?mAccordionPanel->getMaxPanelWidth():0; + LLPanel::reshape(width, height, called_from_parent); + LLView* title_panel = findChildView(TAB_PANEL_CAPTION_NAME, true); + if (!title_panel) + { + // not fully constructed yet + return; + } + + S32 title_height = title_panel->getRect().getHeight(); + title_panel->setOrigin( 0, height - title_height ); + title_panel->reshape(width,title_height); + + LLRect sRect; + sRect.setLeftTopAndSize( splitter_margin, height - title_height - splitter_margin, + width - 2*splitter_margin, height - title_height - 2*splitter_margin); + mMainPanel->setShape(sRect); } -static const S32 splitter_margin = 1; +void LLSideTrayTab::onOpen (const LLSD& key) +{ + LLPanel *panel = getPanel(); + if(panel) + panel->onOpen(key); +} -//virtual -void LLSideTrayTab::arrange(S32 width, S32 height ) +// Attempts to get the existing side tray instance. +// Needed to avoid recursive calls of LLSideTray::getInstance(). +LLSideTray* LLSideTrayTab::getSideTray() +{ + // First, check if the side tray is our parent (i.e. we're attached). + LLSideTray* side_tray = dynamic_cast<LLSideTray*>(getParent()); + if (!side_tray) + { + // Detached? Ok, check if the instance exists at all/ + if (LLSideTray::instanceCreated()) + { + side_tray = LLSideTray::getInstance(); + } + else + { + llerrs << "No safe way to get the side tray instance" << llendl; + } + } + + return side_tray; +} + +void LLSideTrayTab::toggleTabDocked() { - S32 offset = 0; + std::string tab_name = getName(); + + LLFloater* floater_tab = LLFloaterReg::getInstance("side_bar_tab", tab_name); + if (!floater_tab) return; + + bool docking = LLFloater::isShown(floater_tab); - LLView* title_panel = getChildView(TAB_PANEL_CAPTION_NAME, true, false); + // Hide the "Tear Off" button when a tab gets undocked + // and show "Dock" button instead. + getChild<LLButton>("undock")->setVisible(docking); + getChild<LLButton>("dock")->setVisible(!docking); - if(title_panel) + if (docking) { - title_panel->setOrigin( 0, height - title_panel->getRect().getHeight() ); - offset = title_panel->getRect().getHeight(); + dock(); + } + else + { + undock(floater_tab); } - LLRect sRect = mAccordionPanel->getRect(); - sRect.setLeftTopAndSize( splitter_margin, height - offset - splitter_margin, width - 2*splitter_margin, height - offset - 2*splitter_margin); - mAccordionPanel->setRect(sRect); - - mAccordionPanel->setMaxWidth(sRect.getWidth()); - mAccordionPanel->arrange(); + // Open/close the floater *after* we reparent the tab panel, + // so that it doesn't receive redundant visibility change notifications. + LLFloaterReg::toggleInstance("side_bar_tab", tab_name); } -void LLSideTrayTab::reshape (S32 width, S32 height, BOOL called_from_parent ) +void LLSideTrayTab::dock() { - if(!mAccordionPanel) - return; - S32 offset = 0; - - LLView* title_panel = getChildView(TAB_PANEL_CAPTION_NAME, true, false); + LLSideTray* side_tray = getSideTray(); + if (!side_tray) return; - if(title_panel) + if (!side_tray->addTab(this)) { - title_panel->setOrigin( 0, height - title_panel->getRect().getHeight() ); - title_panel->reshape(width,title_panel->getRect().getHeight()); - offset = title_panel->getRect().getHeight(); + llwarns << "Failed to add tab " << getName() << " to side tray" << llendl; + return; } - + setRect(side_tray->getLocalRect()); + reshape(getRect().getWidth(), getRect().getHeight()); - LLRect sRect = mAccordionPanel->getRect(); - sRect.setLeftTopAndSize( splitter_margin, height - offset - splitter_margin, width - 2*splitter_margin, height - offset - 2*splitter_margin); - mAccordionPanel->setMaxWidth(sRect.getWidth()); - mAccordionPanel->reshape(sRect.getWidth(), sRect.getHeight()); - - mAccordionPanel->setRect(sRect); + // Select the re-docked tab. + side_tray->selectTabByName(getName()); + + if (side_tray->getCollapsed()) + { + side_tray->expandSideBar(false); + } +} +static void on_minimize(LLSidepanelAppearance* panel, LLSD minimized) +{ + if (!panel) return; + bool visible = !minimized.asBoolean(); + panel->updateToVisibility(LLSD(visible)); } -void LLSideTrayTab::draw() +void LLSideTrayTab::undock(LLFloater* floater_tab) { - LLPanel::draw(); + LLSideTray* side_tray = getSideTray(); + if (!side_tray) return; + + // Remember whether the tab have been active before detaching + // because removeTab() will change active tab. + bool was_active = side_tray->getActiveTab() == this; + + // Remove the tab from Side Tray's tabs list. + // We have to do it despite removing the tab from Side Tray's child view tree + // by addChild(). Otherwise the tab could be accessed by the pointer in LLSideTray::mTabs. + if (!side_tray->removeTab(this)) + { + llwarns << "Failed to remove tab " << getName() << " from side tray" << llendl; + return; + } + + // If we're undocking while side tray is collapsed we need to explicitly show the panel. + if (!getVisible()) + { + setVisible(true); + } - //border - gl_rect_2d(0,0,getRect().getWidth() - 1,getRect().getHeight() - 1,LLColor4::black,false); + floater_tab->addChild(this); + floater_tab->setTitle(mTabTitle); + floater_tab->setName(getName()); + // Resize handles get obscured by added panel so move them to front. + floater_tab->moveResizeHandlesToFront(); + + // Reshape the floater if needed. + LLRect floater_rect; + if (floater_tab->hasSavedRect()) + { + // We've got saved rect for the floater, hence no need to reshape it. + floater_rect = floater_tab->getLocalRect(); + } + else + { + // Detaching for the first time. Reshape the floater. + floater_rect = side_tray->getLocalRect(); + // Reduce detached floater height by small BOTTOM_BAR_PAD not to make it flush with the bottom bar. + floater_rect.mBottom += LLBottomTray::getInstance()->getRect().getHeight() + BOTTOM_BAR_PAD; + floater_rect.makeValid(); + floater_tab->reshape(floater_rect.getWidth(), floater_rect.getHeight()); + } + + // Reshape the panel. + { + LLRect panel_rect = floater_tab->getLocalRect(); + panel_rect.mTop -= floater_tab->getHeaderHeight(); + panel_rect.makeValid(); + setRect(panel_rect); + reshape(panel_rect.getWidth(), panel_rect.getHeight()); + } + + // Set FOLLOWS_ALL flag for the tab to follow floater dimensions upon resizing. + setFollowsAll(); + + // Camera view may need to be changed for appearance panel(STORM-301) on minimize of floater, + // so setting callback here. + if (getName() == "sidebar_appearance") + { + LLSidepanelAppearance* panel_appearance = dynamic_cast<LLSidepanelAppearance*>(getPanel()); + if(panel_appearance) + { + floater_tab->setMinimizeCallback(boost::bind(&on_minimize, panel_appearance, _2)); + } + } + + if (!side_tray->getCollapsed()) + { + side_tray->collapseSideBar(); + } + + if (!was_active) + { + // When a tab other then current active tab is detached from Side Tray + // onOpen() should be called as tab visibility is changed. + onOpen(LLSD()); + } } -void LLSideTrayTab::onOpen (const LLSD& key) +LLPanel* LLSideTrayTab::getPanel() { - mAccordionPanel->onOpen(key); + LLPanel* panel = dynamic_cast<LLPanel*>(mMainPanel); + return panel; } LLSideTrayTab* LLSideTrayTab::createInstance () { LLSideTrayTab::Params tab_params; - tab_params.tab_title("Home"); + tab_params.tab_title("openclose"); LLSideTrayTab* tab = LLUICtrlFactory::create<LLSideTrayTab>(tab_params); return tab; } +////////////////////////////////////////////////////////////////////////////// +// LLSideTrayButton +// Side Tray tab button with "tear off" handling. +////////////////////////////////////////////////////////////////////////////// + +class LLSideTrayButton : public LLButton +{ +public: + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) + { + // Route future Mouse messages here preemptively. (Release on mouse up.) + // No handler needed for focus lost since this class has no state that depends on it. + gFocusMgr.setMouseCapture(this); + + localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY); + + // Note: don't pass on to children + return TRUE; + } + + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) + { + // We only handle the click if the click both started and ended within us + if( !hasMouseCapture() ) return FALSE; + + S32 screen_x; + S32 screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + + S32 delta_x = screen_x - mDragLastScreenX; + S32 delta_y = screen_y - mDragLastScreenY; + + LLSideTray* side_tray = LLSideTray::getInstance(); + + // Check if the tab we are dragging is docked. + if (!side_tray->isTabAttached(getName())) return FALSE; + + // Same value is hardcoded in LLDragHandle::handleHover(). + const S32 undock_threshold = 12; + + // Detach a tab if it has been pulled further than undock_threshold. + if (delta_x <= -undock_threshold || delta_x >= undock_threshold || + delta_y <= -undock_threshold || delta_y >= undock_threshold) + { + LLSideTrayTab* tab = side_tray->getTab(getName()); + if (!tab) return FALSE; + + tab->toggleTabDocked(); + + LLFloater* floater_tab = LLFloaterReg::getInstance("side_bar_tab", tab->getName()); + if (!floater_tab) return FALSE; + + LLRect original_rect = floater_tab->getRect(); + S32 header_snap_y = floater_tab->getHeaderHeight() / 2; + S32 snap_x = screen_x - original_rect.mLeft - original_rect.getWidth() / 2; + S32 snap_y = screen_y - original_rect.mTop + header_snap_y; + + // Move the floater to appear "under" the mouse pointer. + floater_tab->setRect(original_rect.translate(snap_x, snap_y)); + + // Snap the mouse pointer to the center of the floater header + // and call 'mouse down' event handler to begin dragging. + floater_tab->handleMouseDown(original_rect.getWidth() / 2, + original_rect.getHeight() - header_snap_y, + mask); + + return TRUE; + } + + return FALSE; + } + +protected: + LLSideTrayButton(const LLButton::Params& p) + : LLButton(p) + , mDragLastScreenX(0) + , mDragLastScreenY(0) + {} + + friend class LLUICtrlFactory; + +private: + S32 mDragLastScreenX; + S32 mDragLastScreenY; +}; + +////////////////////////////////////////////////////////////////////////////// +// LLSideTray +////////////////////////////////////////////////////////////////////////////// + +LLSideTray::Params::Params() +: collapsed("collapsed",false), + tab_btn_image_normal("tab_btn_image",LLUI::getUIImage("sidebar_tab_left.tga")), + tab_btn_image_selected("tab_btn_image_selected",LLUI::getUIImage("button_enabled_selected_32x128.tga")), + default_button_width("tab_btn_width",32), + default_button_height("tab_btn_height",32), + default_button_margin("tab_btn_margin",0) +{} //virtual -LLSideTray::LLSideTray(Params& params) - :mActiveTab(0) +LLSideTray::LLSideTray(const Params& params) + : LLPanel(params) + ,mActiveTab(0) ,mCollapsed(false) ,mCollapseButton(0) - ,mMaxBarWidth(0) - ,mHomeTab(0) { mCollapsed=params.collapsed; + + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + + // 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); + LLView* side_bar_tabs = gViewerWindow->getRootView()->getChildView("side_bar_tabs"); + if (side_bar_tabs != NULL) + { + LLTransientFloaterMgr::getInstance()->addControlView(side_bar_tabs); + } + + LLPanel::Params p; + p.name = "buttons_panel"; + p.mouse_opaque = false; + mButtonsPanel = LLUICtrlFactory::create<LLPanel>(p); } BOOL LLSideTray::postBuild() { - calcMaxSideBarWidth(); - createButtons(); - createHomeTab(); - arrange(); - selectTabByName("home_tab"); + selectTabByName("sidebar_home"); if(mCollapsed) collapseSideBar(); setMouseOpaque(false); + + LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSideTray::handleLoginComplete, this)); + + // Remember original tabs order, so that we can restore it if user detaches and then re-attaches a tab. + for (child_vector_const_iter_t it = mTabs.begin(); it != mTabs.end(); ++it) + { + std::string tab_name = (*it)->getName(); + mOriginalTabOrder.push_back(tab_name); + } + + //EXT-8045 + //connect all already created channels to reflect sidetray collapse/expand + std::vector<LLChannelManager::ChannelElem>& channels = LLChannelManager::getInstance()->getChannelList(); + for(std::vector<LLChannelManager::ChannelElem>::iterator it = channels.begin();it!=channels.end();++it) + { + if ((*it).channel) + { + getCollapseSignal().connect(boost::bind(&LLScreenChannelBase::resetPositionAndSize, (*it).channel, _2)); + } + } + return true; } - -/** - * add new panel to tab with tab_name name - * @param tab_name - name of sidebar tab to add new panel - * @param panel - pointer to panel - */ -bool LLSideTray::addPanel ( const std::string& tab_name - ,LLPanel* panel ) + +void LLSideTray::handleLoginComplete() { - return false; -} -/** - * Add new tab to side bar - * @param tab_name - name of the new tab - * @param image - image for new sidebar button - * @param title - title for new tab - */ -bool LLSideTray::addTab ( const std::string& tab_name - ,const std::string& image - ,const std::string& title) -{ - LLSideTrayTab::Params params; - params.image_path = image; - params.tab_title = title; - LLSideTrayTab* tab = LLUICtrlFactory::create<LLSideTrayTab> (params); - addChild(tab,1); - return true; -} + //reset tab to "home" tab if it was changesd during login process + selectTabByName("sidebar_home"); + detachTabs(); +} LLSideTrayTab* LLSideTray::getTab(const std::string& name) { - return getChild<LLSideTrayTab>(name,false,false); + return findChild<LLSideTrayTab>(name,false); } +bool LLSideTray::isTabAttached(const std::string& name) +{ + LLSideTrayTab* tab = getTab(name); + if (!tab) return false; + + return std::find(mTabs.begin(), mTabs.end(), tab) != mTabs.end(); +} +bool LLSideTray::hasTabs() +{ + // The open/close tab doesn't count. + return mTabs.size() > 1; +} -void LLSideTray::toggleTabButton (LLSideTrayTab* tab) +void LLSideTray::toggleTabButton(LLSideTrayTab* tab) { if(tab == NULL) return; - string name = tab->getName(); - std::map<std::string,LLButton*>::iterator tIt = mTabButtons.find(name); - if(tIt!=mTabButtons.end()) - tIt->second->setToggleState(!tIt->second->getToggleState()); + std::string name = tab->getName(); + std::map<std::string,LLButton*>::iterator it = mTabButtons.find(name); + if(it != mTabButtons.end()) + { + LLButton* btn = it->second; + bool new_state = !btn->getToggleState(); + btn->setToggleState(new_state); + // Only highlight the tab if side tray is expanded (STORM-157). + btn->setImageOverlay( new_state && !getCollapsed() ? tab->mImageSelected : tab->mImage ); + } +} + +LLPanel* LLSideTray::openChildPanel(LLSideTrayTab* tab, const std::string& panel_name, const LLSD& params) +{ + LLView* view = tab->findChildView(panel_name, true); + if (!view) return NULL; + + std::string tab_name = tab->getName(); + + // Select tab and expand Side Tray only when a tab is attached. + if (isTabAttached(tab_name)) + { + selectTabByName(tab_name); + if (mCollapsed) + expandSideBar(); + } + else + { + LLFloater* floater_tab = LLFloaterReg::getInstance("side_bar_tab", tab_name); + if (!floater_tab) return NULL; + + // Restore the floater if it was minimized. + if (floater_tab->isMinimized()) + { + floater_tab->setMinimized(FALSE); + } + + // Send the floater to the front. + floater_tab->setFrontmost(); + } + + LLSideTrayPanelContainer* container = dynamic_cast<LLSideTrayPanelContainer*>(view->getParent()); + if (container) + { + LLSD new_params = params; + new_params[LLSideTrayPanelContainer::PARAM_SUB_PANEL_NAME] = panel_name; + container->onOpen(new_params); + + return container->getCurrentPanel(); + } + + LLPanel* panel = dynamic_cast<LLPanel*>(view); + if (panel) + { + panel->onOpen(params); + } + + return panel; } bool LLSideTray::selectTabByIndex(size_t index) @@ -331,32 +659,37 @@ bool LLSideTray::selectTabByIndex(size_t index) if(index>=mTabs.size()) return false; - LLSideTrayTab* sidebar_tab = dynamic_cast<LLSideTrayTab*>(mTabs[index]); - if(sidebar_tab == NULL) - return false; + LLSideTrayTab* sidebar_tab = mTabs[index]; return selectTabByName(sidebar_tab->getName()); } -bool LLSideTray::selectTabByName (const std::string& name) +bool LLSideTray::selectTabByName(const std::string& name, bool keep_prev_visible) { - LLSideTrayTab* side_bar = getTab(name); - if(side_bar == 0 && name == "home_tab") - side_bar = mHomeTab; + LLSideTrayTab* tab_to_keep_visible = NULL; + LLSideTrayTab* new_tab = getTab(name); + if (!new_tab) return false; - if(side_bar == NULL || side_bar == mActiveTab) + // Bail out if already selected. + if (new_tab == mActiveTab) return false; + //deselect old tab + if (mActiveTab) + { + // Keep previously active tab visible if requested. + if (keep_prev_visible) tab_to_keep_visible = mActiveTab; toggleTabButton(mActiveTab); - if(mActiveTab) - mActiveTab->setVisible(false); + } //select new tab - mActiveTab = side_bar; + mActiveTab = new_tab; + + if (mActiveTab) + { toggleTabButton(mActiveTab); LLSD key;//empty mActiveTab->onOpen(key); - - mActiveTab->setVisible(true); + } //arrange(); @@ -364,17 +697,26 @@ bool LLSideTray::selectTabByName (const std::string& name) child_vector_const_iter_t child_it; for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) { - LLSideTrayTab* sidebar_tab = dynamic_cast<LLSideTrayTab*>(*child_it); - if(sidebar_tab == NULL) - continue; - sidebar_tab->setVisible(sidebar_tab == mActiveTab); + LLSideTrayTab* sidebar_tab = *child_it; + + bool vis = sidebar_tab == mActiveTab; + + // Force keeping the tab visible if requested. + vis |= sidebar_tab == tab_to_keep_visible; + + // When the last tab gets detached, for a short moment the "Toggle Sidebar" pseudo-tab + // is shown. So, to avoid the flicker we make sure it never gets visible. + vis &= (*child_it)->getName() != "sidebar_openclose"; + + sidebar_tab->setVisible(vis); } return true; } -LLButton* LLSideTray::createButton (const std::string& name,const std::string& image,LLUICtrl::commit_callback_t callback) +LLButton* LLSideTray::createButton (const std::string& name,const std::string& image,const std::string& tooltip, + LLUICtrl::commit_callback_t callback) { - static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams<LLSideTray::Params>()); + static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams<LLSideTray>()); LLButton::Params bparams; @@ -382,24 +724,36 @@ LLButton* LLSideTray::createButton (const std::string& name,const std::string& i rect.setOriginAndSize(0, 0, sidetray_params.default_button_width, sidetray_params.default_button_height); bparams.name(name); - bparams.follows.flags (FOLLOWS_LEFT | FOLLOWS_BOTTOM); + bparams.follows.flags (FOLLOWS_LEFT | FOLLOWS_TOP); bparams.rect (rect); bparams.tab_stop(false); - bparams.image_unselected.name(sidetray_params.tab_btn_image_normal); - bparams.image_selected.name(sidetray_params.tab_btn_image_selected); - bparams.image_disabled.name(sidetray_params.tab_btn_image_normal); - bparams.image_disabled_selected.name(sidetray_params.tab_btn_image_selected); + bparams.image_unselected(sidetray_params.tab_btn_image_normal); + bparams.image_selected(sidetray_params.tab_btn_image_selected); + bparams.image_disabled(sidetray_params.tab_btn_image_normal); + bparams.image_disabled_selected(sidetray_params.tab_btn_image_selected); + + LLButton* button; + if (name == "sidebar_openclose") + { + // "Open/Close" button shouldn't allow "tear off" + // hence it is created as LLButton instance. + button = LLUICtrlFactory::create<LLButton>(bparams); + } + else + { + button = LLUICtrlFactory::create<LLSideTrayButton>(bparams); + } - LLButton* button = LLUICtrlFactory::create<LLButton> (bparams); - button->setLabel(name); button->setClickedCallback(callback); + + button->setToolTip(tooltip); if(image.length()) { button->setImageOverlay(image); } - addChildInBack(button); + mButtonsPanel->addChildInBack(button); return button; } @@ -416,32 +770,178 @@ bool LLSideTray::addChild(LLView* view, S32 tab_group) return LLUICtrl::addChild(view, tab_group); } +bool LLSideTray::removeTab(LLSideTrayTab* tab) +{ + if (!tab) return false; + std::string tab_name = tab->getName(); -void LLSideTray::createButtons () + // Look up the tab in the list of known tabs. + child_vector_iter_t tab_it = std::find(mTabs.begin(), mTabs.end(), tab); + if (tab_it == mTabs.end()) + { + llwarns << "Cannot find tab named " << tab_name << llendl; + return false; + } + + // Find the button corresponding to the tab. + button_map_t::iterator btn_it = mTabButtons.find(tab_name); + if (btn_it == mTabButtons.end()) + { + llwarns << "Cannot find button for tab named " << tab_name << llendl; + return false; + } + LLButton* btn = btn_it->second; + + // Deselect the tab. + if (mActiveTab == tab) + { + // Select the next tab (or first one, if we're removing the last tab), + // skipping the fake open/close tab (STORM-155). + child_vector_iter_t next_tab_it = tab_it; + do + { + next_tab_it = (next_tab_it < (mTabs.end() - 1)) ? next_tab_it + 1 : mTabs.begin(); + } + while ((*next_tab_it)->getName() == "sidebar_openclose"); + + selectTabByName((*next_tab_it)->getName(), true); // Don't hide the tab being removed. + } + + // Remove the tab. + removeChild(tab); + mTabs.erase(tab_it); + + // Add the tab to detached tabs list. + mDetachedTabs.push_back(tab); + + // Remove the button from the buttons panel so that it isn't drawn anymore. + mButtonsPanel->removeChild(btn); + + // Re-arrange remaining tabs. + arrange(); + + return true; +} + +bool LLSideTray::addTab(LLSideTrayTab* tab) { - //create show/hide button - mCollapseButton = createButton(EXPANDED_NAME,"",boost::bind(&LLSideTray::onToggleCollapse, this)); + if (tab == NULL) return false; - //create buttons for tabs - child_vector_const_iter_t child_it; + std::string tab_name = tab->getName(); - for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + // Make sure the tab isn't already in the list. + if (std::find(mTabs.begin(), mTabs.end(), tab) != mTabs.end()) { - LLSideTrayTab* sidebar_tab = dynamic_cast<LLSideTrayTab*>(*child_it); - if(sidebar_tab == NULL) - continue; + llwarns << "Attempt to re-add existing tab " << tab_name << llendl; + return false; + } + + // Look up the corresponding button. + button_map_t::const_iterator btn_it = mTabButtons.find(tab_name); + if (btn_it == mTabButtons.end()) + { + llwarns << "Tab " << tab_name << " has no associated button" << llendl; + return false; + } + LLButton* btn = btn_it->second; + + // Insert the tab at its original position. + LLUICtrl::addChild(tab); + { + tab_order_vector_const_iter_t new_tab_orig_pos = + std::find(mOriginalTabOrder.begin(), mOriginalTabOrder.end(), tab_name); + llassert(new_tab_orig_pos != mOriginalTabOrder.end()); + child_vector_iter_t insert_pos = mTabs.end(); + + for (child_vector_iter_t tab_it = mTabs.begin(); tab_it != mTabs.end(); ++tab_it) + { + tab_order_vector_const_iter_t cur_tab_orig_pos = + std::find(mOriginalTabOrder.begin(), mOriginalTabOrder.end(), (*tab_it)->getName()); + llassert(cur_tab_orig_pos != mOriginalTabOrder.end()); + + if (new_tab_orig_pos < cur_tab_orig_pos) + { + insert_pos = tab_it; + break; + } + } + + mTabs.insert(insert_pos, tab); + } + + // Add the button to the buttons panel so that it's drawn again. + mButtonsPanel->addChildInBack(btn); - string name = sidebar_tab->getName(); + // Arrange tabs after inserting a new one. + arrange(); + + // Remove the tab from the list of detached tabs. + child_vector_iter_t tab_it = std::find(mDetachedTabs.begin(), mDetachedTabs.end(), tab); + if (tab_it != mDetachedTabs.end()) + { + mDetachedTabs.erase(tab_it); + } + + return true; +} + +void LLSideTray::createButtons () +{ + //create buttons for tabs + child_vector_const_iter_t child_it = mTabs.begin(); + for ( ; child_it != mTabs.end(); ++child_it) + { + LLSideTrayTab* sidebar_tab = *child_it; + + std::string name = sidebar_tab->getName(); + + // The "OpenClose" button will open/close the whole panel + if (name == "sidebar_openclose") + { + mCollapseButton = createButton(name,sidebar_tab->mImage,sidebar_tab->getTabTitle(), + boost::bind(&LLSideTray::onToggleCollapse, this)); + LLHints::registerHintTarget("side_panel_btn", mCollapseButton->getHandle()); + } + else + { + LLButton* button = createButton(name,sidebar_tab->mImage,sidebar_tab->getTabTitle(), + boost::bind(&LLSideTray::onTabButtonClick, this, name)); + mTabButtons[name] = button; + } + } + LLHints::registerHintTarget("inventory_btn", mTabButtons["sidebar_inventory"]->getHandle()); + LLHints::registerHintTarget("dest_guide_btn", mTabButtons["sidebar_places"]->getHandle()); +} + +void LLSideTray::processTriState () +{ + if(mCollapsed) + expandSideBar(); + else + { +#if 0 // *TODO: EXT-2092 - LLButton* button = createButton("",sidebar_tab->mImagePath,boost::bind(&LLSideTray::onTabButtonClick, this, sidebar_tab->getName())); - mTabButtons[sidebar_tab->getName()] = button; + // Tell the active task panel to switch to its default view + // or collapse side tray if already on the default view. + LLSD info; + info["task-panel-action"] = "handle-tri-state"; + mActiveTab->notifyChildren(info); +#else + collapseSideBar(); +#endif } - } void LLSideTray::onTabButtonClick(string name) { - + LLSideTrayTab* tab = getTab(name); + if (!tab) return; + + if(tab == mActiveTab) + { + processTriState (); + return; + } selectTabByName (name); if(mCollapsed) expandSideBar(); @@ -449,10 +949,11 @@ void LLSideTray::onTabButtonClick(string name) void LLSideTray::onToggleCollapse() { + LLFirstUse::notUsingSidePanel(false); if(mCollapsed) { expandSideBar(); - selectTabByName("home_tab"); + //selectTabByName("sidebar_openclose"); } else collapseSideBar(); @@ -461,32 +962,36 @@ void LLSideTray::onToggleCollapse() void LLSideTray::reflectCollapseChange() { - setPanelRect(); + updateSidetrayVisibility(); if(mCollapsed) + { gFloaterView->setSnapOffsetRight(0); + setFocus(FALSE); + } else - gFloaterView->setSnapOffsetRight(mMaxBarWidth); + { + gFloaterView->setSnapOffsetRight(getRect().getWidth()); + setFocus(TRUE); + } gFloaterView->refresh(); - - setFocus( FALSE ); + + LLSD new_value = mCollapsed; + mCollapseSignal(this,new_value); } -void LLSideTray::arrange () +void LLSideTray::arrange() { - static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams<LLSideTray::Params>()); + static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams<LLSideTray>()); - calcMaxSideBarWidth(); - - - - setPanelRect(); + updateSidetrayVisibility(); LLRect ctrl_rect; - ctrl_rect.setLeftTopAndSize(0,getRect().getHeight()-sidetray_params.default_button_width - ,sidetray_params.default_button_width - ,sidetray_params.default_button_height); + ctrl_rect.setLeftTopAndSize(0, + mButtonsPanel->getRect().getHeight() - sidetray_params.default_button_width, + sidetray_params.default_button_width, + sidetray_params.default_button_height); mCollapseButton->setRect(ctrl_rect); @@ -496,13 +1001,12 @@ void LLSideTray::arrange () int offset = (sidetray_params.default_button_height+sidetray_params.default_button_margin)*2; for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) { - LLSideTrayTab* sidebar_tab = dynamic_cast<LLSideTrayTab*>(*child_it); - if(sidebar_tab == NULL) - continue; + LLSideTrayTab* sidebar_tab = *child_it; - ctrl_rect.setLeftTopAndSize(0,getRect().getHeight()-offset - ,sidetray_params.default_button_width - ,sidetray_params.default_button_height); + ctrl_rect.setLeftTopAndSize(0, + mButtonsPanel->getRect().getHeight()-offset, + sidetray_params.default_button_width, + sidetray_params.default_button_height); if(mTabButtons.find(sidebar_tab->getName()) == mTabButtons.end()) continue; @@ -516,75 +1020,107 @@ void LLSideTray::arrange () btn->setVisible(ctrl_rect.mBottom > 0); } - ctrl_rect.setLeftTopAndSize(sidetray_params.default_button_width,getRect().getHeight(),mMaxBarWidth,getRect().getHeight()); - //arrange tabs - for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + for ( child_vector_t::iterator child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) { - LLSideTrayTab* sidebar_tab = dynamic_cast<LLSideTrayTab*>(*child_it); - if(sidebar_tab == NULL) - continue; - - sidebar_tab->setRect(ctrl_rect); - sidebar_tab->arrange(mMaxBarWidth,getRect().getHeight()); + LLSideTrayTab* sidebar_tab = *child_it; + sidebar_tab->setShape(getLocalRect()); } - mHomeTab->setRect(ctrl_rect); - mHomeTab->arrange(mMaxBarWidth,getRect().getHeight()); - + // The tab buttons should be shown only if there is at least one non-detached tab. + mButtonsPanel->setVisible(hasTabs()); +} + +// Detach those tabs that were detached when the viewer exited last time. +void LLSideTray::detachTabs() +{ + // copy mTabs because LLSideTray::toggleTabDocked() modifies it. + child_vector_t tabs = mTabs; + + for (child_vector_const_iter_t it = tabs.begin(); it != tabs.end(); ++it) + { + LLSideTrayTab* tab = *it; + + std::string floater_ctrl_name = LLFloater::getControlName("side_bar_tab", LLSD(tab->getName())); + std::string vis_ctrl_name = LLFloaterReg::getVisibilityControlName(floater_ctrl_name); + if (!LLFloater::getControlGroup()->controlExists(vis_ctrl_name)) continue; + + bool is_visible = LLFloater::getControlGroup()->getBOOL(vis_ctrl_name); + if (!is_visible) continue; + + llassert(isTabAttached(tab->getName())); + tab->toggleTabDocked(); + } } -void LLSideTray::collapseSideBar () +void LLSideTray::collapseSideBar() { mCollapsed = true; - mCollapseButton->setLabel(COLLAPSED_NAME); - mActiveTab->setVisible(FALSE); + // Reset all overlay images, because there is no "selected" tab when the + // whole side tray is hidden. + child_vector_const_iter_t it = mTabs.begin(); + for ( ; it != mTabs.end(); ++it ) + { + LLSideTrayTab* tab = *it; + std::string name = tab->getName(); + std::map<std::string,LLButton*>::const_iterator btn_it = + mTabButtons.find(name); + if (btn_it != mTabButtons.end()) + { + LLButton* btn = btn_it->second; + btn->setImageOverlay( tab->mImage ); + } + } + + // OpenClose tab doesn't put its button in mTabButtons + LLSideTrayTab* openclose_tab = getTab("sidebar_openclose"); + if (openclose_tab) + { + mCollapseButton->setImageOverlay( openclose_tab->mImage ); + } + //mActiveTab->setVisible(FALSE); reflectCollapseChange(); setFocus( FALSE ); - } -void LLSideTray::expandSideBar () + +void LLSideTray::expandSideBar(bool open_active) { mCollapsed = false; - mCollapseButton->setLabel(EXPANDED_NAME); - mActiveTab->setVisible(TRUE); + LLSideTrayTab* openclose_tab = getTab("sidebar_openclose"); + if (openclose_tab) + { + mCollapseButton->setImageOverlay( openclose_tab->mImageSelected ); + } - reflectCollapseChange(); + if (open_active) + { + mActiveTab->onOpen(LLSD()); + } -} + reflectCollapseChange(); -void LLSideTray::calcMaxSideBarWidth() -{ - - S32 max_bar_width = 0; - - child_vector_const_iter_t child_it; - for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + std::string name = mActiveTab->getName(); + std::map<std::string,LLButton*>::const_iterator btn_it = + mTabButtons.find(name); + if (btn_it != mTabButtons.end()) { - LLSideTrayTab* sidebar_tab = dynamic_cast<LLSideTrayTab*>(*child_it); - if(sidebar_tab == NULL) - continue; - max_bar_width = llmax(max_bar_width,sidebar_tab->getMaxSideBarTabWidth()); + LLButton* btn = btn_it->second; + btn->setImageOverlay( mActiveTab->mImageSelected ); } - - if(max_bar_width > 0) - mMaxBarWidth = max_bar_width; - } + void LLSideTray::highlightFocused() { + /* uncomment in case something change if(!mActiveTab) return; - /* uncomment in case something change BOOL dependent_has_focus = gFocusMgr.childHasKeyboardFocus(this); setBackgroundOpaque( dependent_has_focus ); mActiveTab->setBackgroundOpaque( dependent_has_focus ); */ - mActiveTab->setBackgroundOpaque( true ); - - } + //virtual BOOL LLSideTray::handleMouseDown (S32 x, S32 y, MASK mask) { @@ -593,154 +1129,137 @@ BOOL LLSideTray::handleMouseDown (S32 x, S32 y, MASK mask) setFocus(true); return ret; } -void LLSideTray::reshape (S32 width, S32 height, BOOL called_from_parent) + +void LLSideTray::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLPanel::reshape(width, height, called_from_parent); if(!mActiveTab) return; - static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams<LLSideTray::Params>()); - - setPanelRect(); - - LLRect ctrl_rect; - ctrl_rect.setLeftTopAndSize(0 - ,getRect().getHeight()-sidetray_params.default_button_width - ,sidetray_params.default_button_width - ,sidetray_params.default_button_height); - - mCollapseButton->setRect(ctrl_rect); + arrange(); +} - //arrange tab buttons +/** + * Activate tab with "panel_name" panel + * if no such tab - return false, otherwise true. + * TODO* In some cases a pointer to a panel of + * a specific class may be needed so this method + * would need to use templates. + */ +LLPanel* LLSideTray::showPanel (const std::string& panel_name, const LLSD& params) +{ + // Look up the tab in the list of detached tabs. child_vector_const_iter_t child_it; - int offset = (sidetray_params.default_button_height+sidetray_params.default_button_margin)*2; - for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + for ( child_it = mDetachedTabs.begin(); child_it != mDetachedTabs.end(); ++child_it) { - LLSideTrayTab* sidebar_tab = dynamic_cast<LLSideTrayTab*>(*child_it); - if(sidebar_tab == NULL) - continue; - - ctrl_rect.setLeftTopAndSize(0,getRect().getHeight()-offset - ,sidetray_params.default_button_width - ,sidetray_params.default_button_height); + LLPanel* panel = openChildPanel(*child_it, panel_name, params); + if (panel) return panel; + } - if(mTabButtons.find(sidebar_tab->getName()) == mTabButtons.end()) - continue; - - LLButton* btn = mTabButtons[sidebar_tab->getName()]; + // Look up the tab in the list of attached tabs. + for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + { + LLPanel* panel = openChildPanel(*child_it, panel_name, params); + if (panel) return panel; + } + return NULL; +} - btn->setRect(ctrl_rect); - offset+=sidetray_params.default_button_height; - offset+=sidetray_params.default_button_margin; +void LLSideTray::togglePanel(LLPanel* &sub_panel, const std::string& panel_name, const LLSD& params) +{ + if(!sub_panel) + return; - btn->setVisible(ctrl_rect.mBottom > 0); + // If a panel is visible and attached to Side Tray (has LLSideTray among its ancestors) + // it should be toggled off by collapsing Side Tray. + if (sub_panel->isInVisibleChain() && sub_panel->hasAncestor(this)) + { + LLSideTray::getInstance()->collapseSideBar(); } - - //arrange tabs - - for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + else { - LLSideTrayTab* sidebar_tab = dynamic_cast<LLSideTrayTab*>(*child_it); - if(sidebar_tab == NULL) - continue; - sidebar_tab->reshape(mMaxBarWidth,getRect().getHeight()); - ctrl_rect.setLeftTopAndSize(sidetray_params.default_button_width,getRect().getHeight(),mMaxBarWidth,getRect().getHeight()); - sidebar_tab->setRect(ctrl_rect); - + LLSideTray::getInstance()->showPanel(panel_name, params); } - - mHomeTab->reshape(mMaxBarWidth,getRect().getHeight()); - ctrl_rect.setLeftTopAndSize(sidetray_params.default_button_width,getRect().getHeight(),mMaxBarWidth,getRect().getHeight()); - mHomeTab->setRect(ctrl_rect); - - } -/** - * Activate tab with "panel_name" panel - * if no such tab - return false, otherwise true - */ -bool LLSideTray::showPanel (const std::string& panel_name, const LLSD& params) +// This is just LLView::findChildView specialized to restrict the search to LLPanels. +// Optimization for EXT-4068 to avoid searching down to the individual item level +// when inventories are large. +LLPanel *findChildPanel(LLPanel *panel, const std::string& name, bool recurse) { - //arrange tabs - child_vector_const_iter_t child_it; - for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + for (LLView::child_list_const_iter_t child_it = panel->beginChild(); + child_it != panel->endChild(); ++child_it) + { + LLPanel *child_panel = dynamic_cast<LLPanel*>(*child_it); + if (!child_panel) + continue; + if (child_panel->getName() == name) + return child_panel; + } + if (recurse) { - LLView* view = (*child_it)->getChildView(panel_name,true,false); - if(view) + for (LLView::child_list_const_iter_t child_it = panel->beginChild(); + child_it != panel->endChild(); ++child_it) { - onTabButtonClick((*child_it)->getName()); - LLPanel* panel = dynamic_cast<LLPanel*>(view); - if(panel) - panel->onOpen(params); - return true; + LLPanel *child_panel = dynamic_cast<LLPanel*>(*child_it); + if (!child_panel) + continue; + LLPanel *found_panel = findChildPanel(child_panel,name,recurse); + if (found_panel) + { + return found_panel; + } } } - return false; + return NULL; } -void LLSideTray::createHomeTab() +LLPanel* LLSideTray::getPanel(const std::string& panel_name) { - mHomeTab = LLSideTrayTab::createInstance(); - child_vector_iter_t child_it; - for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + // Look up the panel in the list of detached tabs. + for ( child_vector_const_iter_t child_it = mDetachedTabs.begin(); child_it != mDetachedTabs.end(); ++child_it) { - LLSideTrayTab* sidebar_tab = dynamic_cast<LLSideTrayTab*>(*child_it); - if(sidebar_tab == NULL) - continue; - - LLPanel* panel = LLSideTrayInfoPanel::createInstance(sidebar_tab->mImagePath,sidebar_tab->getTabTitle(),sidebar_tab->getDescription()); - - panel->setCommitCallback(boost::bind(&LLSideTray::onTabButtonClick, this, sidebar_tab->getName())); - - LLCollapsibleCtrl::Params panel_params; - panel_params.display_children(true); - panel_params.collapsible(false); - panel_params.header_visible(false); - panel_params.can_resize(false); - panel_params.min_height(200); - panel_params.padding_left(10); - panel_params.padding_right(10); - panel_params.padding_top(5); - panel_params.padding_bottom(5); - - LLCollapsibleCtrl* ctrl = LLUICtrlFactory::create<LLCollapsibleCtrl>(panel_params); - - - ctrl->setPanel(panel); - ctrl->postBuild(); - mHomeTab->addChild(ctrl,0); + LLPanel *panel = findChildPanel(*child_it,panel_name,true); + if(panel) + { + return panel; + } } - mHomeTab->setBackgroundVisible(true); - mHomeTab->postBuild(); - - LLUICtrl::addChild(mHomeTab, 0); + // Look up the panel in the list of attached tabs. + for ( child_vector_const_iter_t child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + { + LLPanel *panel = findChildPanel(*child_it,panel_name,true); + if(panel) + { + return panel; + } + } + return NULL; } -static const S32 fake_offset = 132; -static const S32 fake_top_offset = 78; -void LLSideTray::setPanelRect () +LLPanel* LLSideTray::getActivePanel() { - static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams<LLSideTray::Params>()); - - const LLRect& parent_rect = gViewerWindow->getRootView()->getRect(); - - S32 panel_width = sidetray_params.default_button_width+sidetray_params.default_button_margin; - if(!mCollapsed) - panel_width+=mMaxBarWidth; - - S32 panel_height = parent_rect.getHeight()-fake_top_offset; - panel_height -= LLBottomTray::getInstance()->getRect().getHeight(); + if (mActiveTab && !mCollapsed) + { + return mActiveTab->getPanel(); + } + return NULL; +} - LLRect panel_rect; - panel_rect.setLeftTopAndSize( parent_rect.mRight-panel_width, parent_rect.mTop-fake_top_offset, panel_width, panel_height); - setRect(panel_rect); +bool LLSideTray::isPanelActive(const std::string& panel_name) +{ + LLPanel *panel = getActivePanel(); + if (!panel) return false; + return (panel->getName() == panel_name); } -S32 LLSideTray::getTrayWidth() +void LLSideTray::updateSidetrayVisibility() { - static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams<LLSideTray::Params>()); - return getRect().getWidth() - (sidetray_params.default_button_width + sidetray_params.default_button_margin); + // set visibility of parent container based on collapsed state + if (getParent()) + { + getParent()->setVisible(!mCollapsed && !gAgentCamera.cameraMouselook()); + } } + |