diff options
Diffstat (limited to 'indra/llui/lltabcontainer.cpp')
-rwxr-xr-x[-rw-r--r--] | indra/llui/lltabcontainer.cpp | 715 |
1 files changed, 474 insertions, 241 deletions
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 3ca05ff0ff..6f858cdeb3 100644..100755 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -2,40 +2,33 @@ * @file lltabcontainer.cpp * @brief LLTabContainer class * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&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$ */ #include "linden_common.h" #include "lltabcontainer.h" - +#include "llviewereventrecorder.h" #include "llfocusmgr.h" -#include "llbutton.h" #include "lllocalcliprect.h" #include "llrect.h" #include "llresizehandle.h" @@ -44,6 +37,7 @@ #include "lluictrlfactory.h" #include "llrender.h" #include "llfloater.h" +#include "lltrans.h" //---------------------------------------------------------------------------- @@ -95,6 +89,96 @@ public: //---------------------------------------------------------------------------- +//============================================================================ +/* + * @file lltabcontainer.cpp + * @brief class implements LLButton with LLIconCtrl on it + */ +class LLCustomButtonIconCtrl : public LLButton +{ +public: + struct Params + : public LLInitParam::Block<Params, LLButton::Params> + { + // LEFT, RIGHT, TOP, BOTTOM paddings of LLIconCtrl in this class has same value + Optional<S32> icon_ctrl_pad; + + Params() + : icon_ctrl_pad("icon_ctrl_pad", 1) + {} + }; + +protected: + friend class LLUICtrlFactory; + + LLCustomButtonIconCtrl(const Params& p) + : LLButton(p), + mIcon(NULL), + mIconAlignment(LLFontGL::HCENTER), + mIconCtrlPad(p.icon_ctrl_pad) + {} + +public: + + void updateLayout() + { + LLRect button_rect = getRect(); + LLRect icon_rect = mIcon->getRect(); + + S32 icon_size = button_rect.getHeight() - 2*mIconCtrlPad; + + switch(mIconAlignment) + { + case LLFontGL::LEFT: + icon_rect.setLeftTopAndSize(button_rect.mLeft + mIconCtrlPad, button_rect.mTop - mIconCtrlPad, + icon_size, icon_size); + setLeftHPad(icon_size + mIconCtrlPad * 2); + break; + case LLFontGL::HCENTER: + icon_rect.setLeftTopAndSize(button_rect.mRight - (button_rect.getWidth() + mIconCtrlPad - icon_size)/2, button_rect.mTop - mIconCtrlPad, + icon_size, icon_size); + setRightHPad(icon_size + mIconCtrlPad * 2); + break; + case LLFontGL::RIGHT: + icon_rect.setLeftTopAndSize(button_rect.mRight - mIconCtrlPad - icon_size, button_rect.mTop - mIconCtrlPad, + icon_size, icon_size); + setRightHPad(icon_size + mIconCtrlPad * 2); + break; + default: + break; + } + mIcon->setRect(icon_rect); + } + + void setIcon(LLIconCtrl* icon, LLFontGL::HAlign alignment = LLFontGL::LEFT) + { + if(icon) + { + if(mIcon) + { + removeChild(mIcon); + mIcon->die(); + } + mIcon = icon; + mIconAlignment = alignment; + + addChild(mIcon); + updateLayout(); + } + } + + LLIconCtrl* getIconCtrl() const + { + return mIcon; + } + +private: + LLIconCtrl* mIcon; + LLFontGL::HAlign mIconAlignment; + S32 mIconCtrlPad; +}; +//============================================================================ + struct LLPlaceHolderPanel : public LLPanel { // create dummy param block to register with "placeholder" nane @@ -105,24 +189,37 @@ struct LLPlaceHolderPanel : public LLPanel static LLDefaultChildRegistry::Register<LLPlaceHolderPanel> r1("placeholder"); static LLDefaultChildRegistry::Register<LLTabContainer> r2("tab_container"); +LLTabContainer::TabParams::TabParams() +: tab_top_image_unselected("tab_top_image_unselected"), + tab_top_image_selected("tab_top_image_selected"), + tab_top_image_flash("tab_top_image_flash"), + tab_bottom_image_unselected("tab_bottom_image_unselected"), + tab_bottom_image_selected("tab_bottom_image_selected"), + tab_bottom_image_flash("tab_bottom_image_flash"), + tab_left_image_unselected("tab_left_image_unselected"), + tab_left_image_selected("tab_left_image_selected"), + tab_left_image_flash("tab_left_image_flash") +{} + LLTabContainer::Params::Params() : tab_width("tab_width"), tab_min_width("tab_min_width"), tab_max_width("tab_max_width"), tab_height("tab_height"), + label_pad_bottom("label_pad_bottom"), + label_pad_left("label_pad_left"), tab_position("tab_position"), hide_tabs("hide_tabs", false), tab_padding_right("tab_padding_right"), - tab_top_image_unselected("tab_top_image_unselected"), - tab_top_image_selected("tab_top_image_selected"), - tab_bottom_image_unselected("tab_bottom_image_unselected"), - tab_bottom_image_selected("tab_bottom_image_selected"), - tab_left_image_unselected("tab_left_image_unselected"), - tab_left_image_selected("tab_left_image_selected") -{ - name(std::string("tab_container")); - mouse_opaque = false; -} + first_tab("first_tab"), + middle_tab("middle_tab"), + last_tab("last_tab"), + use_custom_icon_ctrl("use_custom_icon_ctrl", false), + open_tabs_on_drag_and_drop("open_tabs_on_drag_and_drop", false), + tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0), + use_ellipses("use_ellipses"), + font_halign("halign") +{} LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) : LLPanel(p), @@ -138,6 +235,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) mMinTabWidth(0), mMaxTabWidth(p.tab_max_width), mTabHeight(p.tab_height), + mLabelPadBottom(p.label_pad_bottom), + mLabelPadLeft(p.label_pad_left), mPrevArrowBtn(NULL), mNextArrowBtn(NULL), mIsVertical( p.tab_position == LEFT ), @@ -147,12 +246,15 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) mRightTabBtnOffset(p.tab_padding_right), mTotalTabWidth(0), mTabPosition(p.tab_position), - mImageTopUnselected(p.tab_top_image_unselected), - mImageTopSelected(p.tab_top_image_selected), - mImageBottomUnselected(p.tab_bottom_image_unselected), - mImageBottomSelected(p.tab_bottom_image_selected), - mImageLeftUnselected(p.tab_left_image_unselected), - mImageLeftSelected(p.tab_left_image_selected) + mFontHalign(p.font_halign), + mFont(p.font), + mFirstTabParams(p.first_tab), + mMiddleTabParams(p.middle_tab), + mLastTabParams(p.last_tab), + mCustomIconCtrlUsed(p.use_custom_icon_ctrl), + mOpenTabsOnDragAndDrop(p.open_tabs_on_drag_and_drop), + mTabIconCtrlPad(p.tab_icon_ctrl_pad), + mUseTabEllipses(p.use_ellipses) { static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0); @@ -179,6 +281,7 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) LLTabContainer::~LLTabContainer() { std::for_each(mTabList.begin(), mTabList.end(), DeletePointer()); + mTabList.clear(); } //virtual @@ -256,8 +359,6 @@ bool LLTabContainer::addChild(LLView* view, S32 tab_group) if (panelp) { - panelp->setSaveToXML(TRUE); - addTabPanel(TabPanelParams().panel(panelp).label(panelp->getLabel()).is_placeholder(dynamic_cast<LLPlaceHolderPanel*>(view) != NULL)); return true; } @@ -306,7 +407,7 @@ void LLTabContainer::draw() } } - setScrollPosPixels((S32)lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f))); + setScrollPosPixels((S32)lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLSmoothInterpolation::getInterpolant(0.08f))); BOOL has_scroll_arrows = !getTabsHidden() && ((mMaxScrollPos > 0) || (mScrollPosPixels > 0)); if (!mIsVertical) @@ -340,7 +441,13 @@ void LLTabContainer::draw() } } - LLPanel::draw(); + { + LLRect clip_rect = getLocalRect(); + clip_rect.mLeft+=(LLPANEL_BORDER_WIDTH + 2); + clip_rect.mRight-=(LLPANEL_BORDER_WIDTH + 2); + LLLocalClipRect clip(clip_rect); + LLPanel::draw(); + } // if tabs are hidden, don't draw them and leave them in the invisible state if (!getTabsHidden()) @@ -352,24 +459,6 @@ void LLTabContainer::draw() tuple->mButton->setVisible( TRUE ); } - // Draw some of the buttons... - LLRect clip_rect = getLocalRect(); - if (has_scroll_arrows) - { - // ...but clip them. - if (mIsVertical) - { - clip_rect.mBottom = mNextArrowBtn->getRect().mTop + 3*tabcntrv_pad; - clip_rect.mTop = mPrevArrowBtn->getRect().mBottom - 3*tabcntrv_pad; - } - else - { - clip_rect.mLeft = mPrevArrowBtn->getRect().mRight; - clip_rect.mRight = mNextArrowBtn->getRect().mLeft; - } - } - LLLocalClipRect clip(clip_rect); - S32 max_scroll_visible = getTabCount() - getMaxScrollPos() + getScrollPos(); S32 idx = 0; for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) @@ -398,12 +487,6 @@ void LLTabContainer::draw() } } } - LLUI::pushMatrix(); - { - LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f); - tuple->mButton->draw(); - } - LLUI::popMatrix(); idx++; } @@ -412,20 +495,20 @@ void LLTabContainer::draw() if( mIsVertical && has_scroll_arrows ) { // Redraw the arrows so that they appears on top. - gGL.pushMatrix(); - gGL.translatef((F32)mPrevArrowBtn->getRect().mLeft, (F32)mPrevArrowBtn->getRect().mBottom, 0.f); + gGL.pushUIMatrix(); + gGL.translateUI((F32)mPrevArrowBtn->getRect().mLeft, (F32)mPrevArrowBtn->getRect().mBottom, 0.f); mPrevArrowBtn->draw(); - gGL.popMatrix(); + gGL.popUIMatrix(); - gGL.pushMatrix(); - gGL.translatef((F32)mNextArrowBtn->getRect().mLeft, (F32)mNextArrowBtn->getRect().mBottom, 0.f); + gGL.pushUIMatrix(); + gGL.translateUI((F32)mNextArrowBtn->getRect().mLeft, (F32)mNextArrowBtn->getRect().mBottom, 0.f); mNextArrowBtn->draw(); - gGL.popMatrix(); + gGL.popUIMatrix(); } } - mPrevArrowBtn->setFlashing(FALSE); - mNextArrowBtn->setFlashing(FALSE); + mPrevArrowBtn->setFlashing(false); + mNextArrowBtn->setFlashing(false); } @@ -469,23 +552,23 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) } S32 tab_count = getTabCount(); - if (tab_count > 0) + if (tab_count > 0 && !getTabsHidden()) { LLTabTuple* firsttuple = getTab(0); LLRect tab_rect; if (mIsVertical) { tab_rect = LLRect(firsttuple->mButton->getRect().mLeft, - has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop, - firsttuple->mButton->getRect().mRight, - has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom ); + has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop, + firsttuple->mButton->getRect().mRight, + has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom ); } else { tab_rect = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft, - firsttuple->mButton->getRect().mTop, - has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight, - firsttuple->mButton->getRect().mBottom ); + firsttuple->mButton->getRect().mTop, + has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight, + firsttuple->mButton->getRect().mBottom ); } if( tab_rect.pointInRect( x, y ) ) { @@ -496,6 +579,11 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) tab_button->setFocus(TRUE); } } + if (handled) { + // Note: May need to also capture local coords right here ? + LLViewerEventRecorder::instance().update_xui(getPathname( )); + } + return handled; } @@ -547,30 +635,33 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask ) BOOL handled = FALSE; BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden(); + S32 local_x = x - getRect().mLeft; + S32 local_y = y - getRect().mBottom; + if (has_scroll_arrows) { if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) { - S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; - S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; + local_x = x - mJumpPrevArrowBtn->getRect().mLeft; + local_y = y - mJumpPrevArrowBtn->getRect().mBottom; handled = mJumpPrevArrowBtn->handleMouseUp(local_x, local_y, mask); } else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) { - S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; - S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; + local_x = x - mJumpNextArrowBtn->getRect().mLeft; + local_y = y - mJumpNextArrowBtn->getRect().mBottom; handled = mJumpNextArrowBtn->handleMouseUp(local_x, local_y, mask); } else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y)) { - S32 local_x = x - mPrevArrowBtn->getRect().mLeft; - S32 local_y = y - mPrevArrowBtn->getRect().mBottom; + local_x = x - mPrevArrowBtn->getRect().mLeft; + local_y = y - mPrevArrowBtn->getRect().mBottom; handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask); } else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y)) { - S32 local_x = x - mNextArrowBtn->getRect().mLeft; - S32 local_y = y - mNextArrowBtn->getRect().mBottom; + local_x = x - mNextArrowBtn->getRect().mLeft; + local_y = y - mNextArrowBtn->getRect().mBottom; handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask); } } @@ -594,6 +685,10 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask ) } gFocusMgr.setMouseCapture(NULL); } + if (handled) { + // Note: may need to capture local coords here + LLViewerEventRecorder::instance().update_xui(getPathname( )); + } return handled; } @@ -602,7 +697,7 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, MASK mask) { static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); BOOL handled = LLPanel::handleToolTip( x, y, mask); - if (!handled && getTabCount() > 0) + if (!handled && getTabCount() > 0 && !getTabsHidden()) { LLTabTuple* firsttuple = getTab(0); @@ -638,12 +733,6 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, MASK mask) } } } - - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( FALSE ); - } } return handled; } @@ -739,48 +828,62 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDrag { BOOL has_scroll_arrows = (getMaxScrollPos() > 0); - if( mDragAndDropDelayTimer.getStarted() && mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME ) + if(mOpenTabsOnDragAndDrop && !getTabsHidden()) { - if (has_scroll_arrows) + // In that case, we'll open the hovered tab while dragging and dropping items. + // This allows for drilling through tabs. + if (mDragAndDropDelayTimer.getStarted()) { - if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) + if (mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME) { - S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; - S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; - mJumpPrevArrowBtn->handleHover(local_x, local_y, mask); - } - if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; - S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; - mJumpNextArrowBtn->handleHover(local_x, local_y, mask); - } - if (mPrevArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mPrevArrowBtn->getRect().mLeft; - S32 local_y = y - mPrevArrowBtn->getRect().mBottom; - mPrevArrowBtn->handleHover(local_x, local_y, mask); - } - else if (mNextArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mNextArrowBtn->getRect().mLeft; - S32 local_y = y - mNextArrowBtn->getRect().mBottom; - mNextArrowBtn->handleHover(local_x, local_y, mask); - } - } + if (has_scroll_arrows) + { + if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; + S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; + mJumpPrevArrowBtn->handleHover(local_x, local_y, mask); + } + if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; + S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; + mJumpNextArrowBtn->handleHover(local_x, local_y, mask); + } + if (mPrevArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mPrevArrowBtn->getRect().mLeft; + S32 local_y = y - mPrevArrowBtn->getRect().mBottom; + mPrevArrowBtn->handleHover(local_x, local_y, mask); + } + else if (mNextArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mNextArrowBtn->getRect().mLeft; + S32 local_y = y - mNextArrowBtn->getRect().mBottom; + mNextArrowBtn->handleHover(local_x, local_y, mask); + } + } - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( TRUE ); - S32 local_x = x - tuple->mButton->getRect().mLeft; - S32 local_y = y - tuple->mButton->getRect().mBottom; - if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) - { - tuple->mButton->onCommit(); + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + tuple->mButton->setVisible( TRUE ); + S32 local_x = x - tuple->mButton->getRect().mLeft; + S32 local_y = y - tuple->mButton->getRect().mBottom; + if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) + { + tuple->mButton->onCommit(); + } + } + // Stop the timer whether successful or not. Don't let it run forever. mDragAndDropDelayTimer.stop(); } } + else + { + // Start a timer so we don't open tabs as soon as we hover on them + mDragAndDropDelayTimer.start(); + } } return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip); @@ -791,9 +894,39 @@ void LLTabContainer::addTabPanel(LLPanel* panelp) addTabPanel(TabPanelParams().panel(panelp)); } +// function to update images +void LLTabContainer::update_images(LLTabTuple* tuple, TabParams params, LLTabContainer::TabPosition pos) +{ + if (tuple && tuple->mButton) + { + if (pos == LLTabContainer::TOP) + { + tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_top_image_unselected)); + tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_top_image_selected)); + tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_top_image_flash)); + } + else if (pos == LLTabContainer::BOTTOM) + { + tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_bottom_image_unselected)); + tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_bottom_image_selected)); + tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_bottom_image_flash)); + } + else if (pos == LLTabContainer::LEFT) + { + tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_left_image_unselected)); + tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_left_image_selected)); + tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_left_image_flash)); + } + } +} + void LLTabContainer::addTabPanel(const TabPanelParams& panel) { LLPanel* child = panel.panel(); + + llassert(child); + if (!child) return; + const std::string& label = panel.label.isProvided() ? panel.label() : panel.panel()->getLabel(); @@ -810,8 +943,6 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) // already a child of mine return; } - const LLFontGL* font = - (mIsVertical ? LLFontGL::getFontSansSerif() : LLFontGL::getFontSansSerifSmall()); // Store the original label for possible xml export. child->setLabel(label); @@ -821,7 +952,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) S32 button_width = mMinTabWidth; if (!mIsVertical) { - button_width = llclamp(font->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth); + button_width = llclamp(mFont->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth); } // Tab panel @@ -851,7 +982,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) LLRect tab_panel_rect; if (!getTabsHidden() && mIsVertical) { - tab_panel_rect = LLRect(mMinTabWidth + (LLPANEL_BORDER_WIDTH * 2) + tabcntrv_pad, + tab_panel_rect = LLRect(mMinTabWidth + mRightTabBtnOffset + (LLPANEL_BORDER_WIDTH * 2) + tabcntrv_pad, getRect().getHeight() - LLPANEL_BORDER_WIDTH, getRect().getWidth() - LLPANEL_BORDER_WIDTH, LLPANEL_BORDER_WIDTH); @@ -888,94 +1019,83 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) else if( getTabPosition() == LLTabContainer::TOP ) { btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, mTabHeight); - tab_img = mImageTopUnselected.get(); - tab_selected_img = mImageTopSelected.get(); + tab_img = mMiddleTabParams.tab_top_image_unselected; + tab_selected_img = mMiddleTabParams.tab_top_image_selected; } else { btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, mTabHeight); - tab_img = mImageBottomUnselected.get(); - tab_selected_img = mImageBottomSelected.get(); + tab_img = mMiddleTabParams.tab_bottom_image_unselected; + tab_selected_img = mMiddleTabParams.tab_bottom_image_selected; } LLTextBox* textbox = NULL; LLButton* btn = NULL; + LLCustomButtonIconCtrl::Params custom_btn_params; + { + custom_btn_params.icon_ctrl_pad(mTabIconCtrlPad); + } + LLButton::Params normal_btn_params; if (placeholder) { - btn_rect.translate(0, -LLBUTTON_V_PAD-2); + btn_rect.translate(0, -6); // *TODO: make configurable LLTextBox::Params params; params.name(trimmed_label); params.rect(btn_rect); params.initial_value(trimmed_label); - params.font(font); + params.font(mFont); textbox = LLUICtrlFactory::create<LLTextBox> (params); LLButton::Params p; - p.name(""); + p.name("placeholder"); btn = LLUICtrlFactory::create<LLButton>(p); } else { + LLButton::Params& p = (mCustomIconCtrlUsed ? custom_btn_params : normal_btn_params); + + p.rect(btn_rect); + p.font(mFont); + p.font_halign = mFontHalign; + p.label(trimmed_label); + p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); + if (indent) + { + p.pad_left(indent); + } + p.pad_bottom( mLabelPadBottom ); + p.scale_image(true); + p.tab_stop(false); + p.label_shadow(false); + p.follows.flags = FOLLOWS_LEFT; + if (mIsVertical) { - LLButton::Params p; - p.name(std::string("vert tab button")); - p.rect(btn_rect); - p.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT); - p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); - p.font(font); - p.label(trimmed_label); - p.image_unselected(mImageLeftUnselected); - p.image_selected(mImageLeftSelected); - p.scale_image(true); - p.font_halign = LLFontGL::LEFT; - p.tab_stop(false); - if (indent) - { - p.pad_left(indent); - } - btn = LLUICtrlFactory::create<LLButton>(p); + p.name("vtab_"+std::string(child->getName())); + p.image_unselected(mMiddleTabParams.tab_left_image_unselected); + p.image_selected(mMiddleTabParams.tab_left_image_selected); + p.follows.flags = p.follows.flags() | FOLLOWS_TOP; + } + else + { + p.name("htab_"+std::string(child->getName())); + p.visible(false); + p.image_unselected(tab_img); + p.image_selected(tab_selected_img); + p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM); + // Try to squeeze in a bit more text + p.pad_left( mLabelPadLeft ); + p.pad_right(2); + } + + // *TODO : It seems wrong not to use p in both cases considering the way p is initialized + if (mCustomIconCtrlUsed) + { + btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params); } else { - std::string tooltip = trimmed_label; - tooltip += "\nAlt-Left arrow for previous tab"; - tooltip += "\nAlt-Right arrow for next tab"; - - LLButton::Params p; - p.name(std::string(child->getName()) + " tab"); - p.rect(btn_rect); - p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); - p.font(font); - p.label(trimmed_label); - p.visible(false); - p.tool_tip(tooltip); - p.scale_image(true); - p.image_unselected(tab_img); - p.image_selected(tab_selected_img); - p.tab_stop(false); - // Try to squeeze in a bit more text - p.pad_left(4); - p.pad_right(2); - p.font_halign = LLFontGL::LEFT; - p.follows.flags = FOLLOWS_LEFT; - p.follows.flags = FOLLOWS_LEFT; - - if (indent) - { - p.pad_left(indent); - } - - if( getTabPosition() == TOP ) - { - p.follows.flags = p.follows.flags() | FOLLOWS_TOP; - } - else - { - p.follows.flags = p.follows.flags() | FOLLOWS_BOTTOM; - } - btn = LLUICtrlFactory::create<LLButton>(p); } } @@ -983,25 +1103,64 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) LLTabTuple* tuple = new LLTabTuple( this, child, btn, textbox ); insertTuple( tuple, insertion_point ); + // if new tab was added as a first or last tab, update button image + // and update button image of any tab it may have affected + if (tuple == mTabList.front()) + { + update_images(tuple, mFirstTabParams, getTabPosition()); + + if (mTabList.size() == 2) + { + update_images(mTabList[1], mLastTabParams, getTabPosition()); + } + else if (mTabList.size() > 2) + { + update_images(mTabList[1], mMiddleTabParams, getTabPosition()); + } + } + else if (tuple == mTabList.back()) + { + update_images(tuple, mLastTabParams, getTabPosition()); + + if (mTabList.size() > 2) + { + update_images(mTabList[mTabList.size()-2], mMiddleTabParams, getTabPosition()); + } + } + //Don't add button and textbox if tab buttons are invisible(EXT - 576) if (!getTabsHidden()) { if (textbox) { - textbox->setSaveToXML(false); addChild( textbox, 0 ); } if (btn) { - btn->setSaveToXML(false); addChild( btn, 0 ); } } + else + { + if (textbox) + { + LLUICtrl::addChild(textbox, 0); + } + if (btn) + { + LLUICtrl::addChild(btn, 0); + } + } if (child) { LLUICtrl::addChild(child, 1); } + + sendChildToFront(mPrevArrowBtn); + sendChildToFront(mNextArrowBtn); + sendChildToFront(mJumpPrevArrowBtn); + sendChildToFront(mJumpNextArrowBtn); if( select ) { @@ -1064,11 +1223,27 @@ void LLTabContainer::removeTabPanel(LLPanel* child) LLTabTuple* tuple = *iter; if( tuple->mTabPanel == child ) { - removeChild( tuple->mButton ); + // update tab button images if removing the first or last tab + if ((tuple == mTabList.front()) && (mTabList.size() > 1)) + { + update_images(mTabList[1], mFirstTabParams, getTabPosition()); + } + else if ((tuple == mTabList.back()) && (mTabList.size() > 2)) + { + update_images(mTabList[mTabList.size()-2], mLastTabParams, getTabPosition()); + } + + if (!getTabsHidden()) + { + // We need to remove tab buttons only if the tabs are not hidden. + removeChild( tuple->mButton ); + } delete tuple->mButton; + tuple->mButton = NULL; removeChild( tuple->mTabPanel ); // delete tuple->mTabPanel; + tuple->mTabPanel = NULL; mTabList.erase( iter ); delete tuple; @@ -1115,6 +1290,10 @@ void LLTabContainer::enableTabButton(S32 which, BOOL enable) { mTabList[which]->mButton->setEnabled(enable); } + // Stop the DaD timer as it might run forever + // enableTabButton() is typically called on refresh and draw when anything changed + // in the tab container so it's a good time to reset that. + mDragAndDropDelayTimer.stop(); } void LLTabContainer::deleteAllTabs() @@ -1126,9 +1305,11 @@ void LLTabContainer::deleteAllTabs() removeChild( tuple->mButton ); delete tuple->mButton; + tuple->mButton = NULL; removeChild( tuple->mTabPanel ); // delete tuple->mTabPanel; + tuple->mTabPanel = NULL; } // Actually delete the tuples themselves @@ -1299,12 +1480,12 @@ BOOL LLTabContainer::selectTab(S32 which) cbdata = selected_tuple->mTabPanel->getName(); BOOL res = FALSE; - if( mValidateSignal( this, cbdata ) ) + if( !mValidateSignal || (*mValidateSignal)( this, cbdata ) ) { res = setTab(which); - if (res) + if (res && mCommitSignal) { - mCommitSignal(this, cbdata); + (*mCommitSignal)(this, cbdata); } } @@ -1331,11 +1512,20 @@ BOOL LLTabContainer::setTab(S32 which) { LLTabTuple* tuple = *iter; BOOL is_selected = ( tuple == selected_tuple ); - tuple->mTabPanel->setVisible( is_selected ); -// tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here. - tuple->mButton->setToggleState( is_selected ); - // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs - tuple->mButton->setTabStop( is_selected ); + // Although the selected tab must be complete, we may have hollow LLTabTuple tucked in the list + if (tuple && tuple->mButton) + { + tuple->mButton->setUseEllipses(mUseTabEllipses); + tuple->mButton->setHAlign(mFontHalign); + tuple->mButton->setToggleState( is_selected ); + // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs + tuple->mButton->setTabStop( is_selected ); + } + if (tuple && tuple->mTabPanel) + { + tuple->mTabPanel->setVisible( is_selected ); + //tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here. + } if (is_selected) { @@ -1362,7 +1552,7 @@ BOOL LLTabContainer::setTab(S32 which) else { S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1); - S32 running_tab_width = tuple->mButton->getRect().getWidth(); + S32 running_tab_width = (tuple && tuple->mButton ? tuple->mButton->getRect().getWidth() : 0); S32 j = i - 1; S32 min_scroll_pos = i; if (running_tab_width < available_width_with_arrows) @@ -1370,7 +1560,7 @@ BOOL LLTabContainer::setTab(S32 which) while (j >= 0) { LLTabTuple* other_tuple = getTab(j); - running_tab_width += other_tuple->mButton->getRect().getWidth(); + running_tab_width += (other_tuple && other_tuple->mButton ? other_tuple->mButton->getRect().getWidth() : 0); if (running_tab_width > available_width_with_arrows) { break; @@ -1406,8 +1596,7 @@ BOOL LLTabContainer::selectTabByName(const std::string& name) LLPanel* panel = getPanelByName(name); if (!panel) { - llwarns << "LLTabContainer::selectTabByName(" - << name << ") failed" << llendl; + LL_WARNS() << "LLTabContainer::selectTabByName(" << name << ") failed" << LL_ENDL; return FALSE; } @@ -1436,33 +1625,81 @@ void LLTabContainer::setTabPanelFlashing(LLPanel* child, BOOL state ) void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color) { - static LLUICachedControl<S32> tab_padding ("UITabPadding", 0); LLTabTuple* tuple = getTabByPanel(child); if( tuple ) { - tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT, color); + tuple->mButton->setImageOverlay(image_name, LLFontGL::LEFT, color); + reshapeTuple(tuple); + } +} - if (!mIsVertical) +void LLTabContainer::setTabImage(LLPanel* child, const LLUUID& image_id, const LLColor4& color) +{ + LLTabTuple* tuple = getTabByPanel(child); + if( tuple ) + { + tuple->mButton->setImageOverlay(image_id, LLFontGL::LEFT, color); + reshapeTuple(tuple); + } +} + +void LLTabContainer::setTabImage(LLPanel* child, LLIconCtrl* icon) +{ + LLTabTuple* tuple = getTabByPanel(child); + LLCustomButtonIconCtrl* button; + bool hasButton = false; + + if(tuple) + { + button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton); + if(button) { - const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall(); - // remove current width from total tab strip width - mTotalTabWidth -= tuple->mButton->getRect().getWidth(); + hasButton = true; + button->setIcon(icon); + reshapeTuple(tuple); + } + } - S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? - tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : - 0; + if (!hasButton && (icon != NULL)) + { + // It was assumed that the tab's button would take ownership of the icon pointer. + // But since the tab did not have a button, kill the icon to prevent the memory + // leak. + icon->die(); + } +} - tuple->mPadding = image_overlay_width; +void LLTabContainer::reshapeTuple(LLTabTuple* tuple) +{ + static LLUICachedControl<S32> tab_padding ("UITabPadding", 0); - tuple->mButton->setRightHPad(6); - tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), - tuple->mButton->getRect().getHeight()); - // add back in button width to total tab strip width - mTotalTabWidth += tuple->mButton->getRect().getWidth(); + if (!mIsVertical) + { + S32 image_overlay_width = 0; - // tabs have changed size, might need to scroll to see current tab - updateMaxScrollPos(); + if(mCustomIconCtrlUsed) + { + LLCustomButtonIconCtrl* button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton); + LLIconCtrl* icon_ctrl = button ? button->getIconCtrl() : NULL; + image_overlay_width = icon_ctrl ? icon_ctrl->getRect().getWidth() : 0; } + else + { + image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? + tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : 0; + } + // remove current width from total tab strip width + mTotalTabWidth -= tuple->mButton->getRect().getWidth(); + + tuple->mPadding = image_overlay_width; + + tuple->mButton->reshape(llclamp(mFont->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), + tuple->mButton->getRect().getHeight()); + // add back in button width to total tab strip width + mTotalTabWidth += tuple->mButton->getRect().getWidth(); + + // tabs have changed size, might need to scroll to see current tab + updateMaxScrollPos(); } } @@ -1525,7 +1762,10 @@ void LLTabContainer::onTabBtn( const LLSD& data, LLPanel* panel ) LLTabTuple* tuple = getTabByPanel(panel); selectTabPanel( panel ); - tuple->mTabPanel->setFocus(TRUE); + if (tuple) + { + tuple->mTabPanel->setFocus(TRUE); + } } void LLTabContainer::onNextBtn( const LLSD& data ) @@ -1626,23 +1866,23 @@ void LLTabContainer::initButtons() S32 btn_top = (getTabPosition() == TOP ) ? getRect().getHeight() - getTopBorderHeight() : tabcntr_arrow_btn_size + 1; LLRect left_arrow_btn_rect; - left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+tabcntr_arrow_btn_size, btn_top + arrow_fudge, tabcntr_arrow_btn_size, tabcntr_arrow_btn_size ); + left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+tabcntr_arrow_btn_size, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight ); LLRect jump_left_arrow_btn_rect; - jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, tabcntr_arrow_btn_size, tabcntr_arrow_btn_size ); + jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight ); S32 right_pad = tabcntr_arrow_btn_size + LLPANEL_BORDER_WIDTH + 1; LLRect right_arrow_btn_rect; right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad - tabcntr_arrow_btn_size, btn_top + arrow_fudge, - tabcntr_arrow_btn_size, tabcntr_arrow_btn_size ); + tabcntr_arrow_btn_size, mTabHeight ); LLRect jump_right_arrow_btn_rect; jump_right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad, btn_top + arrow_fudge, - tabcntr_arrow_btn_size, tabcntr_arrow_btn_size ); + tabcntr_arrow_btn_size, mTabHeight ); LLButton::Params p; p.name(std::string("Jump Left Arrow")); @@ -1702,24 +1942,20 @@ void LLTabContainer::initButtons() } } - mPrevArrowBtn->setSaveToXML(false); mPrevArrowBtn->setTabStop(FALSE); addChild(mPrevArrowBtn); - mNextArrowBtn->setSaveToXML(false); mNextArrowBtn->setTabStop(FALSE); addChild(mNextArrowBtn); if (mJumpPrevArrowBtn) { - mJumpPrevArrowBtn->setSaveToXML(false); mJumpPrevArrowBtn->setTabStop(FALSE); addChild(mJumpPrevArrowBtn); } if (mJumpNextArrowBtn) { - mJumpNextArrowBtn->setSaveToXML(false); mJumpNextArrowBtn->setTabStop(FALSE); addChild(mJumpNextArrowBtn); } @@ -1858,6 +2094,3 @@ void LLTabContainer::commitHoveredButton(S32 x, S32 y) } } } - - - |