/** * @file llcontainerview.cpp * @brief Container for all statistics info * * $LicenseInfo:firstyear=2001&license=viewergpl$ * * Copyright (c) 2001-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 "llcontainerview.h" #include "llerror.h" #include "llfontgl.h" #include "llgl.h" #include "llui.h" #include "llstring.h" #include "llscrollcontainer.h" #include "lluictrlfactory.h" static LLDefaultChildRegistry::Register r1("container_view"); #include "llpanel.h" #include "llstatview.h" static ContainerViewRegistry::Register r2("stat_view"); static ContainerViewRegistry::Register r3("panel", &LLPanel::fromXML); LLContainerView::LLContainerView(const LLContainerView::Params& p) : LLView(p), mShowLabel(p.show_label), mLabel(p.label), mDisplayChildren(p.display_children) { mCollapsible = TRUE; mScrollContainer = NULL; } LLContainerView::~LLContainerView() { // Children all cleaned up by default view destructor. } BOOL LLContainerView::postBuild() { setDisplayChildren(mDisplayChildren); reshape(getRect().getWidth(), getRect().getHeight(), FALSE); return TRUE; } bool LLContainerView::addChild(LLView* child, S32 tab_group) { bool res = LLView::addChild(child, tab_group); if (res) { sendChildToBack(child); } return res; } BOOL LLContainerView::handleMouseDown(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; if (mDisplayChildren) { handled = (LLView::childrenHandleMouseDown(x, y, mask) != NULL); } if (!handled) { if( mCollapsible && mShowLabel && (y >= getRect().getHeight() - 10) ) { setDisplayChildren(!mDisplayChildren); reshape(getRect().getWidth(), getRect().getHeight(), FALSE); handled = TRUE; } } return handled; } BOOL LLContainerView::handleMouseUp(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; if (mDisplayChildren) { handled = (LLView::childrenHandleMouseUp(x, y, mask) != NULL); } return handled; } void LLContainerView::draw() { { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f)); } // Draw the label if (mShowLabel) { LLFontGL::getFontMonospace()->renderUTF8( mLabel, 0, 2, getRect().getHeight() - 2, LLColor4(1,1,1,1), LLFontGL::LEFT, LLFontGL::TOP); } LLView::draw(); } void LLContainerView::reshape(S32 width, S32 height, BOOL called_from_parent) { LLRect scroller_rect; scroller_rect.setOriginAndSize(0, 0, width, height); if (mScrollContainer) { scroller_rect = mScrollContainer->getContentWindowRect(); } else { // if we're uncontained - make height as small as possible scroller_rect.mTop = 0; } arrange(scroller_rect.getWidth(), scroller_rect.getHeight(), called_from_parent); // sometimes, after layout, our container will change size (scrollbars popping in and out) // if so, attempt another layout if (mScrollContainer) { LLRect new_container_rect = mScrollContainer->getContentWindowRect(); if ((new_container_rect.getWidth() != scroller_rect.getWidth()) || (new_container_rect.getHeight() != scroller_rect.getHeight())) // the container size has changed, attempt to arrange again { arrange(new_container_rect.getWidth(), new_container_rect.getHeight(), called_from_parent); } } } void LLContainerView::arrange(S32 width, S32 height, BOOL called_from_parent) { // Determine the sizes and locations of all contained views S32 total_height = 0; S32 top, left, right, bottom; //LLView *childp; // These will be used for the children left = 4; top = getRect().getHeight() - 4; right = width - 2; bottom = top; // Leave some space for the top label/grab handle if (mShowLabel) { total_height += 20; } if (mDisplayChildren) { // Determine total height U32 child_height = 0; for (child_list_const_iter_t child_iter = getChildList()->begin(); child_iter != getChildList()->end(); ++child_iter) { LLView *childp = *child_iter; if (!childp->getVisible()) { llwarns << "Incorrect visibility!" << llendl; } LLRect child_rect = childp->getRequiredRect(); child_height += child_rect.getHeight(); child_height += 2; } total_height += child_height; } if (total_height < height) total_height = height; if (followsTop()) { // HACK: casting away const. Should use setRect or some helper function instead. const_cast(getRect()).mBottom = getRect().mTop - total_height; } else { // HACK: casting away const. Should use setRect or some helper function instead. const_cast(getRect()).mTop = getRect().mBottom + total_height; } // HACK: casting away const. Should use setRect or some helper function instead. const_cast(getRect()).mRight = getRect().mLeft + width; top = total_height; if (mShowLabel) { top -= 20; } bottom = top; if (mDisplayChildren) { // Iterate through all children, and put in container from top down. for (child_list_const_iter_t child_iter = getChildList()->begin(); child_iter != getChildList()->end(); ++child_iter) { LLView *childp = *child_iter; LLRect child_rect = childp->getRequiredRect(); bottom -= child_rect.getHeight(); LLRect r(left, bottom + child_rect.getHeight(), right, bottom); childp->setRect(r); childp->reshape(right - left, top - bottom); top = bottom - 2; bottom = top; } } if (!called_from_parent) { if (getParent()) { getParent()->reshape(getParent()->getRect().getWidth(), getParent()->getRect().getHeight(), FALSE); } } } LLRect LLContainerView::getRequiredRect() { LLRect req_rect; //LLView *childp; U32 total_height = 0; // Determine the sizes and locations of all contained views // Leave some space for the top label/grab handle if (mShowLabel) { total_height = 20; } if (mDisplayChildren) { // Determine total height U32 child_height = 0; for (child_list_const_iter_t child_iter = getChildList()->begin(); child_iter != getChildList()->end(); ++child_iter) { LLView *childp = *child_iter; LLRect child_rect = childp->getRequiredRect(); child_height += child_rect.getHeight(); child_height += 2; } total_height += child_height; } req_rect.mTop = total_height; return req_rect; } void LLContainerView::setLabel(const std::string& label) { mLabel = label; } void LLContainerView::setDisplayChildren(const BOOL displayChildren) { mDisplayChildren = displayChildren; for (child_list_const_iter_t child_iter = getChildList()->begin(); child_iter != getChildList()->end(); ++child_iter) { LLView *childp = *child_iter; childp->setVisible(mDisplayChildren); } }