From 9ec432034dc3c45d7ce763eb02dae4cc7f6b8da8 Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Sun, 21 Jun 2009 08:04:56 +0000 Subject: merge -r 122421-124917 viewer-2.0.0-2 -> viewer-2.0.0-3 ignore-dead-branch --- indra/llui/llscrolllistctrl.cpp | 1886 ++++++++------------------------------- 1 file changed, 367 insertions(+), 1519 deletions(-) (limited to 'indra/llui/llscrolllistctrl.cpp') diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 5dd4e2d0ee..42c7c892c8 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1,6 +1,7 @@ /** * @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$ * @@ -30,34 +31,38 @@ * $/LicenseInfo$ */ -#include +#define INSTANTIATE_GETCHILD_SCROLLLIST #include "linden_common.h" -#include "llstl.h" -#include "llboost.h" #include "llscrolllistctrl.h" -#include "indra_constants.h" +#include + +#include "llstl.h" +#include "llboost.h" +//#include "indra_constants.h" #include "llcheckboxctrl.h" #include "llclipboard.h" #include "llfocusmgr.h" -#include "llrender.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" -const S32 MIN_COLUMN_WIDTH = 20; -const S32 LIST_SNAP_PADDING = 5; +template LLScrollListCtrl* LLView::getChild( const std::string& name, BOOL recurse, BOOL create_if_missing ) const; -static LLRegisterWidget r("scroll_list"); +static LLDefaultWidgetRegistry::Register r("scroll_list"); // local structures & classes. struct SortScrollListItem @@ -96,510 +101,89 @@ struct SortScrollListItem 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 - { - std::string 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 std::string& 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); -} - -LLScrollListDate::LLScrollListDate( const LLDate& date, const LLFontGL* font, S32 width, U8 font_style, LLFontGL::HAlign font_alignment, LLColor4& color, BOOL use_color, BOOL visible) -: LLScrollListText(date.asRFC1123(), font, width, font_style, font_alignment, color, use_color, visible), - mDate(date) -{ -} - -void LLScrollListDate::setValue(const LLSD& value) -{ - mDate = value.asDate(); - LLScrollListText::setValue(mDate.asRFC1123()); -} - -const LLSD LLScrollListDate::getValue() const -{ - return mDate; -} - -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; - } -} - -std::string LLScrollListItem::getContentsCSV() const -{ - std::string ret; - - S32 count = getNumColumns(); - for (S32 i=0; igetValue().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; - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_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 std::string& 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 std::string& 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("columns"), + rows("rows") +{ + addSynonym(columns, "column"); + addSynonym(rows, "row"); +} + +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), + commit_on_keyboard_movement("commit_on_keyboard_movement", true), + heading_height("heading_height"), + 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_read_only_color("bg_read_only_color"), + bg_stripe_color("bg_stripe_color"), + hovered_color("hovered_color"), + highlighted_color("highlighted_color") +{ + name = "scroll_list"; + mouse_opaque = true; +} + +LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) +: LLUICtrl(p), mLineHeight(0), mScrollLines(0), mPageLines(0), - mHeadingHeight(20), 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), mNumDynamicWidthColumns(0), mTotalStaticColumnWidth(0), mTotalColumnPadding(0), - mSorted(TRUE), + mSorted(FALSE), mDirty(FALSE), mOriginalSelection(-1), - mDrewSelected(FALSE) + 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_read_only_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) { mItemListRect.setOriginAndSize( mBorderThickness, @@ -612,37 +196,73 @@ LLScrollListCtrl::LLScrollListCtrl(const std::string& name, const LLRect& rect, mPageLines = mLineHeight? (mItemListRect.getHeight()) / mLineHeight : 0; // Init the scrollbar + static LLUICachedControl 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( std::string("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(mPageLines); + sbparams.change_callback(boost::bind(&LLScrollListCtrl::onScrollChange, this, _1, _2)); + sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); + sbparams.visible(false); + mScrollbar = LLUICtrlFactory::create (sbparams); addChild(mScrollbar); // Border - if (show_border) - { - LLRect border_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - mBorder = new LLViewBorder( std::string("dlg border"), border_rect, LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, 1 ); + if (p.has_border) + { + LLRect border_rect = getLocalRect(); + LLViewBorder::Params params; + params.name("dig border"); + params.rect(border_rect); + params.bevel_type(LLViewBorder::BEVEL_IN); + mBorder = LLUICtrlFactory::create (params); addChild(mBorder); } - mColumnPadding = 5; + // set border *after* rect is fully initialized + if (mBorder) + { + mBorder->setRect(getLocalRect()); + mBorder->reshape(getRect().getWidth(), getRect().getHeight()); + } + + if (p.sort_column >= 0) + { + sortByColumnIndex(p.sort_column, p.sort_ascending); + } - mLastSelected = NULL; + + for (LLInitParam::ParamIterator::const_iterator row_it = p.contents.columns().begin(); + row_it != p.contents.columns().end(); + ++row_it) + { + addColumn(*row_it); + } + + for (LLInitParam::ParamIterator::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); + addChild(LLUICtrlFactory::create(text_p)); } S32 LLScrollListCtrl::getSearchColumn() @@ -666,6 +286,18 @@ S32 LLScrollListCtrl::getSearchColumn() } 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() { @@ -818,6 +450,7 @@ void LLScrollListCtrl::reshape( S32 width, S32 height, BOOL called_from_parent ) void LLScrollListCtrl::updateLayout() { + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); // reserve room for column headers, if needed S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0); mItemListRect.setOriginAndSize( @@ -826,22 +459,19 @@ 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; if (scrollbar_visible) { // provide space on the right for scrollbar - mItemListRect.mRight = getRect().getWidth() - mBorderThickness - SCROLLBAR_SIZE; + mItemListRect.mRight = getRect().getWidth() - mBorderThickness - scrollbar_size; } - // don't allow scrolling off bottom - if (mScrollLines + mPageLines > getItemCount()) - { - setScrollPos(llmax(0, getItemCount() - mPageLines)); - } - - mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0)); + mScrollbar->setOrigin(getRect().getWidth() - mBorderThickness - scrollbar_size, mItemListRect.mBottom); + mScrollbar->reshape(scrollbar_size, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0)); mScrollbar->setPageSize( mPageLines ); mScrollbar->setDocSize( getItemCount() ); mScrollbar->setVisible(scrollbar_visible); @@ -916,11 +546,11 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r // 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); @@ -1017,7 +647,7 @@ void LLScrollListCtrl::updateColumns() // update column headers std::vector::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)->getWidth() < 0) @@ -1052,7 +682,7 @@ void LLScrollListCtrl::updateColumns() } // expand last column header we encountered to full list width - if (last_header && last_header->canResize()) + if (last_header) { S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft); last_header->reshape(new_width, last_header->getRect().getHeight()); @@ -1077,13 +707,6 @@ void LLScrollListCtrl::updateColumns() } -void LLScrollListCtrl::setDisplayHeading(BOOL display) -{ - mDisplayColumnHeaders = display; - - updateLayout(); -} - void LLScrollListCtrl::setHeadingHeight(S32 heading_height) { mHeadingHeight = heading_height; @@ -1275,7 +898,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) { @@ -1283,14 +914,14 @@ void LLScrollListCtrl::highlightNthItem(S32 target_index) } } -S32 LLScrollListCtrl::selectMultiple( LLDynamicArray ids ) +S32 LLScrollListCtrl::selectMultiple( std::vector ids ) { item_list::iterator iter; S32 count = 0; for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; - LLDynamicArray::iterator iditr; + std::vector::iterator iditr; for(iditr = ids.begin(); iditr != ids.end(); ++iditr) { if (item->getEnabled() && (item->getUUID() == (*iditr))) @@ -1446,35 +1077,51 @@ 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 std::string& 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("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 cell_params; + cell_params.type = "icon"; + cell_params.value = "menu_separator"; + cell_params.color = LLColor4(0.f, 0.f, 0.f, 0.7f); + cell_params.font_halign = LLFontGL::HCENTER; + separator_params.cells.add(cell_params); + return addRow( separator_params, pos ); } // Selects first enabled item of the given name. // Returns false if item not found. +// 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); + } + + if (mCommitOnSelectionChange) + { + commitIfChanged(); + } + + 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; @@ -1483,34 +1130,21 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen LLStringUtil::toLower(target_text); } - BOOL found = FALSE; - 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 - std::string 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) { 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; } @@ -1614,14 +1248,16 @@ const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const LLScrollListItem* LLScrollListCtrl::addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos, BOOL enabled, S32 column_width) { - 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.cells.add().value(item_text).width(column_width).type("text"); + + return addRow( item_p, pos ); } - return item; + return NULL; } // Select the line or lines that match this UUID @@ -1726,7 +1362,7 @@ void LLScrollListCtrl::drawItems() S32 max_columns = 0; LLColor4 highlight_color = LLColor4::white; - F32 type_ahead_timeout = LLUI::sConfigGroup->getF32("TypeAheadTimeout"); + static LLUICachedControl 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; @@ -1754,27 +1390,46 @@ 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); @@ -1807,8 +1462,7 @@ void LLScrollListCtrl::draw() if (mBackgroundVisible) { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4fv( getEnabled() ? mBgWriteableColor.mV : mBgReadOnlyColor.mV ); - gl_rect_2d(background); + gl_rect_2d(background, getEnabled() ? mBgWriteableColor.get() : mBgReadOnlyColor.get() ); } if (mColumnsDirty) @@ -1817,6 +1471,8 @@ void LLScrollListCtrl::draw() mColumnsDirty = FALSE; } + getChildView("comment_text")->setVisible(mItemList.empty()); + drawItems(); if (mBorder) @@ -1879,7 +1535,7 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sti } // 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); @@ -1922,7 +1578,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) { if(mOnMaximumSelectCallback) { - mOnMaximumSelectCallback(mCallbackUserData); + mOnMaximumSelectCallback(); } break; } @@ -1960,7 +1616,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) { if(mOnMaximumSelectCallback) { - mOnMaximumSelectCallback(mCallbackUserData); + mOnMaximumSelectCallback(); } } } @@ -2051,7 +1707,7 @@ BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask) { if( mCanSelect && mOnDoubleClickCallback ) { - mOnDoubleClickCallback( mCallbackUserData ); + mOnDoubleClickCallback(); } } } @@ -2221,11 +1877,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); } } @@ -2234,6 +1890,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 ) { @@ -2378,7 +2039,8 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char) } // perform incremental search based on keyboard input - if (mSearchTimer.getElapsedTimeF32() > LLUI::sConfigGroup->getF32("TypeAheadTimeout")) + static LLUICachedControl type_ahead_timeout ("TypeAheadTimeout", 0); + if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout) { mSearchString.clear(); } @@ -2554,7 +2216,7 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending) LLScrollListColumn* sort_column = getColumn(column_idx); if (!sort_column) return FALSE; - sort_column->mSortAscending = ascending; + sort_column->mSortDirection = ascending ? LLScrollListColumn::ASCENDING : LLScrollListColumn::DESCENDING; sort_column_t new_sort_column(column_idx, ascending); @@ -2579,11 +2241,9 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending) } // Called by scrollbar -//static -void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar, void* userdata ) +void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar ) { - LLScrollListCtrl* self = (LLScrollListCtrl*) userdata; - self->mScrollLines = new_pos; + mScrollLines = new_pos; } @@ -2656,7 +2316,7 @@ void LLScrollListCtrl::setScrollPos( S32 pos ) { mScrollbar->setDocPos( pos ); - onScrollChange(mScrollbar->getDocPos(), mScrollbar, this); + onScrollChange(mScrollbar->getDocPos(), mScrollbar); } @@ -2706,293 +2366,6 @@ void LLScrollListCtrl::updateStaticColumnWidth(LLScrollListColumn* col, S32 new_ mTotalStaticColumnWidth += llmax(0, new_width) - llmax(0, col->getWidth()); } - -// virtual -LLXMLNodePtr LLScrollListCtrl::getXML(bool save_children) const -{ - 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::const_iterator itor; - std::vector sorted_list; - sorted_list.resize(mColumns.size()); - for (itor = mColumns.begin(); itor != mColumns.end(); ++itor) - { - sorted_list[itor->second.mIndex] = &itor->second; - } - - std::vector::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->getWidth()); - } - - 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) -{ - std::string 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); - - LLSD columns; - S32 index = 0; - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("column")) - { - std::string labelname(""); - child->getAttributeString("label", labelname); - - std::string columnname(labelname); - child->getAttributeString("name", columnname); - - std::string sortname(columnname); - child->getAttributeString("sort", sortname); - - BOOL sort_ascending = TRUE; - child->getAttributeBOOL("sort_ascending", sort_ascending); - - std::string imagename; - child->getAttributeString("image", imagename); - - BOOL columndynamicwidth = FALSE; - child->getAttributeBOOL("dynamicwidth", columndynamicwidth); - - S32 columnwidth = -1; - child->getAttributeS32("width", columnwidth); - - std::string tooltip; - child->getAttributeString("tool_tip", tooltip); - - 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->setColumnHeadings(columns); - - if (sort_column >= 0) - { - scroll_list->sortByColumnIndex(sort_column, sort_ascending); - } - - 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")) - { - std::string value = row_child->getTextContents(); - - std::string columnname(""); - row_child->getAttributeString("name", columnname); - - std::string font(""); - row_child->getAttributeString("font", font); - - std::string 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); - } - } - - std::string contents = node->getTextContents(); - if (!contents.empty()) - { - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("\t\n"); - tokenizer tokens(contents, sep); - tokenizer::iterator token_iter = tokens.begin(); - - while(token_iter != tokens.end()) - { - const std::string& line = *token_iter; - scroll_list->addSimpleElement(line); - ++token_iter; - } - } - - return scroll_list; -} - // LLEditMenuHandler functions // virtual @@ -3068,20 +2441,27 @@ BOOL LLScrollListCtrl::canDeselect() const void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos) { - std::string 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, this); + mColumns[name] = LLScrollListColumn(column_params, this); LLScrollListColumn* new_column = &mColumns[name]; - new_column->mParentCtrl = this; new_column->mIndex = mColumns.size()-1; // Add button @@ -3101,44 +2481,47 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos) new_column->setWidth((mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns); } S32 top = mItemListRect.mTop; + S32 left = mItemListRect.mLeft; + for (std::map::iterator itor = mColumns.begin(); + itor != mColumns.end(); + ++itor) { - std::map::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.getWidth() > 0) - { - left += itor->second.getWidth() + mColumnPadding; - } + left += itor->second.getWidth() + mColumnPadding; } } - std::string button_name = "btn_" + name; + 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; + 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(params); addChild(new_column->mHeader); - new_column->mHeader->setVisible(mDisplayColumnHeaders); sendChildToFront(mScrollbar); } @@ -3159,7 +2542,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()) { @@ -3178,7 +2561,7 @@ void LLScrollListCtrl::onClickColumn(void *userdata) if (parent->mOnSortChangedCallback) { - parent->mOnSortChangedCallback(parent->getCallbackUserData()); + parent->mOnSortChangedCallback(); } } @@ -3200,7 +2583,7 @@ void LLScrollListCtrl::clearColumns() std::map::iterator itor; for (itor = mColumns.begin(); itor != mColumns.end(); ++itor) { - LLColumnHeader *header = itor->second.mHeader; + LLScrollColumnHeader *header = itor->second.mHeader; if (header) { removeChild(header); @@ -3215,13 +2598,13 @@ void LLScrollListCtrl::clearColumns() void LLScrollListCtrl::setColumnLabel(const std::string& column, const std::string& label) { - std::map::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); } } } @@ -3235,74 +2618,62 @@ 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) +{ + if (!item_p.validateBlock()) return NULL; + LLScrollListItem *new_item = new LLScrollListItem(item_p); 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; - } - std::string column = (*itor)["column"].asString(); + S32 col_index = 0; - LLScrollListColumn* columnp = NULL; + for(LLInitParam::ParamIterator::const_iterator itor = item_p.cells().begin(); + itor != item_p.cells().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::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")) - { - new_column["width"] = (*itor)["width"]; - } - else + if (cell_p.width.isProvided()) { - new_column["dynamicwidth"] = true; + new_column.width.pixel_width = cell_p.width; } addColumn(new_column); columnp = &mColumns[column]; @@ -3310,91 +2681,48 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p } S32 index = columnp->mIndex; - S32 width = columnp->getWidth(); - LLFontGL::HAlign font_alignment = columnp->mFontAlignment; - LLColor4 fcolor = LLColor4::black; - - LLSD value = (*itor)["value"]; - std::string fontname = (*itor)["font"].asString(); - std::string fontstyle = (*itor)["font-style"].asString(); - std::string type = (*itor)["type"].asString(); - - if ((*itor).has("font-color")) - { - LLSD sd_color = (*itor)["font-color"]; - fcolor.setValue(sd_color); - } - - BOOL has_color = (*itor).has("color"); - LLColor4 color = ((*itor)["color"]); - BOOL enabled = !(*itor).has("enabled") || (*itor)["enabled"].asBoolean() == true; + cell_p.width.setIfNotProvided(columnp->getWidth()); - const LLFontGL *font = LLResMgr::getInstance()->getRes(fontname); - if (!font) - { - font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ); - } - U8 font_style = LLFontGL::getStyleFromString(fontstyle); + LLScrollListCell* cell = LLScrollListCell::create(cell_p); - if (type == "icon") + if (cell) { - 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(std::string("check"), - LLRect(0, width, width, 0), std::string(" ")); - 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); - } - new_item->setColumn(index, cell); - } - else if (type == "separator") - { - LLScrollListSeparator* cell = new LLScrollListSeparator(width); - if (has_color) - { - cell->setColor(color); + columnp->mHeader->setHasResizableElement(TRUE); } - new_item->setColumn(index, cell); } - else if (type == "date") + + col_index++; + } + + if (item_p.cells().empty()) + { + if (mColumns.empty()) { - LLScrollListDate* cell = new LLScrollListDate(value.asDate(), font, width, font_style, font_alignment); - if (has_color) - { - cell->setColor(color); - } - new_item->setColumn(index, cell); - if (columnp->mHeader && !value.asString().empty()) - { - columnp->mHeader->setHasResizableElement(TRUE); - } + 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, fcolor, TRUE); - 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 @@ -3404,12 +2732,14 @@ 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(LLStringUtil::null, LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ), column_ptr->getWidth(), 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; } @@ -3422,14 +2752,13 @@ LLScrollListItem* LLScrollListCtrl::addSimpleElement(const std::string& value, E 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.cells.add() + .value(value) + .font(LLFontGL::getFontSansSerifSmall()); + + return addRow(item_params, pos); } void LLScrollListCtrl::setValue(const LLSD& value ) @@ -3530,484 +2859,3 @@ void LLScrollListCtrl::onFocusLost() LLUICtrl::onFocusLost(); } -LLColumnHeader::LLColumnHeader(const std::string& 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); - mButton->setToolTip(label); - - mAscendingText = std::string("[LOW]...[HIGH](Ascending)"); // *TODO: Translate - mDescendingText = std::string("[HIGH]...[LOW](Descending)"); // *TODO: Translate - - 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( - std::string("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 std::string &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); - - // propagate 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()); - - std::string low_item_text; - std::string 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(); - } - } - } - - LLStringUtil::truncate(low_item_text, 3); - LLStringUtil::truncate(high_item_text, 3); - - std::string ascending_string; - std::string 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::getFontSansSerifSmall()->getWidth(ascending_string); - text_width = llmax(text_width, LLFontGL::getFontSansSerifSmall()->getWidth(descending_string)) + 10; - text_width = llmax(text_width, getRect().getWidth() - 30); - - mList->getColumn(0)->setWidth(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, 10); - - 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) continue; - - 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->getWidth() - MIN_COLUMN_WIDTH); - - // user shrinking column, need to add width to other columns - if (delta_width < 0) - { - if (/*!columnp->mDynamicWidth && */columnp->getWidth() > 0) - { - // statically sized column, give all remaining width to this column - columnp->setWidth(columnp->getWidth() + remaining_width); - if (columnp->mRelWidth > 0.f) - { - columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); - } - // all padding went to this widget, we're done - break; - } - } - else - { - // user growing column, need to take width from other columns - remaining_width += resize_buffer_amt; - - if (/*!columnp->mDynamicWidth && */columnp->getWidth() > 0) - { - columnp->setWidth(columnp->getWidth() - llmin(columnp->getWidth() - MIN_COLUMN_WIDTH, delta_width)); - if (columnp->mRelWidth > 0.f) - { - columnp->mRelWidth = (F32)columnp->getWidth() / (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 += llmin(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->setWidth(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 (mHasResizableElement != resizable) - { - mColumn->mParentCtrl->dirtyColumns(); - mHasResizableElement = resizable; - } -} - -void LLColumnHeader::updateResizeBars() -{ - 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++; - } - } -} - -void LLColumnHeader::enableResizeBar(BOOL enable) -{ - // for now, dynamically spaced columns can't be resized - //if (!mColumn->mDynamicWidth) - { - mResizeBar->setEnabled(enable); - } -} - -BOOL LLColumnHeader::canResize() -{ - return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth); -} - -void LLScrollListColumn::setWidth(S32 width) -{ - if (!mDynamicWidth && mRelWidth <= 0.f) - { - mParentCtrl->updateStaticColumnWidth(this, width); - } - mWidth = width; -} - -// Default constructor -LLScrollListColumn::LLScrollListColumn() : - mName(), - mSortingColumn(), - mSortAscending(TRUE), - mLabel(), - mWidth(-1), - mRelWidth(-1.0), - mDynamicWidth(FALSE), - mMaxContentWidth(0), - mIndex(-1), - mParentCtrl(NULL), - mHeader(NULL), - mFontAlignment(LLFontGL::LEFT) -{ } - -LLScrollListColumn::LLScrollListColumn(const LLSD &sd, LLScrollListCtrl* parent) : - mWidth(0), - mIndex (-1), - mParentCtrl(parent), - mHeader(NULL), - mMaxContentWidth(0), - mDynamicWidth(FALSE), - mRelWidth(-1.f) -{ - mName = sd.get("name").asString(); - mSortingColumn = mName; - if (sd.has("sort")) - { - mSortingColumn = sd.get("sort").asString(); - } - mSortAscending = TRUE; - if (sd.has("sort_ascending")) - { - mSortAscending = sd.get("sort_ascending").asBoolean(); - } - mLabel = sd.get("label").asString(); - if (sd.has("relwidth") && (F32)sd.get("relwidth").asReal() > 0) - { - mRelWidth = (F32)sd.get("relwidth").asReal(); - if (mRelWidth < 0) mRelWidth = 0; - if (mRelWidth > 1) mRelWidth = 1; - mDynamicWidth = FALSE; - } - else if(sd.has("dynamicwidth") && (BOOL)sd.get("dynamicwidth").asBoolean() == TRUE) - { - mDynamicWidth = TRUE; - mRelWidth = -1; - } - else - { - - setWidth(sd.get("width").asInteger()); - } - - if (sd.has("halign")) - { - mFontAlignment = (LLFontGL::HAlign)llclamp(sd.get("halign").asInteger(), (S32)LLFontGL::LEFT, (S32)LLFontGL::HCENTER); - } - else - { - mFontAlignment = LLFontGL::LEFT; - } - -} -- cgit v1.2.3 From ade6bbb06c6a842f39a3fe32decf7c66682df092 Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Sun, 21 Jun 2009 17:16:27 +0000 Subject: merge -r 124105-124625 skinning-13 -> viewer-2.0.0-3 --- indra/llui/llscrolllistctrl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llui/llscrolllistctrl.cpp') diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 42c7c892c8..6d91c784f7 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1246,14 +1246,14 @@ const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const // "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 std::string& 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) { if (getItemCount() < mMaxItemCount) { LLScrollListItem::Params item_p; item_p.enabled(enabled); item_p.value(id); - item_p.cells.add().value(item_text).width(column_width).type("text"); + item_p.cells.add().value(item_text).type("text"); return addRow( item_p, pos ); } -- cgit v1.2.3 From 52aeaa32841e7d0b37abab0a2a2540c2be2f16b7 Mon Sep 17 00:00:00 2001 From: James Cook Date: Tue, 7 Jul 2009 00:53:05 +0000 Subject: Merge skinning-14 to viewer-2, including refactoring many floaters to register them with LLFloaterReg, support for introspection of ParamBlock based UI widgets to dump XML schema, splitting llfolderview.cpp into three separate files to unravel dependencies and skeleton for for LLListView widget. Resolved conflicts in these files: lldraghandle.h, lluictrl.h, llchiclet.cpp, llfolderview.h/cpp, lliinventorybridge.cpp, llpanelpicks.cpp, llviewermenu.cpp, floater_mute.xml, floater_preferences.xml, notifications.xml, panel_preferences_audio.xml, panel_preferences_graphics1.xml, panel_region_general.xml svn merge -r124961:126284 svn+ssh://svn.lindenlab.com/svn/linden/branches/skinning/skinning-14 --- indra/llui/llscrolllistctrl.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'indra/llui/llscrolllistctrl.cpp') diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 6d91c784f7..75afbffc11 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -31,8 +31,6 @@ * $/LicenseInfo$ */ -#define INSTANTIATE_GETCHILD_SCROLLLIST - #include "linden_common.h" #include "llscrolllistctrl.h" @@ -60,9 +58,7 @@ #include "lltextbox.h" #include "llsdparam.h" -template LLScrollListCtrl* LLView::getChild( const std::string& name, BOOL recurse, BOOL create_if_missing ) const; - -static LLDefaultWidgetRegistry::Register r("scroll_list"); +static LLDefaultChildRegistry::Register r("scroll_list"); // local structures & classes. struct SortScrollListItem @@ -225,7 +221,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) LLViewBorder::Params params; params.name("dig border"); params.rect(border_rect); - params.bevel_type(LLViewBorder::BEVEL_IN); + params.bevel_style(LLViewBorder::BEVEL_IN); mBorder = LLUICtrlFactory::create (params); addChild(mBorder); } -- cgit v1.2.3 From 923d84d08f98b33657d6bd861c34b985125db757 Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Fri, 10 Jul 2009 20:43:08 +0000 Subject: EXT-127: Tooltips don't disappear immediately after moving mouse out of object reviewed by Austin --- indra/llui/llscrolllistctrl.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'indra/llui/llscrolllistctrl.cpp') diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 75afbffc11..84a725ce02 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1512,19 +1512,12 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sti if (hit_cell && hit_cell->isText()) { - 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->getWidth(), mLineHeight); // 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) ); - + localRectToScreen(cell_rect, sticky_rect_screen); msg = hit_cell->getValue().asString(); } handled = TRUE; @@ -1849,8 +1842,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; } -- cgit v1.2.3 From 8f7ec64899c54dcee6caa0307510cc4003ba7bdd Mon Sep 17 00:00:00 2001 From: James Cook Date: Mon, 27 Jul 2009 17:56:26 +0000 Subject: Merged skinning-17 into viewer-2 for bug fixes. Commented out new IM window for now, not complete. Merging revisions 127913-128319 of svn+ssh://svn.lindenlab.com/svn/linden/branches/skinning/skinning-17 into D:\viewer-2.0.0-3, respecting ancestry --- indra/llui/llscrolllistctrl.cpp | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'indra/llui/llscrolllistctrl.cpp') diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 84a725ce02..e8627586ea 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -102,11 +102,11 @@ struct SortScrollListItem //--------------------------------------------------------------------------- LLScrollListCtrl::Contents::Contents() -: columns("columns"), - rows("rows") +: columns("column"), + rows("row") { - addSynonym(columns, "column"); - addSynonym(rows, "row"); + addSynonym(columns, "columns"); + addSynonym(rows, "rows"); } LLScrollListCtrl::Params::Params() @@ -126,10 +126,11 @@ LLScrollListCtrl::Params::Params() bg_selected_color("bg_selected_color"), fg_disable_color("fg_disable_color"), bg_writeable_color("bg_writeable_color"), - bg_read_only_color("bg_read_only_color"), + bg_readonly_color("bg_readonly_color"), bg_stripe_color("bg_stripe_color"), hovered_color("hovered_color"), - highlighted_color("highlighted_color") + highlighted_color("highlighted_color"), + contents("") { name = "scroll_list"; mouse_opaque = true; @@ -170,7 +171,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mBackgroundVisible(p.background_visible), mDrawStripes(p.draw_stripes), mBgWriteableColor(p.bg_writeable_color()), - mBgReadOnlyColor(p.bg_read_only_color()), + mBgReadOnlyColor(p.bg_readonly_color()), mBgSelectedColor(p.bg_selected_color()), mBgStripeColor(p.bg_stripe_color()), mFgSelectedColor(p.fg_selected_color()), @@ -1082,12 +1083,12 @@ LLScrollListItem* LLScrollListCtrl::addSeparator(EAddPosition pos) { LLScrollListItem::Params separator_params; separator_params.enabled(false); - LLScrollListCell::Params cell_params; - cell_params.type = "icon"; - cell_params.value = "menu_separator"; - cell_params.color = LLColor4(0.f, 0.f, 0.f, 0.7f); - cell_params.font_halign = LLFontGL::HCENTER; - separator_params.cells.add(cell_params); + 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 ); } @@ -1249,7 +1250,7 @@ LLScrollListItem* LLScrollListCtrl::addStringUUIDItem(const std::string& item_te LLScrollListItem::Params item_p; item_p.enabled(enabled); item_p.value(id); - item_p.cells.add().value(item_text).type("text"); + item_p.columns.add().value(item_text).type("text"); return addRow( item_p, pos ); } @@ -2635,8 +2636,8 @@ LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_ // Add any columns we don't already have S32 col_index = 0; - for(LLInitParam::ParamIterator::const_iterator itor = item_p.cells().begin(); - itor != item_p.cells().end(); + for(LLInitParam::ParamIterator::const_iterator itor = item_p.columns().begin(); + itor != item_p.columns().end(); ++itor) { LLScrollListCell::Params cell_p = *itor; @@ -2687,7 +2688,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_ col_index++; } - if (item_p.cells().empty()) + if (item_p.columns().empty()) { if (mColumns.empty()) { @@ -2742,7 +2743,7 @@ LLScrollListItem* LLScrollListCtrl::addSimpleElement(const std::string& value, E LLScrollListItem::Params item_params; item_params.value(entry_id); - item_params.cells.add() + item_params.columns.add() .value(value) .font(LLFontGL::getFontSansSerifSmall()); -- cgit v1.2.3 From eb853f55c07ae4a3c3f2aa05fbabcf2e4b4dc115 Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Tue, 4 Aug 2009 01:12:59 +0000 Subject: svn merge -r 128442:129343 svn+ssh://svn.lindenlab.com/svn/linden/branches/skinning/skinning-18 into svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer/viewer-2.0.0-3 --- indra/llui/llscrolllistctrl.cpp | 43 +++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) (limited to 'indra/llui/llscrolllistctrl.cpp') diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index e8627586ea..79f0f9d71b 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -163,7 +163,6 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mSorted(FALSE), mDirty(FALSE), mOriginalSelection(-1), - mDrewSelected(FALSE), mLastSelected(NULL), mHeadingHeight(p.heading_height), mAllowMultipleSelection(p.multi_select), @@ -1353,8 +1352,6 @@ void LLScrollListCtrl::drawItems() S32 cur_y = y; - mDrewSelected = FALSE; - S32 line = 0; S32 max_columns = 0; @@ -1375,11 +1372,6 @@ void LLScrollListCtrl::drawItems() //llinfos << item_rect.getWidth() << llendl; - if (item->getSelected()) - { - mDrewSelected = TRUE; - } - max_columns = llmax(max_columns, item->getNumColumns()); LLColor4 fg_color; @@ -1444,10 +1436,7 @@ void LLScrollListCtrl::draw() LLLocalClipRect clip(getLocalRect()); // if user specifies sort, make sure it is maintained - if (needsSorting() && !isSorted()) - { - sortItems(); - } + sortItems(); if (mNeedsScroll) { @@ -2208,6 +2197,8 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending) sort_column->mSortDirection = ascending ? LLScrollListColumn::ASCENDING : LLScrollListColumn::DESCENDING; sort_column_t new_sort_column(column_idx, ascending); + + setSorted(FALSE); if (mSortColumns.empty()) { @@ -2248,21 +2239,22 @@ void LLScrollListCtrl::sortByColumn(const std::string& name, BOOL ascending) // First column is column 0 void LLScrollListCtrl::sortByColumnIndex(U32 column, BOOL ascending) { - if (setSort(column, ascending)) - { - sortItems(); - } + setSort(column, ascending); + sortItems(); } void LLScrollListCtrl::sortItems() { - // do stable sort to preserve any previous sorts - std::stable_sort( - mItemList.begin(), - mItemList.end(), - SortScrollListItem(mSortColumns)); + if (hasSortOrder() && !isSorted()) + { + // do stable sort to preserve any previous sorts + std::stable_sort( + mItemList.begin(), + mItemList.end(), + SortScrollListItem(mSortColumns)); - setSorted(TRUE); + setSorted(TRUE); + } } // for one-shot sorts, does not save sort column/order @@ -2318,10 +2310,7 @@ void LLScrollListCtrl::scrollToShowSelected() return; } - if (needsSorting() && !isSorted()) - { - sortItems(); - } + sortItems(); S32 index = getFirstSelectedIndex(); if (index < 0) @@ -2562,7 +2551,7 @@ std::string LLScrollListCtrl::getSortColumnName() else return ""; } -BOOL LLScrollListCtrl::needsSorting() +BOOL LLScrollListCtrl::hasSortOrder() { return !mSortColumns.empty(); } -- cgit v1.2.3 From 0bf4b5f2222ffb8171be094613363427f3b8470a Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Wed, 12 Aug 2009 01:12:27 +0000 Subject: merge https://svn.aws.productengine.com/secondlife/export-from-ll@1277 https://svn.aws.productengine.com/secondlife/pe/stable-1@1297 -> viewer-2-0 Fixes: EXT 208 EXT 366 EXT-211 EXT-245 EXT-246 EXT-278 EXT-279 EXT-280 EXT-298 EXT-301 EXT-304 EXT-311 EXT-317 EXT-318 EXT-319 EXT-339 EXT-343 EXT-344 EXT-346 EXT-349 EXT-350 EXT-351 EXT-354 EXT-355 EXT-358 EXT-360 EXT-362 EXT-369 EXT-372 EXT-374 EXT-381 EXT-382 EXT-383 EXT-395 EXT-396 EXT-412 Other changes: Movement & Caemra controls work Profile and Me panel refactoring Notification refactoring --- indra/llui/llscrolllistctrl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/llui/llscrolllistctrl.cpp') diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 79f0f9d71b..3041773fb2 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1684,7 +1684,8 @@ 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(); } -- cgit v1.2.3 From 138bf1132262c479dbbd5c95195db46b1efd065f Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Mon, 24 Aug 2009 20:04:52 +0000 Subject: merge -r 130399-131510 skinning-21 -> viewer-2.0.0-3 DEV-11254 DEV-11254 DEV-2003: DEV-21567 DEV-37301 EXT-104 EXT-138 EXT-217 EXT-256 EXT-259 EXT-259 EXT-328 EXT-348 EXT-386 EXT-399 EXT-403 EXT-460 EXT-492 EXT-492 EXT-531 EXT-537 EXT-684 improved text editor (handles multiple fonts simultaneously as well as inline widgets) --- indra/llui/llscrolllistctrl.cpp | 47 +++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) (limited to 'indra/llui/llscrolllistctrl.cpp') diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 3041773fb2..637642cdcd 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -160,7 +160,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mNumDynamicWidthColumns(0), mTotalStaticColumnWidth(0), mTotalColumnPadding(0), - mSorted(FALSE), + mSorted(false), mDirty(FALSE), mOriginalSelection(-1), mLastSelected(NULL), @@ -374,6 +374,10 @@ std::vector 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++) { @@ -507,7 +511,7 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r { case ADD_TOP: mItemList.push_front(item); - setSorted(FALSE); + setNeedsSort(); break; case ADD_SORTED: @@ -524,18 +528,18 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r // 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; } @@ -759,6 +763,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); @@ -812,6 +819,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; @@ -825,6 +833,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; @@ -838,6 +847,8 @@ void LLScrollListCtrl::deleteSingleItem(S32 target_index) return; } + updateSort(); + LLScrollListItem *itemp; itemp = mItemList[target_index]; if (itemp == mLastSelected) @@ -939,6 +950,8 @@ S32 LLScrollListCtrl::selectMultiple( std::vector 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++) @@ -955,6 +968,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++) @@ -980,6 +995,8 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection) } else { + updateSort(); + item_list::iterator iter; for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { @@ -1022,6 +1039,8 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection) } else { + updateSort(); + item_list::reverse_iterator iter; for (iter = mItemList.rbegin(); iter != mItemList.rend(); iter++) { @@ -1436,7 +1455,7 @@ void LLScrollListCtrl::draw() LLLocalClipRect clip(getLocalRect()); // if user specifies sort, make sure it is maintained - sortItems(); + updateSort(); if (mNeedsScroll) { @@ -1463,7 +1482,7 @@ void LLScrollListCtrl::draw() if (mBorder) { - mBorder->setKeyboardFocusHighlight(gFocusMgr.getKeyboardFocus() == this); + mBorder->setKeyboardFocusHighlight(hasFocus()); } LLUICtrl::draw(); @@ -1754,6 +1773,8 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y ) // Excludes disabled items. LLScrollListItem* hit_item = NULL; + updateSort(); + LLRect item_rect; item_rect.setLeftTopAndSize( mItemListRect.mLeft, @@ -2199,7 +2220,7 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending) sort_column_t new_sort_column(column_idx, ascending); - setSorted(FALSE); + setNeedsSort(); if (mSortColumns.empty()) { @@ -2241,10 +2262,10 @@ void LLScrollListCtrl::sortByColumn(const std::string& name, BOOL ascending) void LLScrollListCtrl::sortByColumnIndex(U32 column, BOOL ascending) { setSort(column, ascending); - sortItems(); + updateSort(); } -void LLScrollListCtrl::sortItems() +void LLScrollListCtrl::updateSort() const { if (hasSortOrder() && !isSorted()) { @@ -2254,7 +2275,7 @@ void LLScrollListCtrl::sortItems() mItemList.end(), SortScrollListItem(mSortColumns)); - setSorted(TRUE); + mSorted = true; } } @@ -2311,7 +2332,7 @@ void LLScrollListCtrl::scrollToShowSelected() return; } - sortItems(); + updateSort(); S32 index = getFirstSelectedIndex(); if (index < 0) @@ -2552,7 +2573,7 @@ std::string LLScrollListCtrl::getSortColumnName() else return ""; } -BOOL LLScrollListCtrl::hasSortOrder() +BOOL LLScrollListCtrl::hasSortOrder() const { return !mSortColumns.empty(); } -- cgit v1.2.3