summaryrefslogtreecommitdiff
path: root/indra/llui/llscrolllistctrl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/llscrolllistctrl.cpp')
-rw-r--r--indra/llui/llscrolllistctrl.cpp2271
1 files changed, 720 insertions, 1551 deletions
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index c923f6b116..84e438cfb7 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -1,75 +1,77 @@
/**
* @file llscrolllistctrl.cpp
- * @brief LLScrollListCtrl base class
+ * @brief Scroll lists are composed of rows (items), each of which
+ * contains columns (cells).
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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 <algorithm>
-
#include "linden_common.h"
-#include "llstl.h"
-#include "llboost.h"
#include "llscrolllistctrl.h"
-#include "indra_constants.h"
+#include <algorithm>
+
+#include "llstl.h"
+#include "llboost.h"
+//#include "indra_constants.h"
#include "llcheckboxctrl.h"
#include "llclipboard.h"
#include "llfocusmgr.h"
-#include "llglimmediate.h"
+#include "llgl.h" // LLGLSUIDefault()
+#include "lllocalcliprect.h"
+//#include "llrender.h"
#include "llresmgr.h"
#include "llscrollbar.h"
+#include "llscrolllistcell.h"
#include "llstring.h"
#include "llui.h"
#include "lluictrlfactory.h"
#include "llwindow.h"
#include "llcontrol.h"
#include "llkeyboard.h"
-#include "llresizebar.h"
+#include "llviewborder.h"
+#include "lltextbox.h"
+#include "llsdparam.h"
+#include "llcachename.h"
+#include "llmenugl.h"
+#include "llurlaction.h"
+#include "lltooltip.h"
-const S32 MIN_COLUMN_WIDTH = 20;
-const S32 LIST_SNAP_PADDING = 5;
+#include <boost/bind.hpp>
-static LLRegisterWidget<LLScrollListCtrl> r("scroll_list");
+static LLDefaultChildRegistry::Register<LLScrollListCtrl> r("scroll_list");
// local structures & classes.
struct SortScrollListItem
{
- SortScrollListItem(const std::vector<std::pair<S32, BOOL> >& sort_orders)
+ SortScrollListItem(const std::vector<std::pair<S32, BOOL> >& sort_orders,const LLScrollListCtrl::sort_signal_t* sort_signal)
: mSortOrders(sort_orders)
+ , mSortSignal(sort_signal)
{}
bool operator()(const LLScrollListItem* i1, const LLScrollListItem* i2)
{
- if ( mSortOrders.empty() )
- return i1 < i2;
-
// sort over all columns in order specified by mSortOrders
S32 sort_result = 0;
for (sort_order_t::const_reverse_iterator it = mSortOrders.rbegin();
@@ -78,12 +80,20 @@ struct SortScrollListItem
S32 col_idx = it->first;
BOOL sort_ascending = it->second;
+ S32 order = sort_ascending ? 1 : -1; // ascending or descending sort for this column?
+
const LLScrollListCell *cell1 = i1->getColumn(col_idx);
const LLScrollListCell *cell2 = i2->getColumn(col_idx);
- S32 order = sort_ascending ? 1 : -1; // ascending or descending sort for this column?
if (cell1 && cell2)
{
- sort_result = order * LLString::compareDict(cell1->getValue().asString(), cell2->getValue().asString());
+ if(mSortSignal)
+ {
+ sort_result = order * (*mSortSignal)(col_idx,i1, i2);
+ }
+ else
+ {
+ sort_result = order * LLStringUtil::compareDict(cell1->getValue().asString(), cell2->getValue().asString());
+ }
if (sort_result != 0)
{
break; // we have a sort order!
@@ -93,498 +103,105 @@ struct SortScrollListItem
return sort_result < 0;
}
+
typedef std::vector<std::pair<S32, BOOL> > sort_order_t;
+ const LLScrollListCtrl::sort_signal_t* mSortSignal;
const sort_order_t& mSortOrders;
};
-
-//
-// LLScrollListIcon
-//
-LLScrollListIcon::LLScrollListIcon(LLUIImagePtr icon, S32 width)
- : LLScrollListCell(width),
- mIcon(icon),
- mColor(LLColor4::white)
-{
-}
-
-LLScrollListIcon::LLScrollListIcon(const LLSD& value, S32 width)
- : LLScrollListCell(width),
- mColor(LLColor4::white)
-{
- setValue(value);
-}
-
-
-LLScrollListIcon::~LLScrollListIcon()
-{
-}
-
-void LLScrollListIcon::setValue(const LLSD& value)
-{
- if (value.isUUID())
- {
- // don't use default image specified by LLUUID::null, use no image in that case
- LLUUID image_id = value.asUUID();
- mIcon = image_id.notNull() ? LLUI::sImageProvider->getUIImageByID(image_id) : LLUIImagePtr(NULL);
- }
- else
- {
- LLString value_string = value.asString();
- if (LLUUID::validate(value_string))
- {
- setValue(LLUUID(value_string));
- }
- else if (!value_string.empty())
- {
- mIcon = LLUI::getUIImage(value.asString());
- }
- else
- {
- mIcon = NULL;
- }
- }
-}
-
-
-void LLScrollListIcon::setColor(const LLColor4& color)
-{
- mColor = color;
-}
-
-S32 LLScrollListIcon::getWidth() const
-{
- // if no specified fix width, use width of icon
- if (LLScrollListCell::getWidth() == 0 && mIcon.notNull())
- {
- return mIcon->getWidth();
- }
- return LLScrollListCell::getWidth();
-}
-
-
-void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_color) const
-{
- if (mIcon)
- {
- mIcon->draw(0, 0, mColor);
- }
-}
-
-//
-// LLScrollListCheck
-//
-LLScrollListCheck::LLScrollListCheck(LLCheckBoxCtrl* check_box, S32 width)
-{
- mCheckBox = check_box;
- LLRect rect(mCheckBox->getRect());
- if (width)
- {
-
- rect.mRight = rect.mLeft + width;
- mCheckBox->setRect(rect);
- setWidth(width);
- }
- else
- {
- setWidth(rect.getWidth()); //check_box->getWidth();
- }
-}
-
-LLScrollListCheck::~LLScrollListCheck()
-{
- delete mCheckBox;
-}
-
-void LLScrollListCheck::draw(const LLColor4& color, const LLColor4& highlight_color) const
-{
- mCheckBox->draw();
-}
-
-BOOL LLScrollListCheck::handleClick()
-{
- if (mCheckBox->getEnabled())
- {
- mCheckBox->toggle();
- }
- // don't change selection when clicking on embedded checkbox
- return TRUE;
-}
-
-//
-// LLScrollListSeparator
-//
-LLScrollListSeparator::LLScrollListSeparator(S32 width) : LLScrollListCell(width)
-{
-}
-
-//virtual
-S32 LLScrollListSeparator::getHeight() const
-{
- return 5;
-}
-
-
-void LLScrollListSeparator::draw(const LLColor4& color, const LLColor4& highlight_color) const
-{
- //*FIXME: use dynamic item heights and make separators narrow, and inactive
- gl_line_2d(5, 8, llmax(5, getWidth() - 5), 8, color);
-}
-
-//
-// LLScrollListText
-//
-U32 LLScrollListText::sCount = 0;
-
-LLScrollListText::LLScrollListText( const LLString& text, const LLFontGL* font, S32 width, U8 font_style, LLFontGL::HAlign font_alignment, LLColor4& color, BOOL use_color, BOOL visible)
-: LLScrollListCell(width),
- mText( text ),
- mFont( font ),
- mColor(color),
- mUseColor(use_color),
- mFontStyle( font_style ),
- mFontAlignment( font_alignment ),
- mVisible( visible ),
- mHighlightCount( 0 ),
- mHighlightOffset( 0 )
-{
- sCount++;
-
- // initialize rounded rect image
- if (!mRoundedRectImage)
- {
- mRoundedRectImage = LLUI::sImageProvider->getUIImage("rounded_square.tga");
- }
-}
-//virtual
-void LLScrollListText::highlightText(S32 offset, S32 num_chars)
-{
- mHighlightOffset = offset;
- mHighlightCount = num_chars;
-}
-
-//virtual
-BOOL LLScrollListText::isText() const
-{
- return TRUE;
-}
-
-//virtual
-BOOL LLScrollListText::getVisible() const
-{
- return mVisible;
-}
-
-//virtual
-S32 LLScrollListText::getHeight() const
-{
- return llround(mFont->getLineHeight());
-}
-
-
-LLScrollListText::~LLScrollListText()
-{
- sCount--;
-}
-
-S32 LLScrollListText::getContentWidth() const
-{
- return mFont->getWidth(mText.getString());
-}
-
-
-void LLScrollListText::setColor(const LLColor4& color)
-{
- mColor = color;
- mUseColor = TRUE;
-}
-
-void LLScrollListText::setText(const LLStringExplicit& text)
-{
- mText = text;
-}
-
-//virtual
-void LLScrollListText::setValue(const LLSD& text)
-{
- setText(text.asString());
-}
-
-//virtual
-const LLSD LLScrollListText::getValue() const
-{
- return LLSD(mText.getString());
-}
-
-
-void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_color) const
-{
- LLColor4 display_color;
- if (mUseColor)
- {
- display_color = mColor;
- }
- else
- {
- display_color = color;
- }
-
- if (mHighlightCount > 0)
- {
- S32 left = 0;
- switch(mFontAlignment)
- {
- case LLFontGL::LEFT:
- left = mFont->getWidth(mText.getString(), 0, mHighlightOffset);
- break;
- case LLFontGL::RIGHT:
- left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX);
- break;
- case LLFontGL::HCENTER:
- left = (getWidth() - mFont->getWidth(mText.getString())) / 2;
- break;
- }
- LLRect highlight_rect(left - 2,
- llround(mFont->getLineHeight()) + 1,
- left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1,
- 1);
- mRoundedRectImage->draw(highlight_rect, highlight_color);
- }
-
- // Try to draw the entire string
- F32 right_x;
- U32 string_chars = mText.length();
- F32 start_x = 0.f;
- switch(mFontAlignment)
- {
- case LLFontGL::LEFT:
- start_x = 0.f;
- break;
- case LLFontGL::RIGHT:
- start_x = (F32)getWidth();
- break;
- case LLFontGL::HCENTER:
- start_x = (F32)getWidth() * 0.5f;
- break;
- }
- mFont->render(mText.getWString(), 0,
- start_x, 2.f,
- display_color,
- mFontAlignment,
- LLFontGL::BOTTOM,
- mFontStyle,
- string_chars,
- getWidth(),
- &right_x,
- FALSE,
- TRUE);
-}
-
-
-LLScrollListItem::~LLScrollListItem()
-{
- std::for_each(mColumns.begin(), mColumns.end(), DeletePointer());
-}
-
-void LLScrollListItem::setNumColumns(S32 columns)
-{
- S32 prev_columns = mColumns.size();
- if (columns < prev_columns)
- {
- std::for_each(mColumns.begin()+columns, mColumns.end(), DeletePointer());
- }
-
- mColumns.resize(columns);
-
- for (S32 col = prev_columns; col < columns; ++col)
- {
- mColumns[col] = NULL;
- }
-}
-
-void LLScrollListItem::setColumn( S32 column, LLScrollListCell *cell )
-{
- if (column < (S32)mColumns.size())
- {
- delete mColumns[column];
- mColumns[column] = cell;
- }
- else
- {
- llerrs << "LLScrollListItem::setColumn: bad column: " << column << llendl;
- }
-}
-
-LLString LLScrollListItem::getContentsCSV() const
-{
- LLString ret;
-
- S32 count = getNumColumns();
- for (S32 i=0; i<count; ++i)
- {
- ret += getColumn(i)->getValue().asString();
- if (i < count-1)
- {
- ret += ", ";
- }
- }
-
- return ret;
-}
-
-void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
-{
- // draw background rect
- LLRect bg_rect = rect;
- {
- LLGLSNoTexture no_texture;
- gGL.color4fv(bg_color.mV);
- gl_rect_2d( bg_rect );
- }
-
- S32 cur_x = rect.mLeft;
- S32 num_cols = getNumColumns();
- S32 cur_col = 0;
-
- for (LLScrollListCell* cell = getColumn(0); cur_col < num_cols; cell = getColumn(++cur_col))
- {
- // Two ways a cell could be hidden
- if (cell->getWidth() < 0
- || !cell->getVisible()) continue;
-
- LLUI::pushMatrix();
- {
- LLUI::translate((F32) cur_x, (F32) rect.mBottom, 0.0f);
-
- cell->draw( fg_color, highlight_color );
- }
- LLUI::popMatrix();
-
- cur_x += cell->getWidth() + column_padding;
- }
-}
-
-
-void LLScrollListItem::setEnabled(BOOL b)
-{
- mEnabled = b;
-}
-
-//---------------------------------------------------------------------------
-// LLScrollListItemComment
-//---------------------------------------------------------------------------
-LLScrollListItemComment::LLScrollListItemComment(const LLString& comment_string, const LLColor4& color)
-: LLScrollListItem(FALSE),
- mColor(color)
-{
- addColumn( comment_string, LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ) );
-}
-
-void LLScrollListItemComment::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
-{
- LLScrollListCell* cell = getColumn(0);
- if (cell)
- {
- // Two ways a cell could be hidden
- if (cell->getWidth() < 0
- || !cell->getVisible()) return;
-
- LLUI::pushMatrix();
- {
- LLUI::translate((F32)rect.mLeft, (F32)rect.mBottom, 0.0f);
-
- // force first cell to be width of entire item
- cell->setWidth(rect.getWidth());
- cell->draw( mColor, highlight_color );
- }
- LLUI::popMatrix();
- }
-}
-
-//---------------------------------------------------------------------------
-// LLScrollListItemSeparator
-//---------------------------------------------------------------------------
-LLScrollListItemSeparator::LLScrollListItemSeparator()
-: LLScrollListItem(FALSE)
-{
- LLScrollListSeparator* cell = new LLScrollListSeparator(0);
- setNumColumns(1);
- setColumn(0, cell);
-}
-
-void LLScrollListItemSeparator::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
-{
- //TODO* move LLScrollListSeparator::draw into here and get rid of it
- LLScrollListCell* cell = getColumn(0);
- if (cell)
- {
- // Two ways a cell could be hidden
- if (cell->getWidth() < 0
- || !cell->getVisible()) return;
-
- LLUI::pushMatrix();
- {
- LLUI::translate((F32)rect.mLeft, (F32)rect.mBottom, 0.0f);
-
- // force first cell to be width of entire item
- cell->setWidth(rect.getWidth());
- cell->draw( fg_color, highlight_color );
- }
- LLUI::popMatrix();
- }
-}
-
//---------------------------------------------------------------------------
// LLScrollListCtrl
//---------------------------------------------------------------------------
-LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
- void (*commit_callback)(LLUICtrl* ctrl, void* userdata),
- void* callback_user_data,
- BOOL allow_multiple_selection,
- BOOL show_border
- )
- : LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data),
+LLScrollListCtrl::Contents::Contents()
+: columns("column"),
+ rows("row")
+{
+ addSynonym(columns, "columns");
+ addSynonym(rows, "rows");
+}
+
+LLScrollListCtrl::Params::Params()
+: multi_select("multi_select", false),
+ has_border("draw_border"),
+ draw_heading("draw_heading"),
+ search_column("search_column", 0),
+ sort_column("sort_column", -1),
+ sort_ascending("sort_ascending", true),
+ mouse_wheel_opaque("mouse_wheel_opaque", false),
+ commit_on_keyboard_movement("commit_on_keyboard_movement", true),
+ heading_height("heading_height"),
+ page_lines("page_lines", 0),
+ background_visible("background_visible"),
+ draw_stripes("draw_stripes"),
+ column_padding("column_padding"),
+ fg_unselected_color("fg_unselected_color"),
+ fg_selected_color("fg_selected_color"),
+ bg_selected_color("bg_selected_color"),
+ fg_disable_color("fg_disable_color"),
+ bg_writeable_color("bg_writeable_color"),
+ bg_readonly_color("bg_readonly_color"),
+ bg_stripe_color("bg_stripe_color"),
+ hovered_color("hovered_color"),
+ highlighted_color("highlighted_color"),
+ contents(""),
+ scroll_bar_bg_visible("scroll_bar_bg_visible"),
+ scroll_bar_bg_color("scroll_bar_bg_color")
+ , border("border")
+{
+ name = "scroll_list";
+ mouse_opaque = true;
+}
+
+LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
+: LLUICtrl(p),
mLineHeight(0),
mScrollLines(0),
- mPageLines(0),
- mHeadingHeight(20),
+ mMouseWheelOpaque(p.mouse_wheel_opaque),
+ mPageLines(p.page_lines),
mMaxSelectable(0),
- mAllowMultipleSelection( allow_multiple_selection ),
mAllowKeyboardMovement(TRUE),
- mCommitOnKeyboardMovement(TRUE),
+ mCommitOnKeyboardMovement(p.commit_on_keyboard_movement),
mCommitOnSelectionChange(FALSE),
mSelectionChanged(FALSE),
mNeedsScroll(FALSE),
mCanSelect(TRUE),
- mDisplayColumnHeaders(FALSE),
mColumnsDirty(FALSE),
mMaxItemCount(INT_MAX),
mMaxContentWidth(0),
- mBackgroundVisible( TRUE ),
- mDrawStripes(TRUE),
- mBgWriteableColor( LLUI::sColorsGroup->getColor( "ScrollBgWriteableColor" ) ),
- mBgReadOnlyColor( LLUI::sColorsGroup->getColor( "ScrollBgReadOnlyColor" ) ),
- mBgSelectedColor( LLUI::sColorsGroup->getColor("ScrollSelectedBGColor") ),
- mBgStripeColor( LLUI::sColorsGroup->getColor("ScrollBGStripeColor") ),
- mFgSelectedColor( LLUI::sColorsGroup->getColor("ScrollSelectedFGColor") ),
- mFgUnselectedColor( LLUI::sColorsGroup->getColor("ScrollUnselectedColor") ),
- mFgDisabledColor( LLUI::sColorsGroup->getColor("ScrollDisabledColor") ),
- mHighlightedColor( LLUI::sColorsGroup->getColor("ScrollHighlightedColor") ),
mBorderThickness( 2 ),
mOnDoubleClickCallback( NULL ),
mOnMaximumSelectCallback( NULL ),
mOnSortChangedCallback( NULL ),
mHighlightedItem(-1),
mBorder(NULL),
- mSearchColumn(0),
+ mSortCallback(NULL),
+ mPopupMenu(NULL),
mNumDynamicWidthColumns(0),
mTotalStaticColumnWidth(0),
- mSorted(TRUE),
+ mTotalColumnPadding(0),
+ mSorted(false),
mDirty(FALSE),
mOriginalSelection(-1),
- mDrewSelected(FALSE)
+ mLastSelected(NULL),
+ mHeadingHeight(p.heading_height),
+ mAllowMultipleSelection(p.multi_select),
+ mDisplayColumnHeaders(p.draw_heading),
+ mBackgroundVisible(p.background_visible),
+ mDrawStripes(p.draw_stripes),
+ mBgWriteableColor(p.bg_writeable_color()),
+ mBgReadOnlyColor(p.bg_readonly_color()),
+ mBgSelectedColor(p.bg_selected_color()),
+ mBgStripeColor(p.bg_stripe_color()),
+ mFgSelectedColor(p.fg_selected_color()),
+ mFgUnselectedColor(p.fg_unselected_color()),
+ mFgDisabledColor(p.fg_disable_color()),
+ mHighlightedColor(p.highlighted_color()),
+ mHoveredColor(p.hovered_color()),
+ mSearchColumn(p.search_column),
+ mColumnPadding(p.column_padding),
+ mContextMenuType(MENU_NONE)
{
mItemListRect.setOriginAndSize(
mBorderThickness,
@@ -594,50 +211,117 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
updateLineHeight();
- mPageLines = mLineHeight? (mItemListRect.getHeight()) / mLineHeight : 0;
-
// Init the scrollbar
+ static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
+
LLRect scroll_rect;
scroll_rect.setOriginAndSize(
- getRect().getWidth() - mBorderThickness - SCROLLBAR_SIZE,
+ getRect().getWidth() - mBorderThickness - scrollbar_size,
mItemListRect.mBottom,
- SCROLLBAR_SIZE,
+ scrollbar_size,
mItemListRect.getHeight());
- mScrollbar = new LLScrollbar( "Scrollbar", scroll_rect,
- LLScrollbar::VERTICAL,
- getItemCount(),
- mScrollLines,
- mPageLines,
- &LLScrollListCtrl::onScrollChange, this );
- mScrollbar->setFollowsRight();
- mScrollbar->setFollowsTop();
- mScrollbar->setFollowsBottom();
- mScrollbar->setEnabled( TRUE );
- // scrollbar is visible only when needed
- mScrollbar->setVisible(FALSE);
+
+ LLScrollbar::Params sbparams;
+ sbparams.name("Scrollbar");
+ sbparams.rect(scroll_rect);
+ sbparams.orientation(LLScrollbar::VERTICAL);
+ sbparams.doc_size(getItemCount());
+ sbparams.doc_pos(mScrollLines);
+ sbparams.page_size( getLinesPerPage() );
+ sbparams.change_callback(boost::bind(&LLScrollListCtrl::onScrollChange, this, _1, _2));
+ sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
+ sbparams.visible(false);
+ sbparams.bg_visible(p.scroll_bar_bg_visible);
+ sbparams.bg_color(p.scroll_bar_bg_color);
+ mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams);
addChild(mScrollbar);
// Border
- if (show_border)
+ if (p.has_border)
{
- LLRect border_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 );
- mBorder = new LLViewBorder( "dlg border", border_rect, LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, 1 );
+ LLRect border_rect = getLocalRect();
+ LLViewBorder::Params params = p.border;
+ params.rect(border_rect);
+ mBorder = LLUICtrlFactory::create<LLViewBorder> (params);
addChild(mBorder);
}
- mColumnPadding = 5;
+ // set border *after* rect is fully initialized
+ if (mBorder)
+ {
+ mBorder->setRect(getLocalRect());
+ mBorder->reshape(getRect().getWidth(), getRect().getHeight());
+ }
- mLastSelected = NULL;
+ if (p.sort_column >= 0)
+ {
+ sortByColumnIndex(p.sort_column, p.sort_ascending);
+ }
+
+
+ for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = p.contents.columns().begin();
+ row_it != p.contents.columns().end();
+ ++row_it)
+ {
+ addColumn(*row_it);
+ }
+
+ for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = p.contents.rows().begin();
+ row_it != p.contents.rows().end();
+ ++row_it)
+ {
+ addRow(*row_it);
+ }
+
+ LLTextBox::Params text_p;
+ text_p.name("comment_text");
+ text_p.border_visible(false);
+ text_p.rect(mItemListRect);
+ text_p.follows.flags(FOLLOWS_ALL);
+ // word wrap was added accroding to the EXT-6841
+ text_p.wrap(true);
+ addChild(LLUICtrlFactory::create<LLTextBox>(text_p));
}
-LLScrollListCtrl::~LLScrollListCtrl()
+S32 LLScrollListCtrl::getSearchColumn()
{
- std::for_each(mItemList.begin(), mItemList.end(), DeletePointer());
-
- if( gEditMenuHandler == this )
+ // search for proper search column
+ if (mSearchColumn < 0)
{
- gEditMenuHandler = NULL;
+ LLScrollListItem* itemp = getFirstData();
+ if (itemp)
+ {
+ for(S32 column = 0; column < getNumColumns(); column++)
+ {
+ LLScrollListCell* cell = itemp->getColumn(column);
+ if (cell && cell->isText())
+ {
+ mSearchColumn = column;
+ break;
+ }
+ }
+ }
}
+ return llclamp(mSearchColumn, 0, getNumColumns());
+}
+/*virtual*/
+bool LLScrollListCtrl::preProcessChildNode(LLXMLNodePtr child)
+{
+ if (child->hasName("column") || child->hasName("row"))
+ {
+ return true; // skip
+ }
+ else
+ {
+ return false;
+ }
+}
+
+LLScrollListCtrl::~LLScrollListCtrl()
+{
+ delete mSortCallback;
+
+ std::for_each(mItemList.begin(), mItemList.end(), DeletePointer());
}
@@ -709,6 +393,10 @@ std::vector<LLScrollListItem*> LLScrollListCtrl::getAllSelected() const
S32 LLScrollListCtrl::getFirstSelectedIndex() const
{
S32 CurSelectedIndex = 0;
+
+ // make sure sort is up to date before returning an index
+ updateSort();
+
item_list::const_iterator iter;
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{
@@ -756,7 +444,7 @@ std::vector<LLScrollListItem*> LLScrollListCtrl::getAllData() const
// returns first matching item
LLScrollListItem* LLScrollListCtrl::getItem(const LLSD& sd) const
{
- LLString string_val = sd.asString();
+ std::string string_val = sd.asString();
item_list::const_iterator iter;
for(iter = mItemList.begin(); iter != mItemList.end(); iter++)
@@ -781,6 +469,7 @@ void LLScrollListCtrl::reshape( S32 width, S32 height, BOOL called_from_parent )
void LLScrollListCtrl::updateLayout()
{
+ static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
// reserve room for column headers, if needed
S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0);
mItemListRect.setOriginAndSize(
@@ -789,17 +478,21 @@ void LLScrollListCtrl::updateLayout()
getRect().getWidth() - 2 * mBorderThickness,
getRect().getHeight() - (2 * mBorderThickness ) - heading_size );
+ getChildView("comment_text")->setShape(mItemListRect);
+
// how many lines of content in a single "page"
- mPageLines = mLineHeight? mItemListRect.getHeight() / mLineHeight : 0;
- BOOL scrollbar_visible = getItemCount() > mPageLines;
+ S32 page_lines = getLinesPerPage();
+
+ BOOL scrollbar_visible = mLineHeight * getItemCount() > mItemListRect.getHeight();
if (scrollbar_visible)
{
// provide space on the right for scrollbar
- mItemListRect.mRight = getRect().getWidth() - mBorderThickness - SCROLLBAR_SIZE;
+ mItemListRect.mRight = getRect().getWidth() - mBorderThickness - scrollbar_size;
}
- mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0));
- mScrollbar->setPageSize( mPageLines );
+ mScrollbar->setOrigin(getRect().getWidth() - mBorderThickness - scrollbar_size, mItemListRect.mBottom);
+ mScrollbar->reshape(scrollbar_size, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0));
+ mScrollbar->setPageSize(page_lines);
mScrollbar->setDocSize( getItemCount() );
mScrollbar->setVisible(scrollbar_visible);
@@ -811,6 +504,9 @@ void LLScrollListCtrl::updateLayout()
void LLScrollListCtrl::fitContents(S32 max_width, S32 max_height)
{
S32 height = llmin( getRequiredRect().getHeight(), max_height );
+ if(mPageLines)
+ height = llmin( mPageLines * mLineHeight + 2*mBorderThickness + (mDisplayColumnHeaders ? mHeadingHeight : 0), height );
+
S32 width = getRect().getWidth();
reshape( width, height );
@@ -838,7 +534,7 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r
{
case ADD_TOP:
mItemList.push_front(item);
- setSorted(FALSE);
+ setNeedsSort();
break;
case ADD_SORTED:
@@ -851,33 +547,33 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r
std::stable_sort(
mItemList.begin(),
mItemList.end(),
- SortScrollListItem(single_sort_column));
+ SortScrollListItem(single_sort_column,mSortCallback));
// ADD_SORTED just sorts by first column...
// this might not match user sort criteria, so flag list as being in unsorted state
- setSorted(FALSE);
+ setNeedsSort();
break;
}
case ADD_BOTTOM:
mItemList.push_back(item);
- setSorted(FALSE);
+ setNeedsSort();
break;
default:
llassert(0);
mItemList.push_back(item);
- setSorted(FALSE);
+ setNeedsSort();
break;
}
// create new column on demand
if (mColumns.empty() && requires_column)
{
- LLSD new_column;
- new_column["name"] = "default_column";
- new_column["label"] = "";
- new_column["dynamicwidth"] = TRUE;
- addColumn(new_column);
+ LLScrollListColumn::Params col_params;
+ col_params.name = "default_column";
+ col_params.header.label = "";
+ col_params.width.dynamic_width = true;
+ addColumn(col_params);
}
updateLineHeightInsert(item);
@@ -893,8 +589,8 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r
// *TODO: Use bookkeeping to make this an incramental cost with item additions
void LLScrollListCtrl::calcColumnWidths()
{
- const S32 HEADING_TEXT_PADDING = 30;
- const S32 COLUMN_TEXT_PADDING = 20;
+ const S32 HEADING_TEXT_PADDING = 25;
+ const S32 COLUMN_TEXT_PADDING = 10;
mMaxContentWidth = 0;
@@ -907,30 +603,27 @@ void LLScrollListCtrl::calcColumnWidths()
if (!column) continue;
// update column width
- S32 new_width = column->mWidth;
+ S32 new_width = column->getWidth();
if (column->mRelWidth >= 0)
{
new_width = (S32)llround(column->mRelWidth*mItemListRect.getWidth());
}
else if (column->mDynamicWidth)
{
- new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
+ new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns;
}
- if (new_width != column->mWidth)
- {
- column->mWidth = new_width;
- }
+ column->setWidth(new_width);
// update max content width for this column, by looking at all items
- column->mMaxContentWidth = column->mHeader ? LLFontGL::sSansSerifSmall->getWidth(column->mLabel) + mColumnPadding + HEADING_TEXT_PADDING : 0;
+ column->mMaxContentWidth = column->mHeader ? LLFontGL::getFontSansSerifSmall()->getWidth(column->mLabel) + mColumnPadding + HEADING_TEXT_PADDING : 0;
item_list::iterator iter;
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{
LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex);
if (!cellp) continue;
- column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
+ column->mMaxContentWidth = llmax(LLFontGL::getFontSansSerifSmall()->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
}
max_item_width += column->mMaxContentWidth;
@@ -974,28 +667,13 @@ void LLScrollListCtrl::updateColumns()
{
calcColumnWidths();
- // propagate column widths to individual cells
- item_list::iterator iter;
- for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
- {
- LLScrollListItem *itemp = *iter;
- S32 num_cols = itemp->getNumColumns();
- S32 i = 0;
- for (LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
- {
- if (i >= (S32)mColumnsIndexed.size()) break;
-
- cell->setWidth(mColumnsIndexed[i]->mWidth);
- }
- }
-
// update column headers
std::vector<LLScrollListColumn*>::iterator column_ordered_it;
S32 left = mItemListRect.mLeft;
- LLColumnHeader* last_header = NULL;
+ LLScrollColumnHeader* last_header = NULL;
for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it)
{
- if ((*column_ordered_it)->mWidth < 0)
+ if ((*column_ordered_it)->getWidth() < 0)
{
// skip hidden columns
continue;
@@ -1004,9 +682,11 @@ void LLScrollListCtrl::updateColumns()
if (column->mHeader)
{
+ column->mHeader->updateResizeBars();
+
last_header = column->mHeader;
S32 top = mItemListRect.mTop;
- S32 right = left + column->mWidth;
+ S32 right = left + column->getWidth();
if (column->mIndex != (S32)mColumnsIndexed.size()-1)
{
@@ -1024,21 +704,30 @@ void LLScrollListCtrl::updateColumns()
}
}
- //FIXME: stretch the entire last column if it is resizable (gestures windows shows truncated text in last column)
// expand last column header we encountered to full list width
if (last_header)
{
S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft);
last_header->reshape(new_width, last_header->getRect().getHeight());
last_header->setVisible(mDisplayColumnHeaders && new_width > 0);
+ last_header->getColumn()->setWidth(new_width);
}
-}
-void LLScrollListCtrl::setDisplayHeading(BOOL display)
-{
- mDisplayColumnHeaders = display;
+ // propagate column widths to individual cells
+ item_list::iterator iter;
+ for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
+ {
+ LLScrollListItem *itemp = *iter;
+ S32 num_cols = itemp->getNumColumns();
+ S32 i = 0;
+ for (LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
+ {
+ if (i >= (S32)mColumnsIndexed.size()) break;
+
+ cell->setWidth(mColumnsIndexed[i]->getWidth());
+ }
+ }
- updateLayout();
}
void LLScrollListCtrl::setHeadingHeight(S32 heading_height)
@@ -1048,6 +737,12 @@ void LLScrollListCtrl::setHeadingHeight(S32 heading_height)
updateLayout();
}
+void LLScrollListCtrl::setPageLines(S32 new_page_lines)
+{
+ mPageLines = new_page_lines;
+
+ updateLayout();
+}
BOOL LLScrollListCtrl::selectFirstItem()
{
@@ -1097,6 +792,9 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index )
return FALSE;
}
+ // make sure sort is up to date
+ updateSort();
+
S32 listlen = (S32)mItemList.size();
first_index = llclamp(first_index, 0, listlen-1);
@@ -1107,9 +805,15 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index )
BOOL success = FALSE;
S32 index = 0;
- for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
+ for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); )
{
LLScrollListItem *itemp = *iter;
+ if(!itemp)
+ {
+ iter = mItemList.erase(iter);
+ continue ;
+ }
+
if( index >= first_index && index <= last_index )
{
if( itemp->getEnabled() )
@@ -1123,6 +827,7 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index )
deselectItem(itemp);
}
index++;
+ iter++ ;
}
if (mCommitOnSelectionChange)
@@ -1143,6 +848,7 @@ void LLScrollListCtrl::swapWithNext(S32 index)
// At end of list, doesn't do anything
return;
}
+ updateSort();
LLScrollListItem *cur_itemp = mItemList[index];
mItemList[index] = mItemList[index + 1];
mItemList[index + 1] = cur_itemp;
@@ -1156,6 +862,7 @@ void LLScrollListCtrl::swapWithPrevious(S32 index)
// At beginning of list, don't do anything
}
+ updateSort();
LLScrollListItem *cur_itemp = mItemList[index];
mItemList[index] = mItemList[index - 1];
mItemList[index - 1] = cur_itemp;
@@ -1169,6 +876,8 @@ void LLScrollListCtrl::deleteSingleItem(S32 target_index)
return;
}
+ updateSort();
+
LLScrollListItem *itemp;
itemp = mItemList[target_index];
if (itemp == mLastSelected)
@@ -1225,7 +934,15 @@ void LLScrollListCtrl::deleteSelectedItems()
dirtyColumns();
}
-void LLScrollListCtrl::highlightNthItem(S32 target_index)
+void LLScrollListCtrl::clearHighlightedItems()
+{
+ for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); ++iter)
+ {
+ (*iter)->setHighlighted(false);
+ }
+}
+
+void LLScrollListCtrl::mouseOverHighlightNthItem(S32 target_index)
{
if (mHighlightedItem != target_index)
{
@@ -1233,14 +950,14 @@ void LLScrollListCtrl::highlightNthItem(S32 target_index)
}
}
-S32 LLScrollListCtrl::selectMultiple( LLDynamicArray<LLUUID> ids )
+S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
{
item_list::iterator iter;
S32 count = 0;
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{
LLScrollListItem* item = *iter;
- LLDynamicArray<LLUUID>::iterator iditr;
+ uuid_vec_t::iterator iditr;
for(iditr = ids.begin(); iditr != ids.end(); ++iditr)
{
if (item->getEnabled() && (item->getUUID() == (*iditr)))
@@ -1262,6 +979,8 @@ S32 LLScrollListCtrl::selectMultiple( LLDynamicArray<LLUUID> ids )
S32 LLScrollListCtrl::getItemIndex( LLScrollListItem* target_item ) const
{
+ updateSort();
+
S32 index = 0;
item_list::const_iterator iter;
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
@@ -1278,6 +997,8 @@ S32 LLScrollListCtrl::getItemIndex( LLScrollListItem* target_item ) const
S32 LLScrollListCtrl::getItemIndex( const LLUUID& target_id ) const
{
+ updateSort();
+
S32 index = 0;
item_list::const_iterator iter;
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
@@ -1303,6 +1024,8 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
}
else
{
+ updateSort();
+
item_list::iterator iter;
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{
@@ -1345,6 +1068,8 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection)
}
else
{
+ updateSort();
+
item_list::reverse_iterator iter;
for (iter = mItemList.rbegin(); iter != mItemList.rend(); iter++)
{
@@ -1396,75 +1121,78 @@ void LLScrollListCtrl::deselectAllItems(BOOL no_commit_on_change)
///////////////////////////////////////////////////////////////////////////////////////////////////
// Use this to add comment text such as "Searching", which ignores column settings of list
-LLScrollListItem* LLScrollListCtrl::addCommentText(const LLString& comment_text, EAddPosition pos)
+void LLScrollListCtrl::setCommentText(const std::string& comment_text)
{
- LLScrollListItem* item = NULL;
- if (getItemCount() < mMaxItemCount)
- {
- // always draw comment text with "enabled" color
- item = new LLScrollListItemComment( comment_text, mFgUnselectedColor );
- addItem( item, pos, FALSE );
- }
- return item;
+ getChild<LLTextBox>("comment_text")->setValue(comment_text);
}
LLScrollListItem* LLScrollListCtrl::addSeparator(EAddPosition pos)
{
- LLScrollListItem* item = new LLScrollListItemSeparator();
- addItem(item, pos, FALSE);
- return item;
+ LLScrollListItem::Params separator_params;
+ separator_params.enabled(false);
+ LLScrollListCell::Params column_params;
+ column_params.type = "icon";
+ column_params.value = "menu_separator";
+ column_params.color = LLColor4(0.f, 0.f, 0.f, 0.7f);
+ column_params.font_halign = LLFontGL::HCENTER;
+ separator_params.columns.add(column_params);
+ return addRow( separator_params, pos );
}
// Selects first enabled item of the given name.
// Returns false if item not found.
-BOOL LLScrollListCtrl::selectItemByLabel(const LLString& label, BOOL case_sensitive)
+// Calls getItemByLabel in order to combine functionality
+BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sensitive)
{
- // ensure that no stale items are selected, even if we don't find a match
- deselectAllItems(TRUE);
- //RN: assume no empty items
- if (label.empty())
+ deselectAllItems(TRUE); // ensure that no stale items are selected, even if we don't find a match
+ LLScrollListItem* item = getItemByLabel(label, case_sensitive);
+
+ bool found = NULL != item;
+ if(found)
{
- return FALSE;
+ selectItem(item);
}
- LLString target_text = label;
- if (!case_sensitive)
+ if (mCommitOnSelectionChange)
{
- LLString::toLower(target_text);
+ commitIfChanged();
}
- BOOL found = FALSE;
+ return found;
+}
+
+LLScrollListItem* LLScrollListCtrl::getItemByLabel(const std::string& label, BOOL case_sensitive, S32 column)
+{
+ if (label.empty()) //RN: assume no empty items
+ {
+ return NULL;
+ }
+
+ std::string target_text = label;
+ if (!case_sensitive)
+ {
+ LLStringUtil::toLower(target_text);
+ }
item_list::iterator iter;
- S32 index = 0;
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{
LLScrollListItem* item = *iter;
- // Only select enabled items with matching names
- LLString item_text = item->getColumn(0)->getValue().asString();
+ std::string item_text = item->getColumn(column)->getValue().asString(); // Only select enabled items with matching names
if (!case_sensitive)
{
- LLString::toLower(item_text);
+ LLStringUtil::toLower(item_text);
}
- BOOL select = !found && item->getEnabled() && item_text == target_text;
- if (select)
+ if(item_text == target_text)
{
- selectItem(item);
+ return item;
}
- found = found || select;
- index++;
- }
-
- if (mCommitOnSelectionChange)
- {
- commitIfChanged();
}
-
- return found;
+ return NULL;
}
-BOOL LLScrollListCtrl::selectItemByPrefix(const LLString& target, BOOL case_sensitive)
+BOOL LLScrollListCtrl::selectItemByPrefix(const std::string& target, BOOL case_sensitive)
{
return selectItemByPrefix(utf8str_to_wstring(target), case_sensitive);
}
@@ -1486,7 +1214,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
{
LLScrollListItem* item = *iter;
// Only select enabled items with matching names
- LLScrollListCell* cellp = item->getColumn(mSearchColumn);
+ LLScrollListCell* cellp = item->getColumn(getSearchColumn());
BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE;
if (select)
{
@@ -1501,7 +1229,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
if (!case_sensitive)
{
// do comparisons in lower case
- LLWString::toLower(target_trimmed);
+ LLWStringUtil::toLower(target_trimmed);
}
for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
@@ -1509,7 +1237,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
LLScrollListItem* item = *iter;
// Only select enabled items with matching names
- LLScrollListCell* cellp = item->getColumn(mSearchColumn);
+ LLScrollListCell* cellp = item->getColumn(getSearchColumn());
if (!cellp)
{
continue;
@@ -1517,11 +1245,11 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
if (!case_sensitive)
{
- LLWString::toLower(item_label);
+ LLWStringUtil::toLower(item_label);
}
// remove extraneous whitespace from searchable label
LLWString trimmed_label = item_label;
- LLWString::trim(trimmed_label);
+ LLWStringUtil::trim(trimmed_label);
BOOL select = item->getEnabled() && trimmed_label.compare(0, target_trimmed.size(), target_trimmed) == 0;
@@ -1545,7 +1273,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
return found;
}
-const LLString LLScrollListCtrl::getSelectedItemLabel(S32 column) const
+const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const
{
LLScrollListItem* item;
@@ -1555,23 +1283,25 @@ const LLString LLScrollListCtrl::getSelectedItemLabel(S32 column) const
return item->getColumn(column)->getValue().asString();
}
- return LLString::null;
+ return LLStringUtil::null;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// "StringUUID" interface: use this when you're creating a list that contains non-unique strings each of which
// has an associated, unique UUID, and only one of which can be selected at a time.
-LLScrollListItem* LLScrollListCtrl::addStringUUIDItem(const LLString& item_text, const LLUUID& id, EAddPosition pos, BOOL enabled, S32 column_width)
+LLScrollListItem* LLScrollListCtrl::addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos, BOOL enabled)
{
- LLScrollListItem* item = NULL;
if (getItemCount() < mMaxItemCount)
{
- item = new LLScrollListItem( enabled, NULL, id );
- item->addColumn(item_text, LLResMgr::getInstance()->getRes(LLFONT_SANSSERIF_SMALL), column_width);
- addItem( item, pos );
+ LLScrollListItem::Params item_p;
+ item_p.enabled(enabled);
+ item_p.value(id);
+ item_p.columns.add().value(item_text).type("text");
+
+ return addRow( item_p, pos );
}
- return item;
+ return NULL;
}
// Select the line or lines that match this UUID
@@ -1659,24 +1389,24 @@ void LLScrollListCtrl::drawItems()
S32 y = mItemListRect.mTop - mLineHeight;
// allow for partial line at bottom
- S32 num_page_lines = mPageLines + 1;
+ S32 num_page_lines = getLinesPerPage();
LLRect item_rect;
LLGLSUIDefault gls_ui;
+ F32 alpha = getDrawContext().mAlpha;
+
{
LLLocalClipRect clip(mItemListRect);
S32 cur_y = y;
- mDrewSelected = FALSE;
-
S32 line = 0;
S32 max_columns = 0;
LLColor4 highlight_color = LLColor4::white;
- F32 type_ahead_timeout = LLUI::sConfigGroup->getF32("TypeAheadTimeout");
+ static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0);
highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout, 0.4f, 0.f);
item_list::iterator iter;
@@ -1689,14 +1419,10 @@ void LLScrollListCtrl::drawItems()
cur_y,
mItemListRect.getWidth(),
mLineHeight );
+ item->setRect(item_rect);
//llinfos << item_rect.getWidth() << llendl;
- if (item->getSelected())
- {
- mDrewSelected = TRUE;
- }
-
max_columns = llmax(max_columns, item->getNumColumns());
LLColor4 fg_color;
@@ -1704,30 +1430,49 @@ void LLScrollListCtrl::drawItems()
if( mScrollLines <= line && line < mScrollLines + num_page_lines )
{
- fg_color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
+ fg_color = (item->getEnabled() ? mFgUnselectedColor.get() : mFgDisabledColor.get());
if( item->getSelected() && mCanSelect)
{
- bg_color = mBgSelectedColor;
- fg_color = (item->getEnabled() ? mFgSelectedColor : mFgDisabledColor);
+ if(item->getHighlighted()) // if it's highlighted, average the colors
+ {
+ bg_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
+ }
+ else // otherwise just select-highlight it
+ {
+ bg_color = mBgSelectedColor.get();
+ }
+
+ fg_color = (item->getEnabled() ? mFgSelectedColor.get() : mFgDisabledColor.get());
}
else if (mHighlightedItem == line && mCanSelect)
{
- bg_color = mHighlightedColor;
+ if(item->getHighlighted()) // if it's highlighted, average the colors
+ {
+ bg_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
+ }
+ else // otherwise just hover-highlight it
+ {
+ bg_color = mHoveredColor.get();
+ }
+ }
+ else if (item->getHighlighted())
+ {
+ bg_color = mHighlightedColor.get();
}
else
{
if (mDrawStripes && (line % 2 == 0) && (max_columns > 1))
{
- bg_color = mBgStripeColor;
+ bg_color = mBgStripeColor.get();
}
}
if (!item->getEnabled())
{
- bg_color = mBgReadOnlyColor;
+ bg_color = mBgReadOnlyColor.get();
}
- item->draw(item_rect, fg_color, bg_color, highlight_color, mColumnPadding);
+ item->draw(item_rect, fg_color % alpha, bg_color% alpha, highlight_color % alpha, mColumnPadding);
cur_y -= mLineHeight;
}
@@ -1739,11 +1484,10 @@ void LLScrollListCtrl::drawItems()
void LLScrollListCtrl::draw()
{
+ LLLocalClipRect clip(getLocalRect());
+
// if user specifies sort, make sure it is maintained
- if (needsSorting() && !isSorted())
- {
- sortItems();
- }
+ updateSort();
if (mNeedsScroll)
{
@@ -1754,9 +1498,8 @@ void LLScrollListCtrl::draw()
// Draw background
if (mBackgroundVisible)
{
- LLGLSNoTexture no_texture;
- gGL.color4fv( getEnabled() ? mBgWriteableColor.mV : mBgReadOnlyColor.mV );
- gl_rect_2d(background);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gl_rect_2d(background, getEnabled() ? mBgWriteableColor.get() : mBgReadOnlyColor.get() );
}
if (mColumnsDirty)
@@ -1765,11 +1508,13 @@ void LLScrollListCtrl::draw()
mColumnsDirty = FALSE;
}
+ getChildView("comment_text")->setVisible(mItemList.empty());
+
drawItems();
if (mBorder)
{
- mBorder->setKeyboardFocusHighlight(gFocusMgr.getKeyboardFocus() == this);
+ mBorder->setKeyboardFocusHighlight(hasFocus());
}
LLUICtrl::draw();
@@ -1787,10 +1532,28 @@ BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
BOOL handled = FALSE;
// Pretend the mouse is over the scrollbar
handled = mScrollbar->handleScrollWheel( 0, 0, clicks );
+
+ if (mMouseWheelOpaque)
+ {
+ return TRUE;
+ }
+
return handled;
}
-BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
+// *NOTE: Requires a valid row_index and column_index
+LLRect LLScrollListCtrl::getCellRect(S32 row_index, S32 column_index)
+{
+ LLRect cell_rect;
+ S32 rect_left = getColumnOffsetFromIndex(column_index) + mItemListRect.mLeft;
+ S32 rect_bottom = getRowOffsetFromIndex(row_index);
+ LLScrollListColumn* columnp = getColumn(column_index);
+ cell_rect.setOriginAndSize(rect_left, rect_bottom,
+ /*rect_left + */columnp->getWidth(), mLineHeight);
+ return cell_rect;
+}
+
+BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, MASK mask)
{
S32 column_index = getColumnIndexFromOffset(x);
LLScrollListColumn* columnp = getColumn(column_index);
@@ -1804,34 +1567,32 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky
{
LLScrollListCell* hit_cell = hit_item->getColumn(column_index);
if (!hit_cell) return FALSE;
- //S32 cell_required_width = hit_cell->getContentWidth();
if (hit_cell
- && hit_cell->isText())
+ && hit_cell->isText()
+ && hit_cell->needsToolTip())
{
-
- S32 rect_left = getColumnOffsetFromIndex(column_index) + mItemListRect.mLeft;
- S32 rect_bottom = getRowOffsetFromIndex(getItemIndex(hit_item));
- LLRect cell_rect;
- cell_rect.setOriginAndSize(rect_left, rect_bottom, rect_left + columnp->mWidth, mLineHeight);
+ S32 row_index = getItemIndex(hit_item);
+ LLRect cell_rect = getCellRect(row_index, column_index);
// Convert rect local to screen coordinates
- localPointToScreen(
- cell_rect.mLeft, cell_rect.mBottom,
- &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
- localPointToScreen(
- cell_rect.mRight, cell_rect.mTop,
- &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
+ LLRect sticky_rect;
+ localRectToScreen(cell_rect, &sticky_rect);
- msg = hit_cell->getValue().asString();
+ // display tooltip exactly over original cell, in same font
+ LLToolTipMgr::instance().show(LLToolTip::Params()
+ .message(hit_cell->getToolTip())
+ .font(LLFontGL::getFontSansSerifSmall())
+ .pos(LLCoordGL(sticky_rect.mLeft - 5, sticky_rect.mTop + 6))
+ .delay_time(0.2f)
+ .sticky_rect(sticky_rect));
}
handled = TRUE;
}
// otherwise, look for a tooltip associated with this column
- LLColumnHeader* headerp = columnp->mHeader;
+ LLScrollColumnHeader* headerp = columnp->mHeader;
if (headerp && !handled)
{
- headerp->handleToolTip(x, y, msg, sticky_rect_screen);
- handled = !msg.empty();
+ handled = headerp->handleToolTip(x, y, mask);
}
return handled;
@@ -1870,7 +1631,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{
if(mOnMaximumSelectCallback)
{
- mOnMaximumSelectCallback(mCallbackUserData);
+ mOnMaximumSelectCallback();
}
break;
}
@@ -1908,7 +1669,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{
if(mOnMaximumSelectCallback)
{
- mOnMaximumSelectCallback(mCallbackUserData);
+ mOnMaximumSelectCallback();
}
}
}
@@ -1962,7 +1723,7 @@ BOOL LLScrollListCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
}
BOOL LLScrollListCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
-{
+{
if (hasMouseCapture())
{
// release mouse capture immediately so
@@ -1986,6 +1747,72 @@ BOOL LLScrollListCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
return LLUICtrl::handleMouseUp(x, y, mask);
}
+// virtual
+BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ LLScrollListItem *item = hitItem(x, y);
+ if (item)
+ {
+ // check to see if we have a UUID for this row
+ std::string id = item->getValue().asString();
+ LLUUID uuid(id);
+ if (! uuid.isNull() && mContextMenuType != MENU_NONE)
+ {
+ // set up the callbacks for all of the avatar/group menu items
+ // (N.B. callbacks don't take const refs as id is local scope)
+ bool is_group = (mContextMenuType == MENU_GROUP);
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ registrar.add("Url.Execute", boost::bind(&LLScrollListCtrl::showNameDetails, id, is_group));
+ registrar.add("Url.CopyLabel", boost::bind(&LLScrollListCtrl::copyNameToClipboard, id, is_group));
+ registrar.add("Url.CopyUrl", boost::bind(&LLScrollListCtrl::copySLURLToClipboard, id, is_group));
+
+ // create the context menu from the XUI file and display it
+ std::string menu_name = is_group ? "menu_url_group.xml" : "menu_url_agent.xml";
+ delete mPopupMenu;
+ mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
+ menu_name, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+ if (mPopupMenu)
+ {
+ mPopupMenu->show(x, y);
+ LLMenuGL::showPopup(this, mPopupMenu, x, y);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+void LLScrollListCtrl::showNameDetails(std::string id, bool is_group)
+{
+ // show the resident's profile or the group profile
+ std::string sltype = is_group ? "group" : "agent";
+ std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about";
+ LLUrlAction::clickAction(slurl);
+}
+
+void LLScrollListCtrl::copyNameToClipboard(std::string id, bool is_group)
+{
+ // copy the name of the avatar or group to the clipboard
+ std::string name;
+ if (is_group)
+ {
+ gCacheName->getGroupName(LLUUID(id), name);
+ }
+ else
+ {
+ gCacheName->getFullName(LLUUID(id), name);
+ }
+ LLUrlAction::copyURLToClipboard(name);
+}
+
+void LLScrollListCtrl::copySLURLToClipboard(std::string id, bool is_group)
+{
+ // copy a SLURL for the avatar or group to the clipboard
+ std::string sltype = is_group ? "group" : "agent";
+ std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about";
+ LLUrlAction::copyURLToClipboard(slurl);
+}
+
BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
{
//BOOL handled = FALSE;
@@ -1997,9 +1824,10 @@ BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
// so the scroll bars will work.
if (NULL == LLView::childrenHandleDoubleClick(x, y, mask))
{
- if( mCanSelect && mOnDoubleClickCallback )
+ // Run the callback only if an item is being double-clicked.
+ if( mCanSelect && hitItem(x, y) && mOnDoubleClickCallback )
{
- mOnDoubleClickCallback( mCallbackUserData );
+ mOnDoubleClickCallback();
}
}
}
@@ -2066,6 +1894,8 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y )
// Excludes disabled items.
LLScrollListItem* hit_item = NULL;
+ updateSort();
+
LLRect item_rect;
item_rect.setLeftTopAndSize(
mItemListRect.mLeft,
@@ -2074,7 +1904,7 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y )
mLineHeight );
// allow for partial line at bottom
- S32 num_page_lines = mPageLines + 1;
+ S32 num_page_lines = getLinesPerPage();
S32 line = 0;
item_list::iterator iter;
@@ -2109,7 +1939,7 @@ S32 LLScrollListCtrl::getColumnIndexFromOffset(S32 x)
ordered_columns_t::const_iterator end = mColumnsIndexed.end();
for ( ; iter != end; ++iter)
{
- width = (*iter)->mWidth + mColumnPadding;
+ width = (*iter)->getWidth() + mColumnPadding;
right += width;
if (left <= x && x < right )
{
@@ -2136,7 +1966,7 @@ S32 LLScrollListCtrl::getColumnOffsetFromIndex(S32 index)
{
return column_offset;
}
- column_offset += (*iter)->mWidth + mColumnPadding;
+ column_offset += (*iter)->getWidth() + mColumnPadding;
}
// when running off the end, return the rightmost pixel
@@ -2145,8 +1975,7 @@ S32 LLScrollListCtrl::getColumnOffsetFromIndex(S32 index)
S32 LLScrollListCtrl::getRowOffsetFromIndex(S32 index)
{
- S32 row_bottom = ((mItemListRect.mTop - (index - mScrollLines)) * mLineHeight)
- - mLineHeight;
+ S32 row_bottom = (mItemListRect.mTop - ((index - mScrollLines + 1) * mLineHeight) );
return row_bottom;
}
@@ -2169,11 +1998,11 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
LLScrollListItem* item = hitItem(x, y);
if (item)
{
- highlightNthItem(getItemIndex(item));
+ mouseOverHighlightNthItem(getItemIndex(item));
}
else
{
- highlightNthItem(-1);
+ mouseOverHighlightNthItem(-1);
}
}
@@ -2182,6 +2011,11 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
return handled;
}
+void LLScrollListCtrl::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ // clear mouse highlight
+ mouseOverHighlightNthItem(-1);
+}
BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask )
{
@@ -2288,7 +2122,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask )
{
if (getFirstSelected())
{
- LLScrollListCell* cellp = getFirstSelected()->getColumn(mSearchColumn);
+ LLScrollListCell* cellp = getFirstSelected()->getColumn(getSearchColumn());
if (cellp)
{
cellp->highlightText(0, 0);
@@ -2326,7 +2160,8 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char)
}
// perform incremental search based on keyboard input
- if (mSearchTimer.getElapsedTimeF32() > LLUI::sConfigGroup->getF32("TypeAheadTimeout"))
+ static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0);
+ if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout)
{
mSearchString.clear();
}
@@ -2375,7 +2210,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char)
{
LLScrollListItem* item = *iter;
- LLScrollListCell* cellp = item->getColumn(mSearchColumn);
+ LLScrollListCell* cellp = item->getColumn(getSearchColumn());
if (cellp)
{
// Only select enabled items with matching first characters
@@ -2442,7 +2277,7 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_it
{
if (mLastSelected)
{
- LLScrollListCell* cellp = mLastSelected->getColumn(mSearchColumn);
+ LLScrollListCell* cellp = mLastSelected->getColumn(getSearchColumn());
if (cellp)
{
cellp->highlightText(0, 0);
@@ -2470,7 +2305,7 @@ void LLScrollListCtrl::deselectItem(LLScrollListItem* itemp)
}
itemp->setSelected(FALSE);
- LLScrollListCell* cellp = itemp->getColumn(mSearchColumn);
+ LLScrollListCell* cellp = itemp->getColumn(getSearchColumn());
if (cellp)
{
cellp->highlightText(0, 0);
@@ -2497,9 +2332,16 @@ struct SameSortColumn
bool operator()(std::pair<S32, BOOL> sort_column) { return sort_column.first == mColumn; }
};
-BOOL LLScrollListCtrl::setSort(S32 column, BOOL ascending)
+BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending)
{
- sort_column_t new_sort_column(column, ascending);
+ LLScrollListColumn* sort_column = getColumn(column_idx);
+ if (!sort_column) return FALSE;
+
+ sort_column->mSortDirection = ascending ? LLScrollListColumn::ASCENDING : LLScrollListColumn::DESCENDING;
+
+ sort_column_t new_sort_column(column_idx, ascending);
+
+ setNeedsSort();
if (mSortColumns.empty())
{
@@ -2513,7 +2355,7 @@ BOOL LLScrollListCtrl::setSort(S32 column, BOOL ascending)
// remove any existing sort criterion referencing this column
// and add the new one
- mSortColumns.erase(remove_if(mSortColumns.begin(), mSortColumns.end(), SameSortColumn(column)), mSortColumns.end());
+ mSortColumns.erase(remove_if(mSortColumns.begin(), mSortColumns.end(), SameSortColumn(column_idx)), mSortColumns.end());
mSortColumns.push_back(new_sort_column);
// did the sort criteria change?
@@ -2521,48 +2363,68 @@ BOOL LLScrollListCtrl::setSort(S32 column, BOOL ascending)
}
}
-// Called by scrollbar
-//static
-void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar, void* userdata )
+S32 LLScrollListCtrl::getLinesPerPage()
{
- LLScrollListCtrl* self = (LLScrollListCtrl*) userdata;
- self->mScrollLines = new_pos;
+ //if mPageLines is NOT provided display all item
+ if(mPageLines)
+ {
+ return mPageLines;
+ }
+ else
+ {
+ return mLineHeight ? mItemListRect.getHeight() / mLineHeight : getItemCount();
+ }
}
-void LLScrollListCtrl::sortByColumn(LLString name, BOOL ascending)
+// Called by scrollbar
+void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar )
{
- if (name.empty())
- {
- sortItems();
- return;
- }
+ mScrollLines = new_pos;
+}
+
- std::map<LLString, LLScrollListColumn>::iterator itor = mColumns.find(name);
+void LLScrollListCtrl::sortByColumn(const std::string& name, BOOL ascending)
+{
+ std::map<std::string, LLScrollListColumn>::iterator itor = mColumns.find(name);
if (itor != mColumns.end())
{
- sortByColumn((*itor).second.mIndex, ascending);
+ sortByColumnIndex((*itor).second.mIndex, ascending);
}
}
// First column is column 0
-void LLScrollListCtrl::sortByColumn(U32 column, BOOL ascending)
+void LLScrollListCtrl::sortByColumnIndex(U32 column, BOOL ascending)
{
- if (setSort(column, ascending))
+ setSort(column, ascending);
+ updateSort();
+}
+
+void LLScrollListCtrl::updateSort() const
+{
+ if (hasSortOrder() && !isSorted())
{
- sortItems();
+ // do stable sort to preserve any previous sorts
+ std::stable_sort(
+ mItemList.begin(),
+ mItemList.end(),
+ SortScrollListItem(mSortColumns,mSortCallback));
+
+ mSorted = true;
}
}
-void LLScrollListCtrl::sortItems()
+// for one-shot sorts, does not save sort column/order
+void LLScrollListCtrl::sortOnce(S32 column, BOOL ascending)
{
+ std::vector<std::pair<S32, BOOL> > sort_column;
+ sort_column.push_back(std::make_pair(column, ascending));
+
// do stable sort to preserve any previous sorts
std::stable_sort(
mItemList.begin(),
mItemList.end(),
- SortScrollListItem(mSortColumns));
-
- setSorted(TRUE);
+ SortScrollListItem(sort_column,mSortCallback));
}
void LLScrollListCtrl::dirtyColumns()
@@ -2573,7 +2435,7 @@ void LLScrollListCtrl::dirtyColumns()
// just in case someone indexes into it immediately
mColumnsIndexed.resize(mColumns.size());
- std::map<LLString, LLScrollListColumn>::iterator column_itor;
+ std::map<std::string, LLScrollListColumn>::iterator column_itor;
for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)
{
LLScrollListColumn *column = &column_itor->second;
@@ -2592,7 +2454,7 @@ void LLScrollListCtrl::setScrollPos( S32 pos )
{
mScrollbar->setDocPos( pos );
- onScrollChange(mScrollbar->getDocPos(), mScrollbar, this);
+ onScrollChange(mScrollbar->getDocPos(), mScrollbar);
}
@@ -2605,6 +2467,8 @@ void LLScrollListCtrl::scrollToShowSelected()
return;
}
+ updateSort();
+
S32 index = getFirstSelectedIndex();
if (index < 0)
{
@@ -2619,7 +2483,8 @@ void LLScrollListCtrl::scrollToShowSelected()
}
S32 lowest = mScrollLines;
- S32 highest = mScrollLines + mPageLines;
+ S32 page_lines = getLinesPerPage();
+ S32 highest = mScrollLines + page_lines;
if (index < lowest)
{
@@ -2628,298 +2493,13 @@ void LLScrollListCtrl::scrollToShowSelected()
}
else if (highest <= index)
{
- setScrollPos(index - mPageLines + 1);
+ setScrollPos(index - page_lines + 1);
}
}
-// virtual
-LLXMLNodePtr LLScrollListCtrl::getXML(bool save_children) const
+void LLScrollListCtrl::updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width)
{
- LLXMLNodePtr node = LLUICtrl::getXML();
-
- // Attributes
-
- node->createChild("multi_select", TRUE)->setBoolValue(mAllowMultipleSelection);
-
- node->createChild("draw_border", TRUE)->setBoolValue((mBorder != NULL));
-
- node->createChild("draw_heading", TRUE)->setBoolValue(mDisplayColumnHeaders);
-
- node->createChild("background_visible", TRUE)->setBoolValue(mBackgroundVisible);
-
- node->createChild("draw_stripes", TRUE)->setBoolValue(mDrawStripes);
-
- node->createChild("column_padding", TRUE)->setIntValue(mColumnPadding);
-
- addColorXML(node, mBgWriteableColor, "bg_writeable_color", "ScrollBgWriteableColor");
- addColorXML(node, mBgReadOnlyColor, "bg_read_only_color", "ScrollBgReadOnlyColor");
- addColorXML(node, mBgSelectedColor, "bg_selected_color", "ScrollSelectedBGColor");
- addColorXML(node, mBgStripeColor, "bg_stripe_color", "ScrollBGStripeColor");
- addColorXML(node, mFgSelectedColor, "fg_selected_color", "ScrollSelectedFGColor");
- addColorXML(node, mFgUnselectedColor, "fg_unselected_color", "ScrollUnselectedColor");
- addColorXML(node, mFgDisabledColor, "fg_disable_color", "ScrollDisabledColor");
- addColorXML(node, mHighlightedColor, "highlighted_color", "ScrollHighlightedColor");
-
- // Contents
-
- std::map<LLString, LLScrollListColumn>::const_iterator itor;
- std::vector<const LLScrollListColumn*> sorted_list;
- sorted_list.resize(mColumns.size());
- for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
- {
- sorted_list[itor->second.mIndex] = &itor->second;
- }
-
- std::vector<const LLScrollListColumn*>::iterator itor2;
- for (itor2 = sorted_list.begin(); itor2 != sorted_list.end(); ++itor2)
- {
- LLXMLNodePtr child_node = node->createChild("column", FALSE);
- const LLScrollListColumn *column = *itor2;
-
- child_node->createChild("name", TRUE)->setStringValue(column->mName);
- child_node->createChild("label", TRUE)->setStringValue(column->mLabel);
- child_node->createChild("width", TRUE)->setIntValue(column->mWidth);
- }
-
- return node;
-}
-
-void LLScrollListCtrl::setScrollListParameters(LLXMLNodePtr node)
-{
- // James: This is not a good way to do colors. We need a central "UI style"
- // manager that sets the colors for ALL scroll lists, buttons, etc.
-
- LLColor4 color;
- if(node->hasAttribute("fg_unselected_color"))
- {
- LLUICtrlFactory::getAttributeColor(node,"fg_unselected_color", color);
- setFgUnselectedColor(color);
- }
- if(node->hasAttribute("fg_selected_color"))
- {
- LLUICtrlFactory::getAttributeColor(node,"fg_selected_color", color);
- setFgSelectedColor(color);
- }
- if(node->hasAttribute("bg_selected_color"))
- {
- LLUICtrlFactory::getAttributeColor(node,"bg_selected_color", color);
- setBgSelectedColor(color);
- }
- if(node->hasAttribute("fg_disable_color"))
- {
- LLUICtrlFactory::getAttributeColor(node,"fg_disable_color", color);
- setFgDisableColor(color);
- }
- if(node->hasAttribute("bg_writeable_color"))
- {
- LLUICtrlFactory::getAttributeColor(node,"bg_writeable_color", color);
- setBgWriteableColor(color);
- }
- if(node->hasAttribute("bg_read_only_color"))
- {
- LLUICtrlFactory::getAttributeColor(node,"bg_read_only_color", color);
- setReadOnlyBgColor(color);
- }
- if (LLUICtrlFactory::getAttributeColor(node,"bg_stripe_color", color))
- {
- setBgStripeColor(color);
- }
- if (LLUICtrlFactory::getAttributeColor(node,"highlighted_color", color))
- {
- setHighlightedColor(color);
- }
-
- if(node->hasAttribute("background_visible"))
- {
- BOOL background_visible;
- node->getAttributeBOOL("background_visible", background_visible);
- setBackgroundVisible(background_visible);
- }
-
- if(node->hasAttribute("draw_stripes"))
- {
- BOOL draw_stripes;
- node->getAttributeBOOL("draw_stripes", draw_stripes);
- setDrawStripes(draw_stripes);
- }
-
- if(node->hasAttribute("column_padding"))
- {
- S32 column_padding;
- node->getAttributeS32("column_padding", column_padding);
- setColumnPadding(column_padding);
- }
-}
-
-// static
-LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
- LLString name("scroll_list");
- node->getAttributeString("name", name);
-
- LLRect rect;
- createRect(node, rect, parent, LLRect());
-
- BOOL multi_select = FALSE;
- node->getAttributeBOOL("multi_select", multi_select);
-
- BOOL draw_border = TRUE;
- node->getAttributeBOOL("draw_border", draw_border);
-
- BOOL draw_heading = FALSE;
- node->getAttributeBOOL("draw_heading", draw_heading);
-
- S32 search_column = 0;
- node->getAttributeS32("search_column", search_column);
-
- S32 sort_column = -1;
- node->getAttributeS32("sort_column", sort_column);
-
- BOOL sort_ascending = TRUE;
- node->getAttributeBOOL("sort_ascending", sort_ascending);
-
- LLUICtrlCallback callback = NULL;
-
- LLScrollListCtrl* scroll_list = new LLScrollListCtrl(
- name,
- rect,
- callback,
- NULL,
- multi_select,
- draw_border);
-
- scroll_list->setDisplayHeading(draw_heading);
- if (node->hasAttribute("heading_height"))
- {
- S32 heading_height;
- node->getAttributeS32("heading_height", heading_height);
- scroll_list->setHeadingHeight(heading_height);
- }
-
- scroll_list->setScrollListParameters(node);
-
- scroll_list->initFromXML(node, parent);
-
- scroll_list->setSearchColumn(search_column);
-
- if (sort_column >= 0)
- {
- scroll_list->sortByColumn(sort_column, sort_ascending);
- }
-
- LLSD columns;
- S32 index = 0;
- LLXMLNodePtr child;
- S32 total_static = 0;
- for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
- {
- if (child->hasName("column"))
- {
- LLString labelname("");
- child->getAttributeString("label", labelname);
-
- LLString columnname(labelname);
- child->getAttributeString("name", columnname);
-
- LLString sortname(columnname);
- child->getAttributeString("sort", sortname);
-
- BOOL sort_ascending = TRUE;
- child->getAttributeBOOL("sort_ascending", sort_ascending);
-
- LLString imagename;
- child->getAttributeString("image", imagename);
-
- BOOL columndynamicwidth = FALSE;
- child->getAttributeBOOL("dynamicwidth", columndynamicwidth);
-
- S32 columnwidth = -1;
- child->getAttributeS32("width", columnwidth);
-
- LLString tooltip;
- child->getAttributeString("tool_tip", tooltip);
-
- if(!columndynamicwidth) total_static += llmax(0, columnwidth);
-
- F32 columnrelwidth = 0.f;
- child->getAttributeF32("relwidth", columnrelwidth);
-
- LLFontGL::HAlign h_align = LLFontGL::LEFT;
- h_align = LLView::selectFontHAlign(child);
-
- columns[index]["name"] = columnname;
- columns[index]["sort"] = sortname;
- columns[index]["sort_ascending"] = sort_ascending;
- columns[index]["image"] = imagename;
- columns[index]["label"] = labelname;
- columns[index]["width"] = columnwidth;
- columns[index]["relwidth"] = columnrelwidth;
- columns[index]["dynamicwidth"] = columndynamicwidth;
- columns[index]["halign"] = (S32)h_align;
- columns[index]["tool_tip"] = tooltip;
-
- index++;
- }
- }
- scroll_list->setTotalStaticColumnWidth(total_static);
- scroll_list->setColumnHeadings(columns);
-
- for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
- {
- if (child->hasName("row"))
- {
- LLUUID id;
- child->getAttributeUUID("id", id);
-
- LLSD row;
-
- row["id"] = id;
-
- S32 column_idx = 0;
- LLXMLNodePtr row_child;
- for (row_child = child->getFirstChild(); row_child.notNull(); row_child = row_child->getNextSibling())
- {
- if (row_child->hasName("column"))
- {
- LLString value = row_child->getTextContents();
-
- LLString columnname("");
- row_child->getAttributeString("name", columnname);
-
- LLString font("");
- row_child->getAttributeString("font", font);
-
- LLString font_style("");
- row_child->getAttributeString("font-style", font_style);
-
- row["columns"][column_idx]["column"] = columnname;
- row["columns"][column_idx]["value"] = value;
- row["columns"][column_idx]["font"] = font;
- row["columns"][column_idx]["font-style"] = font_style;
- column_idx++;
- }
- }
- scroll_list->addElement(row);
- }
- }
-
- LLString contents = node->getTextContents();
- if (!contents.empty())
- {
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("\t\n");
- tokenizer tokens(contents, sep);
- tokenizer::iterator token_iter = tokens.begin();
-
- while(token_iter != tokens.end())
- {
- const char* line = token_iter->c_str();
- scroll_list->addSimpleElement(line);
- ++token_iter;
- }
- }
-
- return scroll_list;
+ mTotalStaticColumnWidth += llmax(0, new_width) - llmax(0, col->getWidth());
}
// LLEditMenuHandler functions
@@ -2927,7 +2507,7 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
// virtual
void LLScrollListCtrl::copy()
{
- LLString buffer;
+ std::string buffer;
std::vector<LLScrollListItem*> items = getAllSelected();
std::vector<LLScrollListItem*>::iterator itor;
@@ -2997,73 +2577,87 @@ BOOL LLScrollListCtrl::canDeselect() const
void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
{
- LLString name = column["name"].asString();
+ LLScrollListColumn::Params p;
+ LLParamSDParser::instance().readSD(column, p);
+ addColumn(p, pos);
+}
+
+void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params, EAddPosition pos)
+{
+ if (!column_params.validateBlock()) return;
+
+ std::string name = column_params.name;
// if no column name provided, just use ordinal as name
if (name.empty())
{
- std::ostringstream new_name;
- new_name << mColumnsIndexed.size();
- name = new_name.str();
+ name = llformat("%d", mColumnsIndexed.size());
}
+
if (mColumns.find(name) == mColumns.end())
{
// Add column
- mColumns[name] = LLScrollListColumn(column);
+ mColumns[name] = LLScrollListColumn(column_params, this);
LLScrollListColumn* new_column = &mColumns[name];
- new_column->mParentCtrl = this;
new_column->mIndex = mColumns.size()-1;
// Add button
- if (new_column->mWidth > 0 || new_column->mRelWidth > 0 || new_column->mDynamicWidth)
+ if (new_column->getWidth() > 0 || new_column->mRelWidth > 0 || new_column->mDynamicWidth)
{
+ if (getNumColumns() > 0)
+ {
+ mTotalColumnPadding += mColumnPadding;
+ }
if (new_column->mRelWidth >= 0)
{
- new_column->mWidth = (S32)llround(new_column->mRelWidth*mItemListRect.getWidth());
+ new_column->setWidth((S32)llround(new_column->mRelWidth*mItemListRect.getWidth()));
}
else if(new_column->mDynamicWidth)
{
mNumDynamicWidthColumns++;
- new_column->mWidth = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
+ new_column->setWidth((mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns);
}
S32 top = mItemListRect.mTop;
+
S32 left = mItemListRect.mLeft;
+ for (std::map<std::string, LLScrollListColumn>::iterator itor = mColumns.begin();
+ itor != mColumns.end();
+ ++itor)
{
- std::map<LLString, LLScrollListColumn>::iterator itor;
- for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
+ if (itor->second.mIndex < new_column->mIndex &&
+ itor->second.getWidth() > 0)
{
- if (itor->second.mIndex < new_column->mIndex &&
- itor->second.mWidth > 0)
- {
- left += itor->second.mWidth + mColumnPadding;
- }
+ left += itor->second.getWidth() + mColumnPadding;
}
}
- LLString button_name = "btn_" + name;
- S32 right = left+new_column->mWidth;
+
+ S32 right = left+new_column->getWidth();
if (new_column->mIndex != (S32)mColumns.size()-1)
{
right += mColumnPadding;
}
+
LLRect temp_rect = LLRect(left,top+mHeadingHeight,right,top);
- new_column->mHeader = new LLColumnHeader(button_name, temp_rect, new_column);
- if(column["image"].asString() != "")
+
+ LLScrollColumnHeader::Params params(LLUICtrlFactory::getDefaultParams<LLScrollColumnHeader>());
+ params.name = "btn_" + name;
+ params.rect = temp_rect;
+ params.column = new_column;
+ params.tool_tip = column_params.tool_tip;
+ params.tab_stop = false;
+ params.visible = mDisplayColumnHeaders;
+
+ if(column_params.header.image.isProvided())
{
- //new_column->mHeader->setScaleImage(false);
- new_column->mHeader->setImage(column["image"].asString());
+ params.image_selected = column_params.header.image;
+ params.image_unselected = column_params.header.image;
}
else
{
- new_column->mHeader->setLabel(new_column->mLabel);
- //new_column->mHeader->setLabel(new_column->mLabel);
+ params.label = column_params.header.label;
}
- new_column->mHeader->setToolTip(column["tool_tip"].asString());
-
- //RN: although it might be useful to change sort order with the keyboard,
- // mixing tab stops on child items along with the parent item is not supported yet
- new_column->mHeader->setTabStop(FALSE);
+ new_column->mHeader = LLUICtrlFactory::create<LLScrollColumnHeader>(params);
addChild(new_column->mHeader);
- new_column->mHeader->setVisible(mDisplayColumnHeaders);
sendChildToFront(mScrollbar);
}
@@ -3084,7 +2678,7 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
S32 column_index = info->mIndex;
LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex];
- bool ascending = column->mSortAscending;
+ bool ascending = column->mSortDirection == LLScrollListColumn::ASCENDING;
if (column->mSortingColumn != column->mName
&& parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end())
{
@@ -3099,11 +2693,11 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
ascending = !parent->mSortColumns.back().second;
}
- parent->sortByColumn(column_index, ascending);
+ parent->sortByColumnIndex(column_index, ascending);
if (parent->mOnSortChangedCallback)
{
- parent->mOnSortChangedCallback(parent->getCallbackUserData());
+ parent->mOnSortChangedCallback();
}
}
@@ -3115,17 +2709,17 @@ std::string LLScrollListCtrl::getSortColumnName()
else return "";
}
-BOOL LLScrollListCtrl::needsSorting()
+BOOL LLScrollListCtrl::hasSortOrder() const
{
return !mSortColumns.empty();
}
void LLScrollListCtrl::clearColumns()
{
- std::map<LLString, LLScrollListColumn>::iterator itor;
+ std::map<std::string, LLScrollListColumn>::iterator itor;
for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
{
- LLColumnHeader *header = itor->second.mHeader;
+ LLScrollColumnHeader *header = itor->second.mHeader;
if (header)
{
removeChild(header);
@@ -3134,17 +2728,19 @@ void LLScrollListCtrl::clearColumns()
}
mColumns.clear();
mSortColumns.clear();
+ mTotalStaticColumnWidth = 0;
+ mTotalColumnPadding = 0;
}
-void LLScrollListCtrl::setColumnLabel(const LLString& column, const LLString& label)
+void LLScrollListCtrl::setColumnLabel(const std::string& column, const std::string& label)
{
- std::map<LLString, LLScrollListColumn>::iterator itor = mColumns.find(column);
- if (itor != mColumns.end())
+ LLScrollListColumn* columnp = getColumn(column);
+ if (columnp)
{
- itor->second.mLabel = label;
- if (itor->second.mHeader)
+ columnp->mLabel = label;
+ if (columnp->mHeader)
{
- itor->second.mHeader->setLabel(label);
+ columnp->mHeader->setLabel(label);
}
}
}
@@ -3158,74 +2754,66 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(S32 index)
return mColumnsIndexed[index];
}
-void LLScrollListCtrl::setColumnHeadings(LLSD headings)
+LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name)
{
- mColumns.clear();
- LLSD::array_const_iterator itor;
- for (itor = headings.beginArray(); itor != headings.endArray(); ++itor)
+ column_map_t::iterator column_itor = mColumns.find(name);
+ if (column_itor != mColumns.end())
{
- addColumn(*itor);
+ return &column_itor->second;
}
+ return NULL;
}
-LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition pos, void* userdata)
+
+LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata)
{
- // ID
- LLSD id = value["id"];
+ LLScrollListItem::Params item_params;
+ LLParamSDParser::instance().readSD(element, item_params);
+ item_params.userdata = userdata;
+ return addRow(item_params, pos);
+}
- LLScrollListItem *new_item = new LLScrollListItem(id, userdata);
- if (value.has("enabled"))
- {
- new_item->setEnabled( value["enabled"].asBoolean() );
- }
+LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos)
+{
+ LLScrollListItem *new_item = new LLScrollListItem(item_p);
+ return addRow(new_item, item_p, pos);
+}
+LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& item_p, EAddPosition pos)
+{
+ if (!item_p.validateBlock() || !new_item) return NULL;
new_item->setNumColumns(mColumns.size());
// Add any columns we don't already have
- LLSD columns = value["columns"];
- LLSD::array_const_iterator itor;
- S32 col_index = 0 ;
- for (itor = columns.beginArray(); itor != columns.endArray(); ++itor)
- {
- if (itor->isUndefined())
- {
- // skip unused columns in item passed in
- continue;
- }
- LLString column = (*itor)["column"].asString();
+ S32 col_index = 0;
- LLScrollListColumn* columnp = NULL;
+ for(LLInitParam::ParamIterator<LLScrollListCell::Params>::const_iterator itor = item_p.columns().begin();
+ itor != item_p.columns().end();
+ ++itor)
+ {
+ LLScrollListCell::Params cell_p = *itor;
+ std::string column = cell_p.column;
// empty columns strings index by ordinal
if (column.empty())
{
- std::ostringstream new_name;
- new_name << col_index;
- column = new_name.str();
+ column = llformat("%d", col_index);
}
- std::map<LLString, LLScrollListColumn>::iterator column_itor;
- column_itor = mColumns.find(column);
- if (column_itor != mColumns.end())
- {
- columnp = &column_itor->second;
- }
+ LLScrollListColumn* columnp = getColumn(column);
// create new column on demand
if (!columnp)
{
- LLSD new_column;
- new_column["name"] = column;
- new_column["label"] = column;
+ LLScrollListColumn::Params new_column;
+ new_column.name = column;
+ new_column.header.label = column;
+
// if width supplied for column, use it, otherwise
// use adaptive width
- if (itor->has("width"))
+ if (cell_p.width.isProvided())
{
- new_column["width"] = (*itor)["width"];
- }
- else
- {
- new_column["dynamicwidth"] = true;
+ new_column.width.pixel_width = cell_p.width;
}
addColumn(new_column);
columnp = &mColumns[column];
@@ -3233,70 +2821,48 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
}
S32 index = columnp->mIndex;
- S32 width = columnp->mWidth;
- LLFontGL::HAlign font_alignment = columnp->mFontAlignment;
+ cell_p.width.setIfNotProvided(columnp->getWidth());
- LLSD value = (*itor)["value"];
- LLString fontname = (*itor)["font"].asString();
- LLString fontstyle = (*itor)["font-style"].asString();
- LLString type = (*itor)["type"].asString();
- BOOL has_color = (*itor).has("color");
- LLColor4 color = ((*itor)["color"]);
- BOOL enabled = !(*itor).has("enabled") || (*itor)["enabled"].asBoolean() == true;
+ LLScrollListCell* cell = LLScrollListCell::create(cell_p);
- const LLFontGL *font = LLResMgr::getInstance()->getRes(fontname);
- if (!font)
+ if (cell)
{
- font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL );
- }
- U8 font_style = LLFontGL::getStyleFromString(fontstyle);
-
- if (type == "icon")
- {
- LLScrollListIcon* cell = new LLScrollListIcon(value, width);
- if (has_color)
- {
- cell->setColor(color);
- }
new_item->setColumn(index, cell);
- }
- else if (type == "checkbox")
- {
- LLCheckBoxCtrl* ctrl = new LLCheckBoxCtrl("check",
- LLRect(0, width, width, 0), " ");
- ctrl->setEnabled(enabled);
- ctrl->setValue(value);
- LLScrollListCheck* cell = new LLScrollListCheck(ctrl,width);
- if (has_color)
+ if (columnp->mHeader
+ && cell->isText()
+ && !cell->getValue().asString().empty())
{
- cell->setColor(color);
+ columnp->mHeader->setHasResizableElement(TRUE);
}
- new_item->setColumn(index, cell);
}
- else if (type == "separator")
+
+ col_index++;
+ }
+
+ if (item_p.columns().empty())
+ {
+ if (mColumns.empty())
{
- LLScrollListSeparator* cell = new LLScrollListSeparator(width);
- if (has_color)
- {
- cell->setColor(color);
- }
- new_item->setColumn(index, cell);
+ LLScrollListColumn::Params new_column;
+ new_column.name = "0";
+
+ addColumn(new_column);
+ new_item->setNumColumns(mColumns.size());
}
- else
+
+ LLScrollListCell* cell = LLScrollListCell::create(LLScrollListCell::Params().value(item_p.value));
+ if (cell)
{
- LLScrollListText* cell = new LLScrollListText(value.asString(), font, width, font_style, font_alignment);
- if (has_color)
- {
- cell->setColor(color);
- }
- new_item->setColumn(index, cell);
- if (columnp->mHeader && !value.asString().empty())
+ LLScrollListColumn* columnp = &(mColumns.begin()->second);
+
+ new_item->setColumn(0, cell);
+ if (columnp->mHeader
+ && cell->isText()
+ && !cell->getValue().asString().empty())
{
columnp->mHeader->setHasResizableElement(TRUE);
}
}
-
- col_index++;
}
// add dummy cells for missing columns
@@ -3306,16 +2872,18 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
if (new_item->getColumn(column_idx) == NULL)
{
LLScrollListColumn* column_ptr = &column_it->second;
- new_item->setColumn(column_idx, new LLScrollListText("", LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ), column_ptr->mWidth, LLFontGL::NORMAL));
+ LLScrollListCell::Params cell_p;
+ cell_p.width = column_ptr->getWidth();
+
+ new_item->setColumn(column_idx, new LLScrollListSpacer(cell_p));
}
}
addItem(new_item, pos);
-
return new_item;
}
-LLScrollListItem* LLScrollListCtrl::addSimpleElement(const LLString& value, EAddPosition pos, const LLSD& id)
+LLScrollListItem* LLScrollListCtrl::addSimpleElement(const std::string& value, EAddPosition pos, const LLSD& id)
{
LLSD entry_id = id;
@@ -3324,14 +2892,13 @@ LLScrollListItem* LLScrollListCtrl::addSimpleElement(const LLString& value, EAdd
entry_id = value;
}
- LLScrollListItem *new_item = new LLScrollListItem(entry_id);
-
- const LLFontGL *font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL );
-
- new_item->addColumn(value, font, getRect().getWidth());
-
- addItem(new_item, pos);
- return new_item;
+ LLScrollListItem::Params item_params;
+ item_params.value(entry_id);
+ item_params.columns.add()
+ .value(value)
+ .font(LLFontGL::getFontSansSerifSmall());
+
+ return addRow(item_params, pos);
}
void LLScrollListCtrl::setValue(const LLSD& value )
@@ -3384,7 +2951,6 @@ BOOL LLScrollListCtrl::operateOnAll(EOperation op)
//virtual
void LLScrollListCtrl::setFocus(BOOL b)
{
- mSearchString.clear();
// for tabbing into pristine scroll lists (Finder)
if (!getFirstSelected())
{
@@ -3429,406 +2995,9 @@ void LLScrollListCtrl::onFocusLost()
{
gFocusMgr.setMouseCapture(NULL);
}
- LLUICtrl::onFocusLost();
-}
-
-LLColumnHeader::LLColumnHeader(const LLString& label, const LLRect &rect, LLScrollListColumn* column, const LLFontGL* fontp) :
- LLComboBox(label, rect, label, NULL, NULL),
- mColumn(column),
- mOrigLabel(label),
- mShowSortOptions(FALSE),
- mHasResizableElement(FALSE)
-{
- mListPosition = LLComboBox::ABOVE;
- setCommitCallback(onSelectSort);
- setCallbackUserData(this);
- mButton->setTabStop(FALSE);
- // require at least two frames between mouse down and mouse up event to capture intentional "hold" not just bad framerate
- mButton->setHeldDownDelay(LLUI::sConfigGroup->getF32("ColumnHeaderDropDownDelay"), 2);
- mButton->setHeldDownCallback(onHeldDown);
- mButton->setClickedCallback(onClick);
- mButton->setMouseDownCallback(onMouseDown);
-
- mButton->setCallbackUserData(this);
-
- mAscendingText = "[LOW]...[HIGH](Ascending)";
- mDescendingText = "[HIGH]...[LOW](Descending)";
-
- mList->reshape(llmax(mList->getRect().getWidth(), 110, getRect().getWidth()), mList->getRect().getHeight());
-
- // resize handles on left and right
- const S32 RESIZE_BAR_THICKNESS = 3;
- mResizeBar = new LLResizeBar(
- "resizebar",
- this,
- LLRect( getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0),
- MIN_COLUMN_WIDTH, S32_MAX, LLResizeBar::RIGHT );
- addChild(mResizeBar);
-
- mResizeBar->setEnabled(FALSE);
-}
-
-LLColumnHeader::~LLColumnHeader()
-{
-}
-
-void LLColumnHeader::draw()
-{
- BOOL draw_arrow = !mColumn->mLabel.empty() && mColumn->mParentCtrl->isSorted() && mColumn->mParentCtrl->getSortColumnName() == mColumn->mSortingColumn;
-
- BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
- mButton->setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, draw_arrow ? LLColor4::white : LLColor4::transparent);
- mArrowImage = mButton->getImageOverlay();
-
- //BOOL clip = getRect().mRight > mColumn->mParentCtrl->getItemListRect().getWidth();
- //LLGLEnable scissor_test(clip ? GL_SCISSOR_TEST : GL_FALSE);
-
- //LLRect column_header_local_rect(-getRect().mLeft, getRect().getHeight(), mColumn->mParentCtrl->getItemListRect().getWidth() - getRect().mLeft, 0);
- //LLUI::setScissorRegionLocal(column_header_local_rect);
-
- // Draw children
- LLComboBox::draw();
-
- if (mList->getVisible())
- {
- // sync sort order with list selection every frame
- mColumn->mParentCtrl->sortByColumn(mColumn->mSortingColumn, getCurrentIndex() == 0);
- }
-}
-BOOL LLColumnHeader::handleDoubleClick(S32 x, S32 y, MASK mask)
-{
- if (canResize() && mResizeBar->getRect().pointInRect(x, y))
- {
- // reshape column to max content width
- LLRect column_rect = getRect();
- column_rect.mRight = column_rect.mLeft + mColumn->mMaxContentWidth;
- userSetShape(column_rect);
- }
- else
- {
- onClick(this);
- }
- return TRUE;
-}
-
-void LLColumnHeader::setImage(const LLString &image_name)
-{
- if (mButton)
- {
- mButton->setImageSelected(image_name);
- mButton->setImageUnselected(image_name);
- }
-}
-
-//static
-void LLColumnHeader::onClick(void* user_data)
-{
- LLColumnHeader* headerp = (LLColumnHeader*)user_data;
- if (!headerp) return;
-
- LLScrollListColumn* column = headerp->mColumn;
- if (!column) return;
-
- if (headerp->mList->getVisible())
- {
- headerp->hideList();
- }
-
- LLScrollListCtrl::onClickColumn(column);
-
- // propage new sort order to sort order list
- headerp->mList->selectNthItem(column->mParentCtrl->getSortAscending() ? 0 : 1);
-}
-
-//static
-void LLColumnHeader::onMouseDown(void* user_data)
-{
- // for now, do nothing but block the normal showList() behavior
- return;
-}
-
-//static
-void LLColumnHeader::onHeldDown(void* user_data)
-{
- LLColumnHeader* headerp = (LLColumnHeader*)user_data;
- headerp->showList();
-}
-
-void LLColumnHeader::showList()
-{
- if (mShowSortOptions)
- {
- //LLSD item_val = mColumn->mParentCtrl->getFirstData()->getValue();
- mOrigLabel = mButton->getLabelSelected();
-
- // move sort column over to this column and do initial sort
- mColumn->mParentCtrl->sortByColumn(mColumn->mSortingColumn, mColumn->mParentCtrl->getSortAscending());
-
- LLString low_item_text;
- LLString high_item_text;
-
- LLScrollListItem* itemp = mColumn->mParentCtrl->getFirstData();
- if (itemp)
- {
- LLScrollListCell* cell = itemp->getColumn(mColumn->mIndex);
- if (cell && cell->isText())
- {
- if (mColumn->mParentCtrl->getSortAscending())
- {
- low_item_text = cell->getValue().asString();
- }
- else
- {
- high_item_text = cell->getValue().asString();
- }
- }
- }
-
- itemp = mColumn->mParentCtrl->getLastData();
- if (itemp)
- {
- LLScrollListCell* cell = itemp->getColumn(mColumn->mIndex);
- if (cell && cell->isText())
- {
- if (mColumn->mParentCtrl->getSortAscending())
- {
- high_item_text = cell->getValue().asString();
- }
- else
- {
- low_item_text = cell->getValue().asString();
- }
- }
- }
-
- LLString::truncate(low_item_text, 3);
- LLString::truncate(high_item_text, 3);
-
- LLString ascending_string;
- LLString descending_string;
-
- if (low_item_text.empty() || high_item_text.empty())
- {
- ascending_string = "Ascending";
- descending_string = "Descending";
- }
- else
- {
- mAscendingText.setArg("[LOW]", low_item_text);
- mAscendingText.setArg("[HIGH]", high_item_text);
- mDescendingText.setArg("[LOW]", low_item_text);
- mDescendingText.setArg("[HIGH]", high_item_text);
- ascending_string = mAscendingText.getString();
- descending_string = mDescendingText.getString();
- }
-
- S32 text_width = LLFontGL::sSansSerifSmall->getWidth(ascending_string);
- text_width = llmax(text_width, LLFontGL::sSansSerifSmall->getWidth(descending_string)) + 10;
- text_width = llmax(text_width, getRect().getWidth() - 30);
-
- mList->getColumn(0)->mWidth = text_width;
- ((LLScrollListText*)mList->getFirstData()->getColumn(0))->setText(ascending_string);
- ((LLScrollListText*)mList->getLastData()->getColumn(0))->setText(descending_string);
-
- mList->reshape(llmax(text_width + 30, 110, getRect().getWidth()), mList->getRect().getHeight());
-
- LLComboBox::showList();
- }
-}
-
-//static
-void LLColumnHeader::onSelectSort(LLUICtrl* ctrl, void* user_data)
-{
- LLColumnHeader* headerp = (LLColumnHeader*)user_data;
- if (!headerp) return;
-
- LLScrollListColumn* column = headerp->mColumn;
- if (!column) return;
- LLScrollListCtrl *parent = column->mParentCtrl;
- if (!parent) return;
-
- if (headerp->getCurrentIndex() == 0)
- {
- // ascending
- parent->sortByColumn(column->mSortingColumn, TRUE);
- }
- else
- {
- // descending
- parent->sortByColumn(column->mSortingColumn, FALSE);
- }
-
- // restore original column header
- headerp->setLabel(headerp->mOrigLabel);
-}
-
-LLView* LLColumnHeader::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding)
-{
- // this logic assumes dragging on right
- llassert(snap_edge == SNAP_RIGHT);
-
- // use higher snap threshold for column headers
- threshold = llmin(threshold, 15);
-
- LLRect snap_rect = getSnapRect();
-
- S32 snap_delta = mColumn->mMaxContentWidth - snap_rect.getWidth();
-
- // x coord growing means column growing, so same signs mean we're going in right direction
- if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 )
- {
- new_edge_val = snap_rect.mRight + snap_delta;
- }
- else
- {
- LLScrollListColumn* next_column = mColumn->mParentCtrl->getColumn(mColumn->mIndex + 1);
- while (next_column)
- {
- if (next_column->mHeader)
- {
- snap_delta = (next_column->mHeader->getSnapRect().mRight - next_column->mMaxContentWidth) - snap_rect.mRight;
- if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 )
- {
- new_edge_val = snap_rect.mRight + snap_delta;
- }
- break;
- }
- next_column = mColumn->mParentCtrl->getColumn(next_column->mIndex + 1);
- }
- }
-
- return this;
-}
-
-void LLColumnHeader::userSetShape(const LLRect& new_rect)
-{
- S32 new_width = new_rect.getWidth();
- S32 delta_width = new_width - (getRect().getWidth() /*+ mColumn->mParentCtrl->getColumnPadding()*/);
-
- if (delta_width != 0)
- {
- S32 remaining_width = delta_width;
- S32 col;
- for (col = mColumn->mIndex + 1; col < mColumn->mParentCtrl->getNumColumns(); col++)
- {
- LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
- if (!columnp) break;
-
- if (columnp->mHeader && columnp->mHeader->canResize())
- {
- // how many pixels in width can this column afford to give up?
- S32 resize_buffer_amt = llmax(0, columnp->mWidth - MIN_COLUMN_WIDTH);
-
- // user shrinking column, need to add width to other columns
- if (delta_width < 0)
- {
- if (!columnp->mDynamicWidth && columnp->mWidth > 0)
- {
- // statically sized column, give all remaining width to this column
- columnp->mWidth -= remaining_width;
- if (columnp->mRelWidth > 0.f)
- {
- columnp->mRelWidth = (F32)columnp->mWidth / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
- }
- }
- break;
- }
- else
- {
- // user growing column, need to take width from other columns
- remaining_width -= resize_buffer_amt;
-
- if (!columnp->mDynamicWidth && columnp->mWidth > 0)
- {
- columnp->mWidth -= llmin(columnp->mWidth - MIN_COLUMN_WIDTH, delta_width);
- if (columnp->mRelWidth > 0.f)
- {
- columnp->mRelWidth = (F32)columnp->mWidth / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
- }
- }
-
- if (remaining_width <= 0)
- {
- // width sucked up from neighboring columns, done
- break;
- }
- }
- }
- }
-
- // clamp resize amount to maximum that can be absorbed by other columns
- if (delta_width > 0)
- {
- delta_width -= llmax(remaining_width, 0);
- }
-
- // propagate constrained delta_width to new width for this column
- new_width = getRect().getWidth() + delta_width - mColumn->mParentCtrl->getColumnPadding();
-
- // use requested width
- mColumn->mWidth = new_width;
-
- // update proportional spacing
- if (mColumn->mRelWidth > 0.f)
- {
- mColumn->mRelWidth = (F32)new_width / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
- }
-
- // tell scroll list to layout columns again
- // do immediate update to get proper feedback to resize handle
- // which needs to know how far the resize actually went
- mColumn->mParentCtrl->updateColumns();
- }
-}
-
-void LLColumnHeader::setHasResizableElement(BOOL resizable)
-{
- // for now, dynamically spaced columns can't be resized
- if (mColumn->mDynamicWidth) return;
-
- if (resizable != mHasResizableElement)
- {
- mHasResizableElement = resizable;
-
- S32 num_resizable_columns = 0;
- S32 col;
- for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
- {
- LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
- if (columnp->mHeader && columnp->mHeader->canResize())
- {
- num_resizable_columns++;
- }
- }
-
- S32 num_resizers_enabled = 0;
-
- // now enable/disable resize handles on resizable columns if we have at least two
- for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
- {
- LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
- if (!columnp->mHeader) continue;
- BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize();
- columnp->mHeader->enableResizeBar(enable);
- if (enable)
- {
- num_resizers_enabled++;
- }
- }
- }
-}
+ mSearchString.clear();
-void LLColumnHeader::enableResizeBar(BOOL enable)
-{
- // for now, dynamically spaced columns can't be resized
- if (!mColumn->mDynamicWidth)
- {
- mResizeBar->setEnabled(enable);
- }
+ LLUICtrl::onFocusLost();
}
-BOOL LLColumnHeader::canResize()
-{
- return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth);
-}