EXT-3929: Moved LLAccordionCtrl to llui.
Both LLAccordionCtrl and LLAccordionCtrlTab should live in llui, not newview. I need to make this happen in order to fix EXT-3929. No code change was necessary (other than to change #include for predefined headers) as these classes did not rely on any newview code.master
parent
df08485cf8
commit
a4baeed12f
|
|
@ -26,6 +26,8 @@ include_directories(
|
|||
)
|
||||
|
||||
set(llui_SOURCE_FILES
|
||||
llaccordionctrl.cpp
|
||||
llaccordionctrltab.cpp
|
||||
llbutton.cpp
|
||||
llcheckboxctrl.cpp
|
||||
llclipboard.cpp
|
||||
|
|
@ -111,6 +113,8 @@ set(llui_SOURCE_FILES
|
|||
set(llui_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
llaccordionctrl.h
|
||||
llaccordionctrltab.h
|
||||
llbutton.h
|
||||
llcallbackmap.h
|
||||
llcheckboxctrl.h
|
||||
|
|
|
|||
|
|
@ -0,0 +1,578 @@
|
|||
/**
|
||||
* @file llaccordionctrl.cpp
|
||||
* @brief Accordion panel implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2009, Linden Research, Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llaccordionctrl.h"
|
||||
#include "llaccordionctrltab.h"
|
||||
|
||||
#include "lluictrlfactory.h" // builds floaters from XML
|
||||
|
||||
#include "llwindow.h"
|
||||
#include "llfocusmgr.h"
|
||||
#include "lllocalcliprect.h"
|
||||
|
||||
#include "boost/bind.hpp"
|
||||
|
||||
static const S32 DRAGGER_BAR_MARGIN = 4;
|
||||
static const S32 DRAGGER_BAR_HEIGHT = 5;
|
||||
static const S32 BORDER_MARGIN = 2;
|
||||
static const S32 PARENT_BORDER_MARGIN = 5;
|
||||
|
||||
static const S32 panel_delta = DRAGGER_BAR_MARGIN; // Distanse between two panels
|
||||
|
||||
static const S32 HORIZONTAL_MULTIPLE = 8;
|
||||
static const S32 VERTICAL_MULTIPLE = 16;
|
||||
static const F32 MIN_AUTO_SCROLL_RATE = 120.f;
|
||||
static const F32 MAX_AUTO_SCROLL_RATE = 500.f;
|
||||
static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f;
|
||||
|
||||
|
||||
// LLAccordionCtrl =================================================================|
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLAccordionCtrl> t2("accordion");
|
||||
|
||||
|
||||
LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params)
|
||||
, mFitParent(params.fit_parent)
|
||||
{
|
||||
mSingleExpansion = params.single_expansion;
|
||||
if(mFitParent && !mSingleExpansion)
|
||||
{
|
||||
llinfos << "fit_parent works best when combined with single_expansion" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
LLAccordionCtrl::LLAccordionCtrl() : LLPanel()
|
||||
{
|
||||
mSingleExpansion = false;
|
||||
mFitParent = false;
|
||||
LLUICtrlFactory::getInstance()->buildPanel(this, "accordion_parent.xml");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
void LLAccordionCtrl::draw()
|
||||
{
|
||||
LLRect local_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
|
||||
|
||||
LLLocalClipRect clip(local_rect);
|
||||
|
||||
LLPanel::draw();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
BOOL LLAccordionCtrl::postBuild()
|
||||
{
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
|
||||
LLRect scroll_rect;
|
||||
scroll_rect.setOriginAndSize(
|
||||
getRect().getWidth() - scrollbar_size,
|
||||
1,
|
||||
scrollbar_size,
|
||||
getRect().getHeight() - 1);
|
||||
|
||||
|
||||
LLScrollbar::Params sbparams;
|
||||
sbparams.name("scrollable vertical");
|
||||
sbparams.rect(scroll_rect);
|
||||
sbparams.orientation(LLScrollbar::VERTICAL);
|
||||
sbparams.doc_size(mInnerRect.getHeight());
|
||||
sbparams.doc_pos(0);
|
||||
sbparams.page_size(mInnerRect.getHeight());
|
||||
sbparams.step_size(VERTICAL_MULTIPLE);
|
||||
sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
|
||||
sbparams.change_callback(boost::bind(&LLAccordionCtrl::onScrollPosChangeCallback, this, _1, _2));
|
||||
|
||||
mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams);
|
||||
LLView::addChild( mScrollbar );
|
||||
mScrollbar->setVisible( false );
|
||||
mScrollbar->setFollowsRight();
|
||||
mScrollbar->setFollowsTop();
|
||||
mScrollbar->setFollowsBottom();
|
||||
|
||||
//if it was created from xml...
|
||||
std::vector<LLUICtrl*> accordion_tabs;
|
||||
for(child_list_const_iter_t it = getChildList()->begin();
|
||||
getChildList()->end() != it; ++it)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(*it);
|
||||
if(accordion_tab == NULL)
|
||||
continue;
|
||||
if(std::find(mAccordionTabs.begin(),mAccordionTabs.end(),accordion_tab) == mAccordionTabs.end())
|
||||
{
|
||||
accordion_tabs.push_back(accordion_tab);
|
||||
}
|
||||
}
|
||||
|
||||
for(std::vector<LLUICtrl*>::reverse_iterator it = accordion_tabs.rbegin();it!=accordion_tabs.rend();++it)
|
||||
addCollapsibleCtrl(*it);
|
||||
|
||||
arrange ();
|
||||
|
||||
if(mSingleExpansion)
|
||||
{
|
||||
if(!mAccordionTabs[0]->getDisplayChildren())
|
||||
mAccordionTabs[0]->setDisplayChildren(true);
|
||||
for(size_t i=1;i<mAccordionTabs.size();++i)
|
||||
{
|
||||
if(mAccordionTabs[i]->getDisplayChildren())
|
||||
mAccordionTabs[i]->setDisplayChildren(false);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
LLAccordionCtrl::~LLAccordionCtrl()
|
||||
{
|
||||
mAccordionTabs.clear();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
void LLAccordionCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
|
||||
{
|
||||
// adjust our rectangle
|
||||
LLRect rcLocal = getRect();
|
||||
rcLocal.mRight = rcLocal.mLeft + width;
|
||||
rcLocal.mTop = rcLocal.mBottom + height;
|
||||
|
||||
setRect(rcLocal);
|
||||
|
||||
arrange();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
BOOL LLAccordionCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
return LLPanel::handleRightMouseDown(x, y, mask);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
void LLAccordionCtrl::shiftAccordionTabs(S16 panel_num, S32 delta)
|
||||
{
|
||||
for(size_t i = panel_num; i < mAccordionTabs.size(); i++ )
|
||||
{
|
||||
ctrlShiftVertical(mAccordionTabs[i],delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
void LLAccordionCtrl::onCollapseCtrlCloseOpen(S16 panel_num)
|
||||
{
|
||||
if(mSingleExpansion)
|
||||
{
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
{
|
||||
if(i==panel_num)
|
||||
continue;
|
||||
if(mAccordionTabs[i]->getDisplayChildren())
|
||||
mAccordionTabs[i]->setDisplayChildren(false);
|
||||
}
|
||||
|
||||
}
|
||||
arrange();
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::show_hide_scrollbar(S32 width, S32 height)
|
||||
{
|
||||
calcRecuiredHeight();
|
||||
if(getRecuiredHeight() > height )
|
||||
showScrollbar(width,height);
|
||||
else
|
||||
hideScrollbar(width,height);
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::showScrollbar(S32 width, S32 height)
|
||||
{
|
||||
bool was_visible = mScrollbar->getVisible();
|
||||
|
||||
mScrollbar->setVisible(true);
|
||||
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
|
||||
ctrlSetLeftTopAndSize(mScrollbar
|
||||
,width-scrollbar_size - PARENT_BORDER_MARGIN/2
|
||||
,height-PARENT_BORDER_MARGIN
|
||||
,scrollbar_size
|
||||
,height-2*PARENT_BORDER_MARGIN);
|
||||
|
||||
mScrollbar->setPageSize(height);
|
||||
mScrollbar->setDocParams(mInnerRect.getHeight(),mScrollbar->getDocPos());
|
||||
|
||||
if(was_visible)
|
||||
{
|
||||
S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1);
|
||||
mScrollbar->setDocPos(scroll_pos);
|
||||
}
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::hideScrollbar( S32 width, S32 height )
|
||||
{
|
||||
if(mScrollbar->getVisible() == false)
|
||||
return;
|
||||
mScrollbar->setVisible(false);
|
||||
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
|
||||
S32 panel_width = width - 2*BORDER_MARGIN;
|
||||
|
||||
//reshape all accordeons and shift all draggers
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
{
|
||||
LLRect panel_rect = mAccordionTabs[i]->getRect();
|
||||
ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_rect.mTop,panel_width,panel_rect.getHeight());
|
||||
}
|
||||
|
||||
mScrollbar->setDocPos(0);
|
||||
|
||||
if(mAccordionTabs.size()>0)
|
||||
{
|
||||
S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel
|
||||
S32 diff = panel_top - mAccordionTabs[0]->getRect().mTop;
|
||||
shiftAccordionTabs(0,diff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
S32 LLAccordionCtrl::calcRecuiredHeight()
|
||||
{
|
||||
S32 rec_height = 0;
|
||||
|
||||
std::vector<LLAccordionCtrlTab*>::iterator panel;
|
||||
for(panel=mAccordionTabs.begin(); panel!=mAccordionTabs.end(); ++panel)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(*panel);
|
||||
if(accordion_tab && accordion_tab->getVisible())
|
||||
{
|
||||
rec_height += accordion_tab->getRect().getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
mInnerRect.setLeftTopAndSize(0,rec_height + BORDER_MARGIN*2,getRect().getWidth(),rec_height + BORDER_MARGIN);
|
||||
|
||||
return mInnerRect.getHeight();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height)
|
||||
{
|
||||
if(!panel)
|
||||
return;
|
||||
LLRect panel_rect = panel->getRect();
|
||||
panel_rect.setLeftTopAndSize( left, top, width, height);
|
||||
panel->reshape( width, height, 1);
|
||||
panel->setRect(panel_rect);
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::ctrlShiftVertical(LLView* panel,S32 delta)
|
||||
{
|
||||
if(!panel)
|
||||
return;
|
||||
panel->translate(0,delta);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
void LLAccordionCtrl::addCollapsibleCtrl(LLView* view)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view);
|
||||
if(!accordion_tab)
|
||||
return;
|
||||
if(std::find(getChildList()->begin(),getChildList()->end(),accordion_tab) == getChildList()->end())
|
||||
addChild(accordion_tab);
|
||||
mAccordionTabs.push_back(accordion_tab);
|
||||
|
||||
accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, mAccordionTabs.size() - 1) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
void LLAccordionCtrl::arrange()
|
||||
{
|
||||
if( mAccordionTabs.size() == 0)
|
||||
{
|
||||
//We do not arrange if we do not have what should be arranged
|
||||
return;
|
||||
}
|
||||
|
||||
//Calculate params
|
||||
S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter
|
||||
S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
|
||||
S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel
|
||||
|
||||
|
||||
if(mAccordionTabs.size() == 1)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[0]);
|
||||
|
||||
LLRect panel_rect = accordion_tab->getRect();
|
||||
|
||||
S32 panel_height = getRect().getHeight() - 2*BORDER_MARGIN;
|
||||
|
||||
ctrlSetLeftTopAndSize(accordion_tab,panel_rect.mLeft,panel_top,panel_width,panel_height);
|
||||
|
||||
show_hide_scrollbar(getRect().getWidth(),getRect().getHeight());
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < mAccordionTabs.size(); i++ )
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
|
||||
if(accordion_tab->getVisible() == false) //skip hidden accordion tabs
|
||||
continue;
|
||||
|
||||
if(!accordion_tab->isExpanded() )
|
||||
{
|
||||
ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, accordion_tab->getRect().getHeight());
|
||||
panel_top-=mAccordionTabs[i]->getRect().getHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 panel_height = accordion_tab->getRect().getHeight();
|
||||
|
||||
if(mFitParent)
|
||||
{
|
||||
// all expanded tabs will have equal height
|
||||
panel_height = calcExpandedTabHeight(i, panel_top);
|
||||
ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, panel_height);
|
||||
|
||||
// try to make accordion tab fit accordion view height.
|
||||
// Accordion View should implement getRequiredRect() and provide valid height
|
||||
S32 optimal_height = accordion_tab->getAccordionView()->getRequiredRect().getHeight();
|
||||
optimal_height += accordion_tab->getHeaderHeight() + 2 * BORDER_MARGIN;
|
||||
if(optimal_height < panel_height)
|
||||
{
|
||||
panel_height = optimal_height;
|
||||
}
|
||||
|
||||
// minimum tab height is equal to header height
|
||||
if(mAccordionTabs[i]->getHeaderHeight() > panel_height)
|
||||
{
|
||||
panel_height = mAccordionTabs[i]->getHeaderHeight();
|
||||
}
|
||||
}
|
||||
|
||||
ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height);
|
||||
panel_top-=panel_height;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
show_hide_scrollbar(getRect().getWidth(),getRect().getHeight());
|
||||
|
||||
updateLayout(getRect().getWidth(),getRect().getHeight());
|
||||
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
BOOL LLAccordionCtrl::handleScrollWheel ( S32 x, S32 y, S32 clicks )
|
||||
{
|
||||
if(LLPanel::handleScrollWheel(x,y,clicks))
|
||||
return TRUE;
|
||||
if( mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) )
|
||||
return TRUE;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrl::handleKeyHere (KEY key, MASK mask)
|
||||
{
|
||||
if( mScrollbar->getVisible() && mScrollbar->handleKeyHere( key,mask ) )
|
||||
return TRUE;
|
||||
return LLPanel::handleKeyHere(key,mask);
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::updateLayout (S32 width, S32 height)
|
||||
{
|
||||
S32 panel_top = height - BORDER_MARGIN ;
|
||||
if(mScrollbar->getVisible())
|
||||
panel_top+=mScrollbar->getDocPos();
|
||||
|
||||
S32 panel_width = width - 2*BORDER_MARGIN;
|
||||
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
if(mScrollbar->getVisible())
|
||||
panel_width-=scrollbar_size;
|
||||
|
||||
//set sizes for first panels and dragbars
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
{
|
||||
if(!mAccordionTabs[i]->getVisible())
|
||||
continue;
|
||||
LLRect panel_rect = mAccordionTabs[i]->getRect();
|
||||
ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_top,panel_width,panel_rect.getHeight());
|
||||
panel_top-=panel_rect.getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*)
|
||||
{
|
||||
updateLayout(getRect().getWidth(),getRect().getHeight());
|
||||
}
|
||||
void LLAccordionCtrl::onOpen (const LLSD& key)
|
||||
{
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
LLPanel* panel = dynamic_cast<LLPanel*>(accordion_tab->getAccordionView());
|
||||
if(panel!=NULL)
|
||||
{
|
||||
panel->onOpen(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
S32 LLAccordionCtrl::notifyParent(const LLSD& info)
|
||||
{
|
||||
if(info.has("action"))
|
||||
{
|
||||
std::string str_action = info["action"];
|
||||
if(str_action == "size_changes")
|
||||
{
|
||||
//
|
||||
arrange();
|
||||
return 1;
|
||||
}
|
||||
else if(str_action == "select_next")
|
||||
{
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
if(accordion_tab->hasFocus())
|
||||
{
|
||||
while(++i<mAccordionTabs.size())
|
||||
{
|
||||
if(mAccordionTabs[i]->getVisible())
|
||||
break;
|
||||
}
|
||||
if(i<mAccordionTabs.size())
|
||||
{
|
||||
accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
accordion_tab->notify(LLSD().with("action","select_first"));
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if(str_action == "select_prev")
|
||||
{
|
||||
for(size_t i=0;i<mAccordionTabs.size();++i)
|
||||
{
|
||||
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
if(accordion_tab->hasFocus() && i>0)
|
||||
{
|
||||
while(i>0)
|
||||
{
|
||||
if(mAccordionTabs[--i]->getVisible())
|
||||
break;
|
||||
}
|
||||
|
||||
accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
|
||||
accordion_tab->notify(LLSD().with("action","select_last"));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (info.has("scrollToShowRect"))
|
||||
{
|
||||
LLRect screen_rc, local_rc;
|
||||
screen_rc.setValue(info["scrollToShowRect"]);
|
||||
screenRectToLocal(screen_rc, &local_rc);
|
||||
|
||||
// Translate to parent coordinatess to check if we are in visible rectangle
|
||||
local_rc.translate( getRect().mLeft, getRect().mBottom );
|
||||
|
||||
if ( !getRect().contains (local_rc) )
|
||||
{
|
||||
// Back to local coords and calculate position for scroller
|
||||
S32 bottom = mScrollbar->getDocPos() - local_rc.mBottom + getRect().mBottom;
|
||||
S32 top = mScrollbar->getDocPos() - local_rc.mTop + getRect().mTop;
|
||||
|
||||
S32 scroll_pos = llclamp(mScrollbar->getDocPos(),
|
||||
bottom, // min vertical scroll
|
||||
top); // max vertical scroll
|
||||
|
||||
mScrollbar->setDocPos( scroll_pos );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return LLPanel::notifyParent(info);
|
||||
}
|
||||
void LLAccordionCtrl::reset ()
|
||||
{
|
||||
if(mScrollbar)
|
||||
mScrollbar->setDocPos(0);
|
||||
}
|
||||
|
||||
S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 available_height /* = 0 */)
|
||||
{
|
||||
if(tab_index < 0)
|
||||
{
|
||||
return available_height;
|
||||
}
|
||||
|
||||
S32 collapsed_tabs_height = 0;
|
||||
S32 num_expanded = 0;
|
||||
|
||||
for(size_t n = tab_index; n < mAccordionTabs.size(); ++n)
|
||||
{
|
||||
if(!mAccordionTabs[n]->isExpanded())
|
||||
{
|
||||
collapsed_tabs_height += mAccordionTabs[n]->getHeaderHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
++num_expanded;
|
||||
}
|
||||
}
|
||||
|
||||
if(0 == num_expanded)
|
||||
{
|
||||
return available_height;
|
||||
}
|
||||
|
||||
S32 expanded_tab_height = available_height - collapsed_tabs_height - BORDER_MARGIN; // top BORDER_MARGIN is added in arrange(), here we add bottom BORDER_MARGIN
|
||||
expanded_tab_height /= num_expanded;
|
||||
return expanded_tab_height;
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* @file LLAccordionCtrl.h
|
||||
* @brief Accordion Panel implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2004-2009, Linden Research, Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_ACCORDIONCTRL_H
|
||||
#define LL_ACCORDIONCTRL_H
|
||||
|
||||
#include "llpanel.h"
|
||||
#include "llscrollbar.h"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
class LLAccordionCtrlTab;
|
||||
|
||||
class LLAccordionCtrl: public LLPanel
|
||||
{
|
||||
private:
|
||||
|
||||
std::vector<LLAccordionCtrlTab*> mAccordionTabs;
|
||||
|
||||
void ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height);
|
||||
void ctrlShiftVertical(LLView* panel,S32 delta);
|
||||
|
||||
void onCollapseCtrlCloseOpen(S16 panel_num);
|
||||
void shiftAccordionTabs(S16 panel_num, S32 delta);
|
||||
|
||||
|
||||
public:
|
||||
struct Params
|
||||
: public LLInitParam::Block<Params, LLPanel::Params>
|
||||
{
|
||||
Optional<bool> single_expansion,
|
||||
fit_parent; /* Accordion will fit its parent size, controls that are placed into
|
||||
accordion tabs are responsible for scrolling their content.
|
||||
*NOTE fit_parent works best when combined with single_expansion.
|
||||
Accordion view should implement getRequiredRect() and provide valid height*/
|
||||
|
||||
Params()
|
||||
: single_expansion("single_expansion",false)
|
||||
, fit_parent("fit_parent", false)
|
||||
{};
|
||||
};
|
||||
|
||||
LLAccordionCtrl(const Params& params);
|
||||
|
||||
LLAccordionCtrl();
|
||||
virtual ~LLAccordionCtrl();
|
||||
|
||||
virtual BOOL postBuild();
|
||||
|
||||
virtual BOOL handleRightMouseDown ( S32 x, S32 y, MASK mask);
|
||||
virtual BOOL handleScrollWheel ( S32 x, S32 y, S32 clicks );
|
||||
virtual BOOL handleKeyHere (KEY key, MASK mask);
|
||||
//
|
||||
|
||||
// Call reshape after changing splitter's size
|
||||
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
|
||||
|
||||
void addCollapsibleCtrl(LLView* view);
|
||||
void arrange();
|
||||
|
||||
|
||||
void draw();
|
||||
|
||||
void onScrollPosChangeCallback(S32, LLScrollbar*);
|
||||
|
||||
void onOpen (const LLSD& key);
|
||||
S32 notifyParent(const LLSD& info);
|
||||
|
||||
void reset ();
|
||||
|
||||
private:
|
||||
// Calc Splitter's height that is necessary to display all child content
|
||||
S32 calcRecuiredHeight();
|
||||
S32 getRecuiredHeight() const { return mInnerRect.getHeight(); }
|
||||
S32 calcExpandedTabHeight(S32 tab_index = 0, S32 available_height = 0);
|
||||
|
||||
void updateLayout (S32 width, S32 height);
|
||||
|
||||
void show_hide_scrollbar (S32 width, S32 height);
|
||||
|
||||
void showScrollbar (S32 width, S32 height);
|
||||
void hideScrollbar (S32 width, S32 height);
|
||||
|
||||
private:
|
||||
LLRect mInnerRect;
|
||||
LLScrollbar* mScrollbar;
|
||||
bool mSingleExpansion;
|
||||
bool mFitParent;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_LLSPLITTER_H
|
||||
|
|
@ -0,0 +1,599 @@
|
|||
/**
|
||||
* @file LLAccordionCtrlTab.cpp
|
||||
* @brief Collapsible control implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2009, Linden Research, Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lluictrl.h"
|
||||
|
||||
#include "llaccordionctrltab.h"
|
||||
|
||||
#include "lltextbox.h"
|
||||
|
||||
static const std::string DD_BUTTON_NAME = "dd_button";
|
||||
static const std::string DD_TEXTBOX_NAME = "dd_textbox";
|
||||
static const std::string DD_HEADER_NAME = "dd_header";
|
||||
|
||||
static const S32 HEADER_HEIGHT = 20;
|
||||
static const S32 HEADER_IMAGE_LEFT_OFFSET = 5;
|
||||
static const S32 HEADER_TEXT_LEFT_OFFSET = 30;
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLAccordionCtrlTab> t1("accordion_tab");
|
||||
|
||||
class LLAccordionCtrlTab::LLAccordionCtrlTabHeader : public LLUICtrl
|
||||
{
|
||||
public:
|
||||
friend class LLUICtrlFactory;
|
||||
|
||||
struct Params : public LLInitParam::Block<Params, LLAccordionCtrlTab::Params>
|
||||
{
|
||||
Params();
|
||||
};
|
||||
|
||||
LLAccordionCtrlTabHeader(const LLAccordionCtrlTabHeader::Params& p);
|
||||
|
||||
virtual ~LLAccordionCtrlTabHeader();
|
||||
|
||||
virtual void draw();
|
||||
|
||||
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
|
||||
|
||||
virtual BOOL postBuild();
|
||||
|
||||
void setTitle(const std::string& title);
|
||||
|
||||
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);
|
||||
private:
|
||||
|
||||
LLTextBox* mHeaderTextbox;
|
||||
|
||||
// Overlay images (arrows)
|
||||
LLPointer<LLUIImage> mImageCollapsed;
|
||||
LLPointer<LLUIImage> mImageExpanded;
|
||||
LLPointer<LLUIImage> mImageCollapsedPressed;
|
||||
LLPointer<LLUIImage> mImageExpandedPressed;
|
||||
|
||||
// Background images
|
||||
LLPointer<LLUIImage> mImageHeader;
|
||||
LLPointer<LLUIImage> mImageHeaderOver;
|
||||
LLPointer<LLUIImage> mImageHeaderPressed;
|
||||
LLPointer<LLUIImage> mImageHeaderFocused;
|
||||
|
||||
LLUIColor mHeaderBGColor;
|
||||
|
||||
bool mNeedsHighlight;
|
||||
};
|
||||
|
||||
LLAccordionCtrlTab::LLAccordionCtrlTabHeader::Params::Params()
|
||||
{
|
||||
}
|
||||
|
||||
LLAccordionCtrlTab::LLAccordionCtrlTabHeader::LLAccordionCtrlTabHeader(
|
||||
const LLAccordionCtrlTabHeader::Params& p)
|
||||
: LLUICtrl(p)
|
||||
, mHeaderBGColor(p.header_bg_color())
|
||||
,mNeedsHighlight(false),
|
||||
mImageCollapsed(p.header_collapse_img),
|
||||
mImageCollapsedPressed(p.header_collapse_img_pressed),
|
||||
mImageExpanded(p.header_expand_img),
|
||||
mImageExpandedPressed(p.header_expand_img_pressed),
|
||||
mImageHeader(p.header_image),
|
||||
mImageHeaderOver(p.header_image_over),
|
||||
mImageHeaderPressed(p.header_image_pressed),
|
||||
mImageHeaderFocused(p.header_image_focused)
|
||||
{
|
||||
LLTextBox::Params textboxParams;
|
||||
textboxParams.name(DD_TEXTBOX_NAME);
|
||||
textboxParams.initial_value(p.title());
|
||||
textboxParams.text_color(p.header_text_color());
|
||||
textboxParams.follows.flags(FOLLOWS_NONE);
|
||||
textboxParams.font( p.font() );
|
||||
textboxParams.font_shadow(LLFontGL::NO_SHADOW);
|
||||
textboxParams.use_ellipses = true;
|
||||
textboxParams.bg_visible = false;
|
||||
textboxParams.mouse_opaque = false;
|
||||
mHeaderTextbox = LLUICtrlFactory::create<LLTextBox>(textboxParams);
|
||||
addChild(mHeaderTextbox);
|
||||
}
|
||||
|
||||
LLAccordionCtrlTab::LLAccordionCtrlTabHeader::~LLAccordionCtrlTabHeader()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::postBuild()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title)
|
||||
{
|
||||
if(mHeaderTextbox)
|
||||
mHeaderTextbox->setText(title);
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
|
||||
{
|
||||
S32 width = getRect().getWidth();
|
||||
S32 height = getRect().getHeight();
|
||||
|
||||
gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get(),true);
|
||||
|
||||
LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent());
|
||||
bool collapsible = (parent && parent->getCollapsible());
|
||||
bool expanded = (parent && parent->getDisplayChildren());
|
||||
|
||||
// Handle overlay images, if needed
|
||||
// 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()
|
||||
&& !(collapsible && !expanded))
|
||||
{
|
||||
mImageHeaderFocused->draw(0,0,width,height);
|
||||
}
|
||||
else
|
||||
{
|
||||
mImageHeader->draw(0,0,width,height);
|
||||
}
|
||||
|
||||
if(mNeedsHighlight)
|
||||
{
|
||||
mImageHeaderOver->draw(0,0,width,height);
|
||||
}
|
||||
|
||||
|
||||
if(collapsible)
|
||||
{
|
||||
LLPointer<LLUIImage> overlay_image;
|
||||
if(expanded)
|
||||
{
|
||||
overlay_image = mImageExpanded;
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay_image = mImageCollapsed;
|
||||
}
|
||||
overlay_image->draw(HEADER_IMAGE_LEFT_OFFSET,
|
||||
(height - overlay_image->getHeight()) / 2);
|
||||
}
|
||||
|
||||
LLUICtrl::draw();
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */)
|
||||
{
|
||||
S32 header_height = mHeaderTextbox->getTextPixelHeight();
|
||||
|
||||
LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET,(height+header_height)/2 ,width,(height-header_height)/2);
|
||||
mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight());
|
||||
mHeaderTextbox->setRect(textboxRect);
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseEnter(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLUICtrl::onMouseEnter(x, y, mask);
|
||||
mNeedsHighlight = true;
|
||||
}
|
||||
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseLeave(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLUICtrl::onMouseLeave(x, y, mask);
|
||||
mNeedsHighlight = false;
|
||||
}
|
||||
BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
||||
{
|
||||
if ( ( key == KEY_LEFT || key == KEY_RIGHT) && mask == MASK_NONE)
|
||||
{
|
||||
return getParent()->handleKey(key, mask, called_from_parent);
|
||||
}
|
||||
return LLUICtrl::handleKey(key, mask, called_from_parent);
|
||||
}
|
||||
|
||||
|
||||
LLAccordionCtrlTab::Params::Params()
|
||||
: title("title")
|
||||
,display_children("expanded", true)
|
||||
,header_height("header_height", HEADER_HEIGHT),
|
||||
min_width("min_width", 0),
|
||||
min_height("min_height", 0)
|
||||
,collapsible("collapsible", true)
|
||||
,header_bg_color("header_bg_color")
|
||||
,dropdown_bg_color("dropdown_bg_color")
|
||||
,header_visible("header_visible",true)
|
||||
,padding_left("padding_left",2)
|
||||
,padding_right("padding_right",2)
|
||||
,padding_top("padding_top",2)
|
||||
,padding_bottom("padding_bottom",2)
|
||||
,header_expand_img("header_expand_img")
|
||||
,header_expand_img_pressed("header_expand_img_pressed")
|
||||
,header_collapse_img("header_collapse_img")
|
||||
,header_collapse_img_pressed("header_collapse_img_pressed")
|
||||
,header_image("header_image")
|
||||
,header_image_over("header_image_over")
|
||||
,header_image_pressed("header_image_pressed")
|
||||
,header_image_focused("header_image_focused")
|
||||
,header_text_color("header_text_color")
|
||||
{
|
||||
mouse_opaque(false);
|
||||
}
|
||||
|
||||
LLAccordionCtrlTab::LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&p)
|
||||
: LLUICtrl(p)
|
||||
,mDisplayChildren(p.display_children)
|
||||
,mCollapsible(p.collapsible)
|
||||
,mExpandedHeight(0)
|
||||
,mDropdownBGColor(p.dropdown_bg_color())
|
||||
,mHeaderVisible(p.header_visible)
|
||||
,mPaddingLeft(p.padding_left)
|
||||
,mPaddingRight(p.padding_right)
|
||||
,mPaddingTop(p.padding_top)
|
||||
,mPaddingBottom(p.padding_bottom)
|
||||
,mCanOpenClose(true)
|
||||
{
|
||||
mStoredOpenCloseState = false;
|
||||
mWasStateStored = false;
|
||||
|
||||
mDropdownBGColor = LLColor4::white;
|
||||
LLAccordionCtrlTabHeader::Params headerParams;
|
||||
headerParams.name(DD_HEADER_NAME);
|
||||
headerParams.title(p.title);
|
||||
mHeader = LLUICtrlFactory::create<LLAccordionCtrlTabHeader>(headerParams);
|
||||
addChild(mHeader, 1);
|
||||
|
||||
reshape(100, 200,FALSE);
|
||||
}
|
||||
|
||||
LLAccordionCtrlTab::~LLAccordionCtrlTab()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void LLAccordionCtrlTab::setDisplayChildren(bool display)
|
||||
{
|
||||
mDisplayChildren = display;
|
||||
LLRect rect = getRect();
|
||||
|
||||
rect.mBottom = rect.mTop - (getDisplayChildren() ?
|
||||
mExpandedHeight : HEADER_HEIGHT);
|
||||
setRect(rect);
|
||||
|
||||
for(child_list_const_iter_t it = getChildList()->begin();
|
||||
getChildList()->end() != it; ++it)
|
||||
{
|
||||
LLView* child = *it;
|
||||
if(DD_HEADER_NAME == child->getName())
|
||||
continue;
|
||||
|
||||
child->setVisible(getDisplayChildren());
|
||||
}
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */)
|
||||
{
|
||||
LLRect headerRect;
|
||||
|
||||
LLUICtrl::reshape(width, height, TRUE);
|
||||
|
||||
headerRect.setLeftTopAndSize(
|
||||
0,height,width,HEADER_HEIGHT);
|
||||
mHeader->setRect(headerRect);
|
||||
mHeader->reshape(headerRect.getWidth(), headerRect.getHeight());
|
||||
|
||||
for(child_list_const_iter_t it = getChildList()->begin();
|
||||
getChildList()->end() != it; ++it)
|
||||
{
|
||||
LLView* child = *it;
|
||||
if(DD_HEADER_NAME == child->getName())
|
||||
continue;
|
||||
if(!child->getVisible())
|
||||
continue;
|
||||
|
||||
LLRect childRect = child->getRect();
|
||||
S32 childWidth = width - getPaddingLeft() - getPaddingRight();
|
||||
S32 childHeight = height - getHeaderHeight() - getPaddingTop() - getPaddingBottom();
|
||||
|
||||
child->reshape(childWidth,childHeight);
|
||||
|
||||
childRect.setLeftTopAndSize(
|
||||
getPaddingLeft(),
|
||||
childHeight + getPaddingBottom(),
|
||||
childWidth,
|
||||
childHeight);
|
||||
|
||||
child->setRect(childRect);
|
||||
|
||||
break;//suppose that there is only one panel
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::changeOpenClose(bool is_open)
|
||||
{
|
||||
if(is_open)
|
||||
mExpandedHeight = getRect().getHeight();
|
||||
|
||||
setDisplayChildren(!is_open);
|
||||
reshape(getRect().getWidth(), getRect().getHeight(), FALSE);
|
||||
if (mCommitSignal)
|
||||
{
|
||||
(*mCommitSignal)(this, getDisplayChildren());
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if(mCollapsible && mHeaderVisible && mCanOpenClose)
|
||||
{
|
||||
if(y >= (getRect().getHeight() - HEADER_HEIGHT) )
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
header->setFocus(true);
|
||||
changeOpenClose(getDisplayChildren());
|
||||
|
||||
//reset stored state
|
||||
mWasStateStored = false;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return LLUICtrl::handleMouseDown(x,y,mask);
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrlTab::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
return LLUICtrl::handleMouseUp(x,y,mask);
|
||||
}
|
||||
|
||||
boost::signals2::connection LLAccordionCtrlTab::setDropDownStateChangedCallback(commit_callback_t cb)
|
||||
{
|
||||
return setCommitCallback(cb);
|
||||
}
|
||||
|
||||
bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group)
|
||||
{
|
||||
if(DD_HEADER_NAME != child->getName())
|
||||
{
|
||||
reshape(child->getRect().getWidth() , child->getRect().getHeight() + HEADER_HEIGHT );
|
||||
mExpandedHeight = getRect().getHeight();
|
||||
}
|
||||
|
||||
bool res = LLUICtrl::addChild(child, tab_group);
|
||||
|
||||
if(DD_HEADER_NAME != child->getName())
|
||||
{
|
||||
if(!mCollapsible)
|
||||
setDisplayChildren(true);
|
||||
else
|
||||
setDisplayChildren(getDisplayChildren());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::setAccordionView(LLView* panel)
|
||||
{
|
||||
addChild(panel,0);
|
||||
}
|
||||
|
||||
|
||||
LLView* LLAccordionCtrlTab::getAccordionView()
|
||||
{
|
||||
for(child_list_const_iter_t it = getChildList()->begin();
|
||||
getChildList()->end() != it; ++it)
|
||||
{
|
||||
LLView* child = *it;
|
||||
if(DD_HEADER_NAME == child->getName())
|
||||
continue;
|
||||
if(!child->getVisible())
|
||||
continue;
|
||||
return child;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
S32 LLAccordionCtrlTab::getHeaderHeight()
|
||||
{
|
||||
return mHeaderVisible?HEADER_HEIGHT:0;
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::setHeaderVisible(bool value)
|
||||
{
|
||||
if(mHeaderVisible == value)
|
||||
return;
|
||||
mHeaderVisible = value;
|
||||
if(mHeader)
|
||||
mHeader->setVisible(value);
|
||||
reshape(getRect().getWidth(), getRect().getHeight(), FALSE);
|
||||
};
|
||||
|
||||
//vurtual
|
||||
BOOL LLAccordionCtrlTab::postBuild()
|
||||
{
|
||||
mHeader->setVisible(mHeaderVisible);
|
||||
return LLUICtrl::postBuild();
|
||||
}
|
||||
bool LLAccordionCtrlTab::notifyChildren (const LLSD& info)
|
||||
{
|
||||
if(info.has("action"))
|
||||
{
|
||||
std::string str_action = info["action"];
|
||||
if(str_action == "store_state")
|
||||
{
|
||||
storeOpenCloseState();
|
||||
return true;
|
||||
}
|
||||
if(str_action == "restore_state")
|
||||
{
|
||||
restoreOpenCloseState();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return LLUICtrl::notifyChildren(info);
|
||||
}
|
||||
|
||||
S32 LLAccordionCtrlTab::notifyParent(const LLSD& info)
|
||||
{
|
||||
if(info.has("action"))
|
||||
{
|
||||
std::string str_action = info["action"];
|
||||
if(str_action == "size_changes")
|
||||
{
|
||||
//
|
||||
S32 height = info["height"];
|
||||
height = llmax(height,10) + HEADER_HEIGHT + getPaddingTop() + getPaddingBottom();
|
||||
|
||||
mExpandedHeight = height;
|
||||
|
||||
if(isExpanded())
|
||||
{
|
||||
LLRect panel_rect = getRect();
|
||||
panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), height);
|
||||
reshape(getRect().getWidth(),height);
|
||||
setRect(panel_rect);
|
||||
}
|
||||
|
||||
//LLAccordionCtrl should rearrange accodion tab if one of accordion change its size
|
||||
getParent()->notifyParent(info);
|
||||
return 1;
|
||||
}
|
||||
else if(str_action == "select_prev")
|
||||
{
|
||||
showAndFocusHeader();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return LLUICtrl::notifyParent(info);
|
||||
}
|
||||
|
||||
S32 LLAccordionCtrlTab::notify(const LLSD& info)
|
||||
{
|
||||
if(info.has("action"))
|
||||
{
|
||||
std::string str_action = info["action"];
|
||||
if(str_action == "select_first")
|
||||
{
|
||||
showAndFocusHeader();
|
||||
return 1;
|
||||
}
|
||||
else if( str_action == "select_last" )
|
||||
{
|
||||
if(getDisplayChildren() == false)
|
||||
{
|
||||
showAndFocusHeader();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLView* view = getAccordionView();
|
||||
if(view)
|
||||
view->notify(LLSD().with("action","select_last"));
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
if( !header->hasFocus() )
|
||||
return LLUICtrl::handleKey(key, mask, called_from_parent);
|
||||
|
||||
if ( (key == KEY_ADD || key == KEY_RIGHT)&& mask == MASK_NONE)
|
||||
{
|
||||
if(getDisplayChildren() == false)
|
||||
{
|
||||
changeOpenClose(getDisplayChildren());
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
if ( (key == KEY_SUBTRACT || key == KEY_LEFT)&& mask == MASK_NONE)
|
||||
{
|
||||
if(getDisplayChildren() == true)
|
||||
{
|
||||
changeOpenClose(getDisplayChildren());
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( key == KEY_DOWN && mask == MASK_NONE)
|
||||
{
|
||||
//if collapsed go to the next accordion
|
||||
if(getDisplayChildren() == false)
|
||||
//we processing notifyParent so let call parent directly
|
||||
getParent()->notifyParent(LLSD().with("action","select_next"));
|
||||
else
|
||||
{
|
||||
getAccordionView()->notify(LLSD().with("action","select_first"));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ( key == KEY_UP && mask == MASK_NONE)
|
||||
{
|
||||
//go to the previous accordion
|
||||
|
||||
//we processing notifyParent so let call parent directly
|
||||
getParent()->notifyParent(LLSD().with("action","select_prev"));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return LLUICtrl::handleKey(key, mask, called_from_parent);
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::showAndFocusHeader()
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
header->setFocus(true);
|
||||
|
||||
LLRect screen_rc;
|
||||
LLRect selected_rc = header->getRect();
|
||||
localRectToScreen(selected_rc, &screen_rc);
|
||||
notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));
|
||||
|
||||
}
|
||||
void LLAccordionCtrlTab::storeOpenCloseState()
|
||||
{
|
||||
if(mWasStateStored)
|
||||
return;
|
||||
mStoredOpenCloseState = getDisplayChildren();
|
||||
mWasStateStored = true;
|
||||
}
|
||||
void LLAccordionCtrlTab::restoreOpenCloseState()
|
||||
{
|
||||
if(!mWasStateStored)
|
||||
return;
|
||||
if(getDisplayChildren() != mStoredOpenCloseState)
|
||||
{
|
||||
changeOpenClose(getDisplayChildren());
|
||||
}
|
||||
mWasStateStored = false;
|
||||
}
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
/**
|
||||
* @file LLAccordionCtrlTab.h
|
||||
* @brief Collapsible box control implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2004-2009, Linden Research, Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_ACCORDIONCTRLTAB_H_
|
||||
#define LL_ACCORDIONCTRLTAB_H_
|
||||
|
||||
#include <string>
|
||||
#include "llrect.h"
|
||||
|
||||
class LLUICtrl;
|
||||
class LLUICtrlFactory;
|
||||
class LLUIImage;
|
||||
class LLButton;
|
||||
class LLTextBox;
|
||||
|
||||
|
||||
|
||||
// LLAccordionCtrlTab is a container for other controls.
|
||||
// It has a Header, by clicking on which hosted controls are shown or hidden.
|
||||
// When hosted controls are show - LLAccordionCtrlTab is expanded.
|
||||
// When hosted controls are hidden - LLAccordionCtrlTab is collapsed.
|
||||
|
||||
class LLAccordionCtrlTab : public LLUICtrl
|
||||
{
|
||||
// Interface
|
||||
public:
|
||||
|
||||
struct Params
|
||||
: public LLInitParam::Block<Params, LLUICtrl::Params>
|
||||
{
|
||||
Optional<bool> display_children, //expanded or collapsed after initialization
|
||||
collapsible;
|
||||
|
||||
Optional<std::string> title;
|
||||
|
||||
Optional<S32> header_height,
|
||||
min_width,
|
||||
min_height;
|
||||
|
||||
// Overlay images (arrows on the left)
|
||||
Mandatory<LLUIImage*> header_expand_img,
|
||||
header_expand_img_pressed,
|
||||
header_collapse_img,
|
||||
header_collapse_img_pressed;
|
||||
|
||||
// Background images for the accordion tabs
|
||||
Mandatory<LLUIImage*> header_image,
|
||||
header_image_over,
|
||||
header_image_pressed,
|
||||
header_image_focused;
|
||||
|
||||
Optional<LLUIColor> header_bg_color,
|
||||
header_text_color,
|
||||
dropdown_bg_color;
|
||||
|
||||
Optional<bool> header_visible;
|
||||
|
||||
Optional<S32> padding_left;
|
||||
Optional<S32> padding_right;
|
||||
Optional<S32> padding_top;
|
||||
Optional<S32> padding_bottom;
|
||||
|
||||
Params();
|
||||
};
|
||||
|
||||
typedef LLDefaultChildRegistry child_registry_t;
|
||||
|
||||
virtual ~LLAccordionCtrlTab();
|
||||
|
||||
// Registers callback for expand/collapse events.
|
||||
boost::signals2::connection setDropDownStateChangedCallback(commit_callback_t cb);
|
||||
|
||||
// Changes expand/collapse state
|
||||
virtual void setDisplayChildren(bool display);
|
||||
|
||||
// Returns expand/collapse state
|
||||
virtual bool getDisplayChildren() const {return mDisplayChildren;};
|
||||
|
||||
//set LLAccordionCtrlTab panel
|
||||
void setAccordionView(LLView* panel);
|
||||
LLView* getAccordionView();
|
||||
|
||||
bool getCollapsible() {return mCollapsible;};
|
||||
|
||||
void setCollapsible(bool collapsible) {mCollapsible = collapsible;};
|
||||
void changeOpenClose(bool is_open);
|
||||
|
||||
void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close;};
|
||||
|
||||
virtual BOOL postBuild();
|
||||
|
||||
S32 notifyParent(const LLSD& info);
|
||||
S32 notify(const LLSD& info);
|
||||
bool notifyChildren(const LLSD& info);
|
||||
|
||||
void storeOpenCloseState ();
|
||||
void restoreOpenCloseState ();
|
||||
|
||||
protected:
|
||||
LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&);
|
||||
friend class LLUICtrlFactory;
|
||||
|
||||
// Overrides
|
||||
public:
|
||||
|
||||
// Call reshape after changing size
|
||||
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
|
||||
|
||||
// Changes expand/collapse state and triggers expand/collapse callbacks
|
||||
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
|
||||
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
|
||||
|
||||
virtual bool addChild(LLView* child, S32 tab_group);
|
||||
|
||||
bool isExpanded() { return mDisplayChildren; }
|
||||
|
||||
S32 getHeaderHeight();
|
||||
|
||||
// Min size functions
|
||||
|
||||
void setHeaderVisible(bool value);
|
||||
|
||||
bool getHeaderVisible() { return mHeaderVisible;}
|
||||
|
||||
S32 mExpandedHeight; // Height of expanded ctrl.
|
||||
// Used to restore height after expand.
|
||||
|
||||
S32 getPaddingLeft() const { return mPaddingLeft;}
|
||||
S32 getPaddingRight() const { return mPaddingRight;}
|
||||
S32 getPaddingTop() const { return mPaddingTop;}
|
||||
S32 getPaddingBottom() const { return mPaddingBottom;}
|
||||
|
||||
void showAndFocusHeader();
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
class LLAccordionCtrlTabHeader;
|
||||
LLAccordionCtrlTabHeader* mHeader; //Header
|
||||
|
||||
bool mDisplayChildren; //Expanded/collapsed
|
||||
bool mCollapsible;
|
||||
bool mHeaderVisible;
|
||||
|
||||
bool mCanOpenClose;
|
||||
|
||||
S32 mPaddingLeft;
|
||||
S32 mPaddingRight;
|
||||
S32 mPaddingTop;
|
||||
S32 mPaddingBottom;
|
||||
|
||||
bool mStoredOpenCloseState;
|
||||
bool mWasStateStored;
|
||||
|
||||
|
||||
LLUIColor mDropdownBGColor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -63,8 +63,6 @@ include_directories(
|
|||
)
|
||||
|
||||
set(viewer_SOURCE_FILES
|
||||
llaccordionctrl.cpp
|
||||
llaccordionctrltab.cpp
|
||||
llagent.cpp
|
||||
llagentaccess.cpp
|
||||
llagentdata.cpp
|
||||
|
|
@ -569,8 +567,6 @@ endif (LINUX)
|
|||
set(viewer_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
ViewerInstall.cmake
|
||||
llaccordionctrl.h
|
||||
llaccordionctrltab.h
|
||||
llagent.h
|
||||
llagentaccess.h
|
||||
llagentdata.h
|
||||
|
|
|
|||
Loading…
Reference in New Issue