PageRenderTime 73ms CodeModel.GetById 2ms app.highlight 64ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/llaccordionctrltab.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1068 lines | 852 code | 155 blank | 61 comment | 147 complexity | 79c6105c942f28a4128288f8f3ce26e4 MD5 | raw file
   1/** 
   2 * @file LLAccordionCtrlTab.cpp
   3 * @brief Collapsible control implementation
   4 *
   5 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "linden_common.h"
  28
  29#include "llaccordionctrltab.h"
  30#include "llaccordionctrl.h"
  31
  32#include "lllocalcliprect.h"
  33#include "llscrollbar.h"
  34#include "lltextbox.h"
  35#include "lltextutil.h"
  36#include "lluictrl.h"
  37
  38static const std::string DD_BUTTON_NAME = "dd_button";
  39static const std::string DD_TEXTBOX_NAME = "dd_textbox";
  40static const std::string DD_HEADER_NAME = "dd_header";
  41
  42static const S32 HEADER_HEIGHT = 23;
  43static const S32 HEADER_IMAGE_LEFT_OFFSET = 5;
  44static const S32 HEADER_TEXT_LEFT_OFFSET = 30;
  45static const F32 AUTO_OPEN_TIME = 1.f;
  46static const S32 VERTICAL_MULTIPLE = 16;
  47static const S32 PARENT_BORDER_MARGIN = 5;
  48
  49static LLDefaultChildRegistry::Register<LLAccordionCtrlTab> t1("accordion_tab");
  50
  51class LLAccordionCtrlTab::LLAccordionCtrlTabHeader : public LLUICtrl
  52{
  53public:
  54	friend class LLUICtrlFactory;
  55
  56	struct Params : public LLInitParam::Block<Params, LLAccordionCtrlTab::Params>
  57	{
  58		Params();
  59	};
  60
  61	LLAccordionCtrlTabHeader(const LLAccordionCtrlTabHeader::Params& p);
  62	
  63	virtual ~LLAccordionCtrlTabHeader();
  64
  65	virtual void draw();
  66
  67	virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
  68
  69	virtual BOOL postBuild();
  70
  71	std::string getTitle();
  72	void	setTitle(const std::string& title, const std::string& hl);
  73
  74	void	setTitleFontStyle(std::string style);
  75
  76	void	setTitleColor(LLUIColor);
  77
  78	void	setSelected(bool is_selected) { mIsSelected = is_selected; }
  79
  80	virtual void onMouseEnter(S32 x, S32 y, MASK mask);
  81	virtual void onMouseLeave(S32 x, S32 y, MASK mask);
  82	virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
  83	virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
  84								   EDragAndDropType cargo_type,
  85								   void* cargo_data,
  86								   EAcceptance* accept,
  87								   std::string& tooltip_msg);
  88private:
  89
  90	LLTextBox* mHeaderTextbox;
  91
  92	// Overlay images (arrows)
  93	LLPointer<LLUIImage> mImageCollapsed;
  94	LLPointer<LLUIImage> mImageExpanded;
  95	LLPointer<LLUIImage> mImageCollapsedPressed;
  96	LLPointer<LLUIImage> mImageExpandedPressed;
  97
  98	// Background images
  99	LLPointer<LLUIImage> mImageHeader;
 100	LLPointer<LLUIImage> mImageHeaderOver;
 101	LLPointer<LLUIImage> mImageHeaderPressed;
 102	LLPointer<LLUIImage> mImageHeaderFocused;
 103
 104	// style saved when applying it in setTitleFontStyle
 105	LLStyle::Params			mStyleParams;
 106
 107	LLUIColor mHeaderBGColor;
 108
 109	bool mNeedsHighlight;
 110	bool mIsSelected;
 111
 112	LLFrameTimer mAutoOpenTimer;
 113};
 114
 115LLAccordionCtrlTab::LLAccordionCtrlTabHeader::Params::Params()
 116{
 117}
 118
 119LLAccordionCtrlTab::LLAccordionCtrlTabHeader::LLAccordionCtrlTabHeader(
 120	const LLAccordionCtrlTabHeader::Params& p)
 121: LLUICtrl(p)
 122, mHeaderBGColor(p.header_bg_color())
 123, mNeedsHighlight(false)
 124, mIsSelected(false),
 125	mImageCollapsed(p.header_collapse_img),
 126	mImageCollapsedPressed(p.header_collapse_img_pressed),
 127	mImageExpanded(p.header_expand_img),
 128	mImageExpandedPressed(p.header_expand_img_pressed),
 129	mImageHeader(p.header_image),
 130	mImageHeaderOver(p.header_image_over),
 131	mImageHeaderPressed(p.header_image_pressed),
 132	mImageHeaderFocused(p.header_image_focused)
 133{
 134	LLTextBox::Params textboxParams;
 135	textboxParams.name(DD_TEXTBOX_NAME);
 136	textboxParams.initial_value(p.title());
 137	textboxParams.text_color(p.header_text_color());
 138	textboxParams.follows.flags(FOLLOWS_NONE);
 139	textboxParams.font( p.font() );
 140	textboxParams.font_shadow(LLFontGL::NO_SHADOW);
 141	textboxParams.use_ellipses = true;
 142	textboxParams.bg_visible = false;
 143	textboxParams.mouse_opaque = false;
 144	textboxParams.parse_urls = false;
 145	mHeaderTextbox = LLUICtrlFactory::create<LLTextBox>(textboxParams);
 146	addChild(mHeaderTextbox);
 147}
 148
 149LLAccordionCtrlTab::LLAccordionCtrlTabHeader::~LLAccordionCtrlTabHeader()
 150{
 151}
 152
 153BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::postBuild()
 154{
 155	return TRUE;
 156}
 157
 158std::string LLAccordionCtrlTab::LLAccordionCtrlTabHeader::getTitle()
 159{
 160	if(mHeaderTextbox)
 161	{
 162		return mHeaderTextbox->getText();
 163	}
 164	else
 165	{
 166		return LLStringUtil::null;
 167	}
 168}
 169
 170void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title, const std::string& hl)
 171{
 172	if(mHeaderTextbox)
 173	{
 174		LLTextUtil::textboxSetHighlightedVal(
 175			mHeaderTextbox,
 176			mStyleParams,
 177			title,
 178			hl);
 179	}
 180}
 181
 182void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleFontStyle(std::string style)
 183{
 184	if (mHeaderTextbox)
 185	{
 186		std::string text = mHeaderTextbox->getText();
 187		mStyleParams.font(mHeaderTextbox->getDefaultFont());
 188		mStyleParams.font.style(style);
 189		mHeaderTextbox->setText(text, mStyleParams);
 190	}
 191}
 192
 193void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleColor(LLUIColor color)
 194{
 195	if(mHeaderTextbox)
 196	{
 197		mHeaderTextbox->setColor(color);
 198	}
 199}
 200
 201void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
 202{
 203	S32 width = getRect().getWidth();
 204	S32 height = getRect().getHeight();
 205
 206	F32 alpha = getCurrentTransparency();
 207	gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get() % alpha,true);
 208
 209	LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent());
 210	bool collapsible = (parent && parent->getCollapsible());
 211	bool expanded = (parent && parent->getDisplayChildren());
 212
 213	// Handle overlay images, if needed
 214	// Only show green "focus" background image if the accordion is open,
 215	// because the user's mental model of focus is that it goes away after
 216	// the accordion is closed.
 217	if (getParent()->hasFocus() || mIsSelected
 218		/*&& !(collapsible && !expanded)*/ // WHY??
 219		)
 220	{
 221		mImageHeaderFocused->draw(0,0,width,height);
 222	}
 223	else
 224	{
 225		mImageHeader->draw(0,0,width,height);
 226	}
 227
 228	if(mNeedsHighlight)
 229	{
 230		mImageHeaderOver->draw(0,0,width,height);
 231	}
 232	
 233
 234	if(collapsible)
 235	{
 236		LLPointer<LLUIImage> overlay_image;
 237		if(expanded)
 238		{
 239			overlay_image = mImageExpanded;
 240		}
 241		else
 242		{
 243			overlay_image = mImageCollapsed;
 244		}
 245		overlay_image->draw(HEADER_IMAGE_LEFT_OFFSET,
 246							(height - overlay_image->getHeight()) / 2);
 247	}
 248	
 249	LLUICtrl::draw();
 250}
 251
 252void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */)
 253{
 254	S32 header_height = mHeaderTextbox->getTextPixelHeight();
 255
 256	LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET,(height+header_height)/2 ,width,(height-header_height)/2);
 257	mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight());
 258	mHeaderTextbox->setRect(textboxRect);
 259
 260	if (mHeaderTextbox->getTextPixelWidth() > mHeaderTextbox->getRect().getWidth())
 261	{
 262		setToolTip(mHeaderTextbox->getText());
 263	}
 264	else
 265	{
 266		setToolTip(LLStringUtil::null);
 267	}
 268}
 269
 270void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseEnter(S32 x, S32 y, MASK mask)
 271{
 272	LLUICtrl::onMouseEnter(x, y, mask);
 273	mNeedsHighlight = true;
 274}
 275void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseLeave(S32 x, S32 y, MASK mask)
 276{
 277	LLUICtrl::onMouseLeave(x, y, mask);
 278	mNeedsHighlight = false;
 279	mAutoOpenTimer.stop();
 280}
 281BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 282{
 283	if ( ( key == KEY_LEFT || key == KEY_RIGHT) && mask == MASK_NONE)
 284	{
 285		return getParent()->handleKey(key, mask, called_from_parent);
 286	}
 287	return LLUICtrl::handleKey(key, mask, called_from_parent);
 288}
 289BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleDragAndDrop(S32 x, S32 y, MASK mask,
 290																	 BOOL drop,
 291																	 EDragAndDropType cargo_type,
 292																	 void* cargo_data,
 293																	 EAcceptance* accept,
 294																	 std::string& tooltip_msg)
 295{
 296	LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent());
 297
 298	if ( parent && !parent->getDisplayChildren() && parent->getCollapsible() && parent->canOpenClose() )
 299	{
 300		if (mAutoOpenTimer.getStarted())
 301		{
 302			if (mAutoOpenTimer.getElapsedTimeF32() > AUTO_OPEN_TIME)
 303			{
 304				parent->changeOpenClose(false);
 305				mAutoOpenTimer.stop();
 306				return TRUE;
 307			}
 308		}
 309		else
 310			mAutoOpenTimer.start();
 311	}
 312
 313	return LLUICtrl::handleDragAndDrop(x, y, mask, drop, cargo_type,
 314									   cargo_data, accept, tooltip_msg);
 315}
 316LLAccordionCtrlTab::Params::Params()
 317	: title("title")
 318	,display_children("expanded", true)
 319	,header_height("header_height", HEADER_HEIGHT),
 320	min_width("min_width", 0),
 321	min_height("min_height", 0)
 322	,collapsible("collapsible", true)
 323	,header_bg_color("header_bg_color")
 324	,dropdown_bg_color("dropdown_bg_color")
 325	,header_visible("header_visible",true)
 326	,padding_left("padding_left",2)
 327	,padding_right("padding_right",2)
 328	,padding_top("padding_top",2)
 329	,padding_bottom("padding_bottom",2)
 330	,header_expand_img("header_expand_img")
 331	,header_expand_img_pressed("header_expand_img_pressed")
 332	,header_collapse_img("header_collapse_img")
 333	,header_collapse_img_pressed("header_collapse_img_pressed")
 334	,header_image("header_image")
 335	,header_image_over("header_image_over")
 336	,header_image_pressed("header_image_pressed")
 337	,header_image_focused("header_image_focused")
 338	,header_text_color("header_text_color")
 339	,fit_panel("fit_panel",true)
 340	,selection_enabled("selection_enabled", false)
 341{
 342	changeDefault(mouse_opaque, false);
 343}
 344
 345LLAccordionCtrlTab::LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&p)
 346	: LLUICtrl(p)
 347	,mDisplayChildren(p.display_children)
 348	,mCollapsible(p.collapsible)
 349	,mExpandedHeight(0)
 350	,mDropdownBGColor(p.dropdown_bg_color())
 351	,mHeaderVisible(p.header_visible)
 352	,mPaddingLeft(p.padding_left)
 353	,mPaddingRight(p.padding_right)
 354	,mPaddingTop(p.padding_top)
 355	,mPaddingBottom(p.padding_bottom)
 356	,mCanOpenClose(true)
 357	,mFitPanel(p.fit_panel)
 358	,mSelectionEnabled(p.selection_enabled)
 359	,mContainerPanel(NULL)
 360	,mScrollbar(NULL)
 361{
 362	mStoredOpenCloseState = false;
 363	mWasStateStored = false;
 364	
 365	mDropdownBGColor = LLColor4::white;
 366	LLAccordionCtrlTabHeader::Params headerParams;
 367	headerParams.name(DD_HEADER_NAME);
 368	headerParams.title(p.title);
 369	mHeader = LLUICtrlFactory::create<LLAccordionCtrlTabHeader>(headerParams);
 370	addChild(mHeader, 1);
 371
 372	LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLAccordionCtrlTab::selectOnFocusReceived, this));
 373
 374	if (!p.selection_enabled)
 375	{
 376		LLFocusableElement::setFocusLostCallback(boost::bind(&LLAccordionCtrlTab::deselectOnFocusLost, this));
 377	}
 378
 379	reshape(100, 200,FALSE);
 380}
 381
 382LLAccordionCtrlTab::~LLAccordionCtrlTab()
 383{
 384}
 385
 386
 387void LLAccordionCtrlTab::setDisplayChildren(bool display)
 388{
 389	mDisplayChildren = display;
 390	LLRect rect = getRect();
 391
 392	rect.mBottom = rect.mTop - (getDisplayChildren() ? 
 393		mExpandedHeight : HEADER_HEIGHT);
 394	setRect(rect);
 395
 396	if(mContainerPanel)
 397		mContainerPanel->setVisible(getDisplayChildren());
 398
 399	if(mDisplayChildren)
 400	{
 401		adjustContainerPanel();
 402	}
 403	else
 404	{
 405		if(mScrollbar)
 406			mScrollbar->setVisible(false);
 407	}
 408
 409}
 410
 411void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */)
 412{
 413	LLRect headerRect;
 414
 415	headerRect.setLeftTopAndSize(
 416		0,height,width,HEADER_HEIGHT);
 417	mHeader->setRect(headerRect);
 418	mHeader->reshape(headerRect.getWidth(), headerRect.getHeight());
 419
 420	if(!mDisplayChildren)
 421		return;
 422
 423	LLRect childRect;
 424
 425	childRect.setLeftTopAndSize(
 426		getPaddingLeft(),
 427		height - getHeaderHeight() - getPaddingTop(),
 428		width - getPaddingLeft() - getPaddingRight(), 
 429		height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() );
 430
 431	adjustContainerPanel(childRect);
 432}
 433
 434void LLAccordionCtrlTab::changeOpenClose(bool is_open)
 435{
 436	if(is_open)
 437		mExpandedHeight = getRect().getHeight();
 438
 439	setDisplayChildren(!is_open);
 440	reshape(getRect().getWidth(), getRect().getHeight(), FALSE);
 441	if (mCommitSignal)
 442	{
 443		(*mCommitSignal)(this, getDisplayChildren());
 444	}
 445}
 446
 447void LLAccordionCtrlTab::handleVisibilityChange(BOOL new_visibility)
 448{
 449	LLUICtrl::handleVisibilityChange(new_visibility);
 450
 451	notifyParent(LLSD().with("child_visibility_change", new_visibility));
 452}
 453
 454BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask)
 455{
 456	if(mCollapsible && mHeaderVisible && mCanOpenClose)
 457	{
 458		if(y >= (getRect().getHeight() - HEADER_HEIGHT) )
 459		{
 460			mHeader->setFocus(true);
 461			changeOpenClose(getDisplayChildren());
 462
 463			//reset stored state
 464			mWasStateStored = false;
 465			return TRUE;
 466		}
 467	}
 468	return LLUICtrl::handleMouseDown(x,y,mask);
 469}
 470
 471BOOL LLAccordionCtrlTab::handleMouseUp(S32 x, S32 y, MASK mask)
 472{
 473	return LLUICtrl::handleMouseUp(x,y,mask);
 474}
 475
 476boost::signals2::connection LLAccordionCtrlTab::setDropDownStateChangedCallback(commit_callback_t cb)
 477{
 478	return setCommitCallback(cb);
 479}
 480
 481bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group)
 482{
 483	if(DD_HEADER_NAME != child->getName())
 484	{
 485		reshape(child->getRect().getWidth() , child->getRect().getHeight() + HEADER_HEIGHT );
 486		mExpandedHeight = getRect().getHeight();
 487	}
 488
 489	bool res = LLUICtrl::addChild(child, tab_group);
 490
 491	if(DD_HEADER_NAME != child->getName())
 492	{
 493		if(!mCollapsible)
 494			setDisplayChildren(true);
 495		else
 496			setDisplayChildren(getDisplayChildren());	
 497	}
 498
 499	if (!mContainerPanel)
 500		mContainerPanel = findContainerView();
 501
 502	return res;
 503}
 504
 505void LLAccordionCtrlTab::setAccordionView(LLView* panel)
 506{
 507	addChild(panel,0);
 508}
 509
 510std::string LLAccordionCtrlTab::getTitle() const
 511{
 512	if (mHeader)
 513	{
 514		return mHeader->getTitle();
 515	}
 516	else
 517	{
 518		return LLStringUtil::null;
 519	}
 520}
 521
 522void LLAccordionCtrlTab::setTitle(const std::string& title, const std::string& hl)
 523{
 524	if (mHeader)
 525	{
 526		mHeader->setTitle(title, hl);
 527	}
 528}
 529
 530void LLAccordionCtrlTab::setTitleFontStyle(std::string style)
 531{
 532	if (mHeader)
 533	{
 534		mHeader->setTitleFontStyle(style);
 535	}
 536}
 537
 538void LLAccordionCtrlTab::setTitleColor(LLUIColor color)
 539{
 540	if (mHeader)
 541	{
 542		mHeader->setTitleColor(color);
 543	}
 544}
 545
 546boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const focus_signal_t::slot_type& cb)
 547{
 548	if (mHeader)
 549	{
 550		return mHeader->setFocusReceivedCallback(cb);
 551	}
 552	return boost::signals2::connection();
 553}
 554
 555boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus_signal_t::slot_type& cb)
 556{
 557	if (mHeader)
 558	{
 559		return mHeader->setFocusLostCallback(cb);
 560	}
 561	return boost::signals2::connection();
 562}
 563
 564void LLAccordionCtrlTab::setSelected(bool is_selected)
 565{
 566	if (mHeader)
 567	{
 568		mHeader->setSelected(is_selected);
 569	}
 570}
 571
 572LLView*	LLAccordionCtrlTab::findContainerView()
 573{
 574	for(child_list_const_iter_t it = getChildList()->begin(); 
 575		getChildList()->end() != it; ++it)
 576	{
 577		LLView* child = *it;
 578		if(DD_HEADER_NAME == child->getName())
 579			continue;
 580		if(!child->getVisible())
 581			continue;
 582		return child;
 583	}
 584	return NULL;
 585}
 586
 587void LLAccordionCtrlTab::selectOnFocusReceived()
 588{
 589	if (getParent()) // A parent may not be set if tabs are added dynamically.
 590		getParent()->notifyParent(LLSD().with("action", "select_current"));
 591}
 592
 593void LLAccordionCtrlTab::deselectOnFocusLost()
 594{
 595	if(getParent()) // A parent may not be set if tabs are added dynamically.
 596	{
 597		getParent()->notifyParent(LLSD().with("action", "deselect_current"));
 598	}
 599
 600}
 601
 602S32 LLAccordionCtrlTab::getHeaderHeight()
 603{
 604	return mHeaderVisible?HEADER_HEIGHT:0; 
 605}
 606
 607void LLAccordionCtrlTab::setHeaderVisible(bool value) 
 608{
 609	if(mHeaderVisible == value)
 610		return;
 611	mHeaderVisible = value;
 612	if(mHeader)
 613		mHeader->setVisible(value);
 614	reshape(getRect().getWidth(), getRect().getHeight(), FALSE);
 615};
 616
 617//virtual
 618BOOL LLAccordionCtrlTab::postBuild()
 619{
 620	if(mHeader)
 621		mHeader->setVisible(mHeaderVisible);
 622	
 623	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
 624
 625	LLRect scroll_rect;
 626	scroll_rect.setOriginAndSize( 
 627		getRect().getWidth() - scrollbar_size,
 628		1,
 629		scrollbar_size,
 630		getRect().getHeight() - 1);
 631
 632	mContainerPanel = findContainerView();
 633
 634	if(!mFitPanel)
 635	{
 636		LLScrollbar::Params sbparams;
 637		sbparams.name("scrollable vertical");
 638		sbparams.rect(scroll_rect);
 639		sbparams.orientation(LLScrollbar::VERTICAL);
 640		sbparams.doc_size(getRect().getHeight());
 641		sbparams.doc_pos(0);
 642		sbparams.page_size(getRect().getHeight());
 643		sbparams.step_size(VERTICAL_MULTIPLE);
 644		sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
 645		sbparams.change_callback(boost::bind(&LLAccordionCtrlTab::onScrollPosChangeCallback, this, _1, _2));
 646
 647
 648		mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams);
 649		LLView::addChild( mScrollbar );
 650		mScrollbar->setFollowsRight();
 651		mScrollbar->setFollowsTop();
 652		mScrollbar->setFollowsBottom();
 653
 654		mScrollbar->setVisible(false);
 655	}
 656
 657	if(mContainerPanel)
 658		mContainerPanel->setVisible(mDisplayChildren);
 659
 660	return LLUICtrl::postBuild();
 661}
 662bool	LLAccordionCtrlTab::notifyChildren	(const LLSD& info)
 663{
 664	if(info.has("action"))
 665	{
 666		std::string str_action = info["action"];
 667		if(str_action == "store_state")
 668		{
 669			storeOpenCloseState();
 670			return true;
 671		}
 672		if(str_action == "restore_state")
 673		{
 674			restoreOpenCloseState();
 675			return true;
 676		}
 677	}	
 678	return LLUICtrl::notifyChildren(info);
 679}
 680
 681S32	LLAccordionCtrlTab::notifyParent(const LLSD& info)
 682{
 683	if(info.has("action"))
 684	{
 685		std::string str_action = info["action"];
 686		if(str_action == "size_changes")
 687		{
 688			//
 689			S32 height = info["height"];
 690			height = llmax(height,10) + HEADER_HEIGHT + getPaddingTop() + getPaddingBottom();
 691			
 692			mExpandedHeight = height;
 693			
 694			if(isExpanded())
 695			{
 696				LLRect panel_rect = getRect();
 697				panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), height);
 698				reshape(getRect().getWidth(),height);
 699				setRect(panel_rect);
 700			}
 701			
 702			//LLAccordionCtrl should rearrange accordion tab if one of accordion change its size
 703			if (getParent()) // A parent may not be set if tabs are added dynamically.
 704				getParent()->notifyParent(info);
 705			return 1;
 706		}
 707		else if(str_action == "select_prev") 
 708		{
 709			showAndFocusHeader();
 710			return 1;
 711		}
 712	}
 713	else if (info.has("scrollToShowRect"))
 714	{
 715		LLAccordionCtrl* parent = dynamic_cast<LLAccordionCtrl*>(getParent());
 716		if (parent && parent->getFitParent())
 717		{
 718			//	EXT-8285 ('No attachments worn' text appears at the bottom of blank 'Attachments' accordion)
 719			//	The problem was in passing message "scrollToShowRect" IN LLAccordionCtrlTab::notifyParent
 720			//	FROM child LLScrollContainer TO parent LLAccordionCtrl with "it_parent" set to true.
 721
 722			//	It is wrong notification for parent accordion which leads to recursive call of adjustContainerPanel
 723			//	As the result of recursive call of adjustContainerPanel we got LLAccordionCtrlTab
 724			//	that reshaped and re-sized with different rectangles.
 725
 726			//	LLAccordionCtrl has own scrollContainer and LLAccordionCtrlTab has own scrollContainer
 727			//	both should handle own scroll container's event.
 728			//	So, if parent accordion "fit_parent" accordion tab should handle its scroll container events itself.
 729
 730			return 1;
 731		}
 732
 733		if (!getDisplayChildren())
 734		{
 735			// Don't pass scrolling event further if our contents are invisible (STORM-298).
 736			return 1;
 737		}
 738	}
 739
 740	return LLUICtrl::notifyParent(info);
 741}
 742
 743S32 LLAccordionCtrlTab::notify(const LLSD& info)
 744{
 745	if(info.has("action"))
 746	{
 747		std::string str_action = info["action"];
 748		if(str_action == "select_first")
 749		{
 750			showAndFocusHeader();
 751			return 1;
 752		}
 753		else if( str_action == "select_last" )
 754		{
 755			if(getDisplayChildren() == false)
 756			{
 757				showAndFocusHeader();
 758			}
 759			else
 760			{
 761				LLView* view = getAccordionView();
 762				if(view)
 763					view->notify(LLSD().with("action","select_last"));
 764			}
 765		}
 766	}
 767	return 0;
 768}
 769
 770BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 771{
 772	if( !mHeader->hasFocus() )
 773		return LLUICtrl::handleKey(key, mask, called_from_parent);
 774
 775	if ( (key == KEY_RETURN )&& mask == MASK_NONE)
 776	{
 777		changeOpenClose(getDisplayChildren());
 778		return TRUE;
 779	}
 780
 781	if ( (key == KEY_ADD || key == KEY_RIGHT)&& mask == MASK_NONE)
 782	{
 783		if(getDisplayChildren() == false)
 784		{
 785			changeOpenClose(getDisplayChildren());
 786			return TRUE;
 787		}
 788	}
 789	if ( (key == KEY_SUBTRACT || key == KEY_LEFT)&& mask == MASK_NONE)
 790	{
 791		if(getDisplayChildren() == true)
 792		{
 793			changeOpenClose(getDisplayChildren());
 794			return TRUE;
 795		}
 796	}
 797
 798	if ( key == KEY_DOWN && mask == MASK_NONE)
 799	{
 800		//if collapsed go to the next accordion
 801		if(getDisplayChildren() == false)
 802			//we processing notifyParent so let call parent directly
 803			getParent()->notifyParent(LLSD().with("action","select_next"));
 804		else
 805		{
 806			getAccordionView()->notify(LLSD().with("action","select_first"));
 807		}
 808		return TRUE;
 809	}
 810
 811	if ( key == KEY_UP && mask == MASK_NONE)
 812	{
 813		//go to the previous accordion
 814
 815		//we processing notifyParent so let call parent directly
 816		getParent()->notifyParent(LLSD().with("action","select_prev"));
 817		return TRUE;
 818	}
 819
 820	return LLUICtrl::handleKey(key, mask, called_from_parent);
 821}
 822
 823void LLAccordionCtrlTab::showAndFocusHeader()
 824{
 825	mHeader->setFocus(true);
 826	mHeader->setSelected(mSelectionEnabled);
 827
 828	LLRect screen_rc;
 829	LLRect selected_rc = mHeader->getRect();
 830	localRectToScreen(selected_rc, &screen_rc);
 831
 832	// This call to notifyParent() is intended to deliver "scrollToShowRect" command
 833	// to the parent LLAccordionCtrl so by calling it from the direct parent of this
 834	// accordion tab (assuming that the parent is an LLAccordionCtrl) the calls chain
 835	// is shortened and messages from inside the collapsed tabs are avoided.
 836	// See STORM-536.
 837	getParent()->notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));
 838}
 839void    LLAccordionCtrlTab::storeOpenCloseState()
 840{
 841	if(mWasStateStored)
 842		return;
 843	mStoredOpenCloseState = getDisplayChildren();
 844	mWasStateStored = true;
 845}
 846
 847void   LLAccordionCtrlTab::restoreOpenCloseState()
 848{
 849	if(!mWasStateStored)
 850		return;
 851	if(getDisplayChildren() != mStoredOpenCloseState)
 852	{
 853		changeOpenClose(getDisplayChildren());
 854	}
 855	mWasStateStored = false;
 856}
 857
 858void LLAccordionCtrlTab::adjustContainerPanel	()
 859{
 860	S32 width = getRect().getWidth();
 861	S32 height = getRect().getHeight();
 862
 863	LLRect child_rect;
 864	child_rect.setLeftTopAndSize(
 865		getPaddingLeft(),
 866		height - getHeaderHeight() - getPaddingTop(),
 867		width - getPaddingLeft() - getPaddingRight(), 
 868		height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() );
 869
 870	adjustContainerPanel(child_rect);
 871}
 872
 873void LLAccordionCtrlTab::adjustContainerPanel(const LLRect& child_rect)
 874{
 875	if(!mContainerPanel)
 876		return; 
 877
 878	if(!mFitPanel)
 879	{
 880		show_hide_scrollbar(child_rect);
 881		updateLayout(child_rect);
 882	}
 883	else
 884	{
 885		mContainerPanel->reshape(child_rect.getWidth(),child_rect.getHeight());
 886		mContainerPanel->setRect(child_rect);
 887	}
 888}
 889
 890S32 LLAccordionCtrlTab::getChildViewHeight()
 891{
 892	if(!mContainerPanel)
 893		return 0;
 894	return mContainerPanel->getRect().getHeight();
 895}
 896
 897void LLAccordionCtrlTab::show_hide_scrollbar(const LLRect& child_rect)
 898{
 899	if(getChildViewHeight() > child_rect.getHeight() )
 900		showScrollbar(child_rect);
 901	else
 902		hideScrollbar(child_rect);
 903}
 904void LLAccordionCtrlTab::showScrollbar(const LLRect& child_rect)
 905{
 906	if(!mContainerPanel || !mScrollbar)
 907		return;
 908	bool was_visible = mScrollbar->getVisible();
 909	mScrollbar->setVisible(true);
 910	
 911	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
 912
 913	{
 914		ctrlSetLeftTopAndSize(mScrollbar,child_rect.getWidth()-scrollbar_size, 
 915			child_rect.getHeight()-PARENT_BORDER_MARGIN, 
 916			scrollbar_size, 
 917			child_rect.getHeight()-2*PARENT_BORDER_MARGIN);
 918	}
 919
 920	LLRect orig_rect = mContainerPanel->getRect();
 921
 922	mScrollbar->setPageSize(child_rect.getHeight());
 923	mScrollbar->setDocParams(orig_rect.getHeight(),mScrollbar->getDocPos());
 924	
 925	if(was_visible)
 926	{
 927		S32 scroll_pos = llmin(mScrollbar->getDocPos(), orig_rect.getHeight() - child_rect.getHeight() - 1);
 928		mScrollbar->setDocPos(scroll_pos);
 929	}
 930	else//shrink child panel
 931	{
 932		updateLayout(child_rect);
 933	}
 934	
 935}
 936
 937void	LLAccordionCtrlTab::hideScrollbar( const LLRect& child_rect )
 938{
 939	if(!mContainerPanel || !mScrollbar)
 940		return;
 941
 942	if(mScrollbar->getVisible() == false)
 943		return;
 944	mScrollbar->setVisible(false);
 945	mScrollbar->setDocPos(0);
 946
 947	//shrink child panel
 948	updateLayout(child_rect);
 949}
 950
 951void	LLAccordionCtrlTab::onScrollPosChangeCallback(S32, LLScrollbar*)
 952{
 953	LLRect child_rect;
 954
 955	S32 width = getRect().getWidth();
 956	S32 height = getRect().getHeight();
 957
 958	child_rect.setLeftTopAndSize(
 959		getPaddingLeft(),
 960		height - getHeaderHeight() - getPaddingTop(),
 961		width - getPaddingLeft() - getPaddingRight(), 
 962		height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() );
 963
 964	updateLayout(child_rect);
 965}
 966
 967void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child)
 968{
 969	if (child && child->getVisible() && child->getRect().isValid())
 970	{
 971		LLRect screen_rect;
 972		localRectToScreen(child->getRect(),&screen_rect);
 973		
 974		if ( root_rect.overlaps(screen_rect)  && LLUI::sDirtyRect.overlaps(screen_rect))
 975		{
 976			gGL.matrixMode(LLRender::MM_MODELVIEW);
 977			LLUI::pushMatrix();
 978			{
 979				LLUI::translate((F32)child->getRect().mLeft, (F32)child->getRect().mBottom, 0.f);
 980				child->draw();
 981
 982			}
 983			LLUI::popMatrix();
 984		}
 985	}
 986}
 987
 988void LLAccordionCtrlTab::draw()
 989{
 990	if(mFitPanel)
 991		LLUICtrl::draw();
 992	else
 993	{
 994		LLRect root_rect = getRootView()->getRect();
 995		drawChild(root_rect,mHeader);
 996		drawChild(root_rect,mScrollbar );
 997		{
 998			LLRect child_rect;
 999
1000			S32 width = getRect().getWidth();
1001			S32 height = getRect().getHeight();
1002
1003			child_rect.setLeftTopAndSize(
1004				getPaddingLeft(),
1005				height - getHeaderHeight() - getPaddingTop(),
1006				width - getPaddingLeft() - getPaddingRight(), 
1007				height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() );
1008
1009			LLLocalClipRect clip(child_rect);
1010			drawChild(root_rect,mContainerPanel);
1011		}
1012	}
1013}
1014
1015void	LLAccordionCtrlTab::updateLayout	( const LLRect& child_rect )
1016{
1017	LLView*	child = getAccordionView();
1018	if(!mContainerPanel)
1019		return;
1020
1021	S32 panel_top = child_rect.getHeight();
1022	S32 panel_width = child_rect.getWidth();
1023
1024	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
1025	if(mScrollbar && mScrollbar->getVisible() != false)
1026	{
1027		panel_top+=mScrollbar->getDocPos();
1028		panel_width-=scrollbar_size;
1029	}
1030
1031	//set sizes for first panels and dragbars
1032	LLRect panel_rect = child->getRect();
1033	ctrlSetLeftTopAndSize(mContainerPanel,child_rect.mLeft,panel_top,panel_width,panel_rect.getHeight());
1034}
1035void LLAccordionCtrlTab::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height)
1036{
1037	if(!panel)
1038		return;
1039	LLRect panel_rect = panel->getRect();
1040	panel_rect.setLeftTopAndSize( left, top, width, height);
1041	panel->reshape( width, height, 1);
1042	panel->setRect(panel_rect);
1043}
1044BOOL LLAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask)
1045{
1046	//header may be not the first child but we need to process it first
1047	if(y >= (getRect().getHeight() - HEADER_HEIGHT - HEADER_HEIGHT/2) )
1048	{
1049		//inside tab header
1050		//fix for EXT-6619
1051		mHeader->handleToolTip(x, y, mask);
1052		return TRUE;
1053	}
1054	return LLUICtrl::handleToolTip(x, y, mask);
1055}
1056BOOL LLAccordionCtrlTab::handleScrollWheel		( S32 x, S32 y, S32 clicks )
1057{
1058	if( LLUICtrl::handleScrollWheel(x,y,clicks))
1059	{
1060		return TRUE;
1061	}
1062	if( mScrollbar && mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) )
1063	{
1064		return TRUE;
1065	}
1066	return FALSE;
1067}
1068