00001
00032 #include <algorithm>
00033
00034 #include "linden_common.h"
00035 #include "llstl.h"
00036 #include "llboost.h"
00037
00038 #include "llscrolllistctrl.h"
00039
00040 #include "indra_constants.h"
00041
00042 #include "llcheckboxctrl.h"
00043 #include "llclipboard.h"
00044 #include "llfocusmgr.h"
00045 #include "llgl.h"
00046 #include "llglheaders.h"
00047 #include "llresmgr.h"
00048 #include "llscrollbar.h"
00049 #include "llstring.h"
00050 #include "llui.h"
00051 #include "lluictrlfactory.h"
00052 #include "llwindow.h"
00053 #include "llcontrol.h"
00054 #include "llkeyboard.h"
00055 #include "llresizebar.h"
00056
00057 const S32 LIST_BORDER_PAD = 0;
00058 const S32 MIN_COLUMN_WIDTH = 20;
00059 const S32 LIST_SNAP_PADDING = 5;
00060
00061
00062 struct SortScrollListItem
00063 {
00064 SortScrollListItem(const S32 sort_col, BOOL sort_ascending)
00065 {
00066 mSortCol = sort_col;
00067 mSortAscending = sort_ascending;
00068 }
00069
00070 bool operator()(const LLScrollListItem* i1, const LLScrollListItem* i2)
00071 {
00072 const LLScrollListCell *cell1;
00073 const LLScrollListCell *cell2;
00074
00075 cell1 = i1->getColumn(mSortCol);
00076 cell2 = i2->getColumn(mSortCol);
00077
00078 S32 order = 1;
00079 if (!mSortAscending)
00080 {
00081 order = -1;
00082 }
00083
00084 BOOL retval = FALSE;
00085
00086 if (cell1 && cell2)
00087 {
00088 retval = ((order * LLString::compareDict(cell1->getText(), cell2->getText())) < 0);
00089 }
00090
00091 return (retval ? TRUE : FALSE);
00092 }
00093
00094 protected:
00095 S32 mSortCol;
00096 S32 mSortAscending;
00097 };
00098
00099
00100
00101
00102
00103
00104 LLScrollListIcon::LLScrollListIcon(LLImageGL* icon, S32 width, LLUUID image_id)
00105 : mIcon(icon),
00106 mImageUUID(image_id.asString()),
00107 mColor(LLColor4::white)
00108 {
00109 if (width)
00110 {
00111 mWidth = width;
00112 }
00113 else
00114 {
00115 mWidth = icon->getWidth();
00116 }
00117 }
00118
00119 LLScrollListIcon::~LLScrollListIcon()
00120 {
00121 }
00122
00123 void LLScrollListIcon::setColor(const LLColor4& color)
00124 {
00125 mColor = color;
00126 }
00127
00128 void LLScrollListIcon::drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const
00129 {
00130 gl_draw_image(0, 0, mIcon, mColor);
00131 }
00132
00133
00134
00135
00136 LLScrollListCheck::LLScrollListCheck(LLCheckBoxCtrl* check_box, S32 width)
00137 {
00138 mCheckBox = check_box;
00139 LLRect rect(mCheckBox->getRect());
00140 if (width)
00141 {
00142
00143 rect.mRight = rect.mLeft + width;
00144 mCheckBox->setRect(rect);
00145 mWidth = width;
00146 }
00147 else
00148 {
00149 mWidth = rect.getWidth();
00150 }
00151 }
00152
00153 LLScrollListCheck::~LLScrollListCheck()
00154 {
00155 delete mCheckBox;
00156 }
00157
00158 void LLScrollListCheck::drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const
00159 {
00160 mCheckBox->draw();
00161
00162 }
00163
00164 BOOL LLScrollListCheck::handleClick()
00165 {
00166 if ( mCheckBox->getEnabled() )
00167 {
00168 LLCheckBoxCtrl::onButtonPress(mCheckBox);
00169 }
00170 return TRUE;
00171 }
00172
00173
00174
00175
00176 LLScrollListSeparator::LLScrollListSeparator(S32 width) : mWidth(width)
00177 {
00178 }
00179
00180 void LLScrollListSeparator::drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const
00181 {
00182
00183 gl_line_2d(5, 8, llmax(5, width - 5), 8, color);
00184 }
00185
00186
00187
00188
00189 U32 LLScrollListText::sCount = 0;
00190
00191 LLScrollListText::LLScrollListText( const LLString& text, const LLFontGL* font, S32 width, U8 font_style, LLFontGL::HAlign font_alignment, LLColor4& color, BOOL use_color, BOOL visible)
00192 : mText( text ),
00193 mFont( font ),
00194 mFontStyle( font_style ),
00195 mFontAlignment( font_alignment ),
00196 mWidth( width ),
00197 mVisible( visible ),
00198 mHighlightCount( 0 ),
00199 mHighlightOffset( 0 )
00200 {
00201 if (use_color)
00202 {
00203 mColor = new LLColor4();
00204 mColor->setVec(color);
00205 }
00206 else
00207 {
00208 mColor = NULL;
00209 }
00210
00211 sCount++;
00212
00213
00214 if (!mRoundedRectImage)
00215 {
00216 mRoundedRectImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("rounded_square.tga")));
00217 }
00218 }
00219
00220 LLScrollListText::~LLScrollListText()
00221 {
00222 sCount--;
00223 delete mColor;
00224 }
00225
00226 void LLScrollListText::setColor(const LLColor4& color)
00227 {
00228 if (!mColor)
00229 {
00230 mColor = new LLColor4();
00231 }
00232 *mColor = color;
00233 }
00234
00235 void LLScrollListText::setText(const LLStringExplicit& text)
00236 {
00237 mText = text;
00238 }
00239
00240 void LLScrollListText::drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const
00241 {
00242
00243 if (mWidth > 0 && mWidth < width)
00244 {
00245 width = mWidth;
00246 }
00247
00248 const LLColor4* display_color;
00249 if (mColor)
00250 {
00251 display_color = mColor;
00252 }
00253 else
00254 {
00255 display_color = &color;
00256 }
00257
00258 if (mHighlightCount > 0)
00259 {
00260 mRoundedRectImage->bind();
00261 glColor4fv(highlight_color.mV);
00262 S32 left = 0;
00263 switch(mFontAlignment)
00264 {
00265 case LLFontGL::LEFT:
00266 left = mFont->getWidth(mText.getString(), 0, mHighlightOffset);
00267 break;
00268 case LLFontGL::RIGHT:
00269 left = width - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX);
00270 break;
00271 case LLFontGL::HCENTER:
00272 left = (width - mFont->getWidth(mText.getString())) / 2;
00273 break;
00274 }
00275 gl_segmented_rect_2d_tex(left - 2,
00276 llround(mFont->getLineHeight()) + 1,
00277 left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1,
00278 1,
00279 mRoundedRectImage->getWidth(),
00280 mRoundedRectImage->getHeight(),
00281 16);
00282 }
00283
00284
00285 F32 right_x;
00286 U32 string_chars = mText.length();
00287 F32 start_x = 0.f;
00288 switch(mFontAlignment)
00289 {
00290 case LLFontGL::LEFT:
00291 start_x = 0.f;
00292 break;
00293 case LLFontGL::RIGHT:
00294 start_x = (F32)width;
00295 break;
00296 case LLFontGL::HCENTER:
00297 start_x = (F32)width * 0.5f;
00298 break;
00299 }
00300 mFont->render(mText.getWString(), 0,
00301 start_x, 2.f,
00302 *display_color,
00303 mFontAlignment,
00304 LLFontGL::BOTTOM,
00305 mFontStyle,
00306 string_chars,
00307 width,
00308 &right_x, FALSE, TRUE);
00309 }
00310
00311
00312 LLScrollListItem::~LLScrollListItem()
00313 {
00314 std::for_each(mColumns.begin(), mColumns.end(), DeletePointer());
00315 }
00316
00317 BOOL LLScrollListItem::handleClick(S32 x, S32 y, MASK mask)
00318 {
00319 BOOL handled = FALSE;
00320
00321 S32 left = 0;
00322 S32 right = 0;
00323 S32 width = 0;
00324
00325 std::vector<LLScrollListCell *>::iterator iter = mColumns.begin();
00326 std::vector<LLScrollListCell *>::iterator end = mColumns.end();
00327 for ( ; iter != end; ++iter)
00328 {
00329 width = (*iter)->getWidth();
00330 right += width;
00331 if (left <= x && x < right )
00332 {
00333 handled = (*iter)->handleClick();
00334 break;
00335 }
00336
00337 left += width;
00338 }
00339 return handled;
00340 }
00341
00342 void LLScrollListItem::setNumColumns(S32 columns)
00343 {
00344 S32 prev_columns = mColumns.size();
00345 if (columns < prev_columns)
00346 {
00347 std::for_each(mColumns.begin()+columns, mColumns.end(), DeletePointer());
00348 }
00349
00350 mColumns.resize(columns);
00351
00352 for (S32 col = prev_columns; col < columns; ++col)
00353 {
00354 mColumns[col] = NULL;
00355 }
00356 }
00357
00358 void LLScrollListItem::setColumn( S32 column, LLScrollListCell *cell )
00359 {
00360 if (column < (S32)mColumns.size())
00361 {
00362 delete mColumns[column];
00363 mColumns[column] = cell;
00364 }
00365 else
00366 {
00367 llerrs << "LLScrollListItem::setColumn: bad column: " << column << llendl;
00368 }
00369 }
00370
00371 LLString LLScrollListItem::getContentsCSV()
00372 {
00373 LLString ret;
00374
00375 S32 count = getNumColumns();
00376 for (S32 i=0; i<count; ++i)
00377 {
00378 ret += getColumn(i)->getText();
00379 if (i < count-1)
00380 {
00381 ret += ", ";
00382 }
00383 }
00384
00385 return ret;
00386 }
00387
00388 void LLScrollListItem::setEnabled(BOOL b)
00389 {
00390 if (b != mEnabled)
00391 {
00392 std::vector<LLScrollListCell *>::iterator iter = mColumns.begin();
00393 std::vector<LLScrollListCell *>::iterator end = mColumns.end();
00394 for ( ; iter != end; ++iter)
00395 {
00396 (*iter)->setEnabled(b);
00397 }
00398 mEnabled = b;
00399 }
00400 }
00401
00402
00403
00404
00405
00406 LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
00407 void (*commit_callback)(LLUICtrl* ctrl, void* userdata),
00408 void* callback_user_data,
00409 BOOL allow_multiple_selection,
00410 BOOL show_border
00411 )
00412 : LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data),
00413 mLineHeight(0),
00414 mScrollLines(0),
00415 mPageLines(0),
00416 mHeadingHeight(20),
00417 mMaxSelectable(0),
00418 mAllowMultipleSelection( allow_multiple_selection ),
00419 mAllowKeyboardMovement(TRUE),
00420 mCommitOnKeyboardMovement(TRUE),
00421 mCommitOnSelectionChange(FALSE),
00422 mSelectionChanged(FALSE),
00423 mNeedsScroll(FALSE),
00424 mCanSelect(TRUE),
00425 mDisplayColumnHeaders(FALSE),
00426 mCollapseEmptyColumns(FALSE),
00427 mIsPopup(FALSE),
00428 mMaxItemCount(INT_MAX),
00429
00430 mBackgroundVisible( TRUE ),
00431 mDrawStripes(TRUE),
00432 mBgWriteableColor( LLUI::sColorsGroup->getColor( "ScrollBgWriteableColor" ) ),
00433 mBgReadOnlyColor( LLUI::sColorsGroup->getColor( "ScrollBgReadOnlyColor" ) ),
00434 mBgSelectedColor( LLUI::sColorsGroup->getColor("ScrollSelectedBGColor") ),
00435 mBgStripeColor( LLUI::sColorsGroup->getColor("ScrollBGStripeColor") ),
00436 mFgSelectedColor( LLUI::sColorsGroup->getColor("ScrollSelectedFGColor") ),
00437 mFgUnselectedColor( LLUI::sColorsGroup->getColor("ScrollUnselectedColor") ),
00438 mFgDisabledColor( LLUI::sColorsGroup->getColor("ScrollDisabledColor") ),
00439 mHighlightedColor( LLUI::sColorsGroup->getColor("ScrollHighlightedColor") ),
00440 mBorderThickness( 2 ),
00441 mOnDoubleClickCallback( NULL ),
00442 mOnMaximumSelectCallback( NULL ),
00443 mOnSortChangedCallback( NULL ),
00444 mHighlightedItem(-1),
00445 mBorder(NULL),
00446 mDefaultColumn("SIMPLE"),
00447 mSearchColumn(0),
00448 mNumDynamicWidthColumns(0),
00449 mTotalStaticColumnWidth(0),
00450 mSortColumn(-1),
00451 mSortAscending(TRUE),
00452 mSorted(TRUE),
00453 mDirty(FALSE),
00454 mOriginalSelection(-1),
00455 mDrewSelected(FALSE)
00456 {
00457 mItemListRect.setOriginAndSize(
00458 mBorderThickness + LIST_BORDER_PAD,
00459 mBorderThickness + LIST_BORDER_PAD,
00460 mRect.getWidth() - 2*( mBorderThickness + LIST_BORDER_PAD ) - SCROLLBAR_SIZE,
00461 mRect.getHeight() - 2*( mBorderThickness + LIST_BORDER_PAD ) );
00462
00463 updateLineHeight();
00464
00465 mPageLines = mLineHeight? (mItemListRect.getHeight()) / mLineHeight : 0;
00466
00467
00468 LLRect scroll_rect;
00469 scroll_rect.setOriginAndSize(
00470 mRect.getWidth() - mBorderThickness - SCROLLBAR_SIZE,
00471 mItemListRect.mBottom,
00472 SCROLLBAR_SIZE,
00473 mItemListRect.getHeight());
00474 mScrollbar = new LLScrollbar( "Scrollbar", scroll_rect,
00475 LLScrollbar::VERTICAL,
00476 getItemCount(),
00477 mScrollLines,
00478 mPageLines,
00479 &LLScrollListCtrl::onScrollChange, this );
00480 mScrollbar->setFollowsRight();
00481 mScrollbar->setFollowsTop();
00482 mScrollbar->setFollowsBottom();
00483 mScrollbar->setEnabled( TRUE );
00484 mScrollbar->setVisible( TRUE );
00485 addChild(mScrollbar);
00486
00487
00488 if (show_border)
00489 {
00490 LLRect border_rect( 0, mRect.getHeight(), mRect.getWidth(), 0 );
00491 mBorder = new LLViewBorder( "dlg border", border_rect, LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, 1 );
00492 addChild(mBorder);
00493 }
00494
00495 mColumnPadding = 5;
00496
00497 mLastSelected = NULL;
00498 }
00499
00500 LLScrollListCtrl::~LLScrollListCtrl()
00501 {
00502 std::for_each(mItemList.begin(), mItemList.end(), DeletePointer());
00503
00504 if( gEditMenuHandler == this )
00505 {
00506 gEditMenuHandler = NULL;
00507 }
00508 }
00509
00510
00511 BOOL LLScrollListCtrl::setMaxItemCount(S32 max_count)
00512 {
00513 if (max_count >= getItemCount())
00514 {
00515 mMaxItemCount = max_count;
00516 }
00517 return (max_count == mMaxItemCount);
00518 }
00519
00520 S32 LLScrollListCtrl::isEmpty() const
00521 {
00522 return mItemList.empty();
00523 }
00524
00525 S32 LLScrollListCtrl::getItemCount() const
00526 {
00527 return mItemList.size();
00528 }
00529
00530
00531 void LLScrollListCtrl::clearRows()
00532 {
00533 std::for_each(mItemList.begin(), mItemList.end(), DeletePointer());
00534 mItemList.clear();
00535
00536
00537
00538 mScrollbar->setDocParams(0, 0);
00539
00540 mScrollLines = 0;
00541 mLastSelected = NULL;
00542 updateMaxContentWidth(NULL);
00543 mDirty = FALSE;
00544 }
00545
00546
00547 LLScrollListItem* LLScrollListCtrl::getFirstSelected() const
00548 {
00549 item_list::const_iterator iter;
00550 for(iter = mItemList.begin(); iter != mItemList.end(); iter++)
00551 {
00552 LLScrollListItem* item = *iter;
00553 if (item->getSelected())
00554 {
00555 return item;
00556 }
00557 }
00558 return NULL;
00559 }
00560
00561 std::vector<LLScrollListItem*> LLScrollListCtrl::getAllSelected() const
00562 {
00563 std::vector<LLScrollListItem*> ret;
00564 item_list::const_iterator iter;
00565 for(iter = mItemList.begin(); iter != mItemList.end(); iter++)
00566 {
00567 LLScrollListItem* item = *iter;
00568 if (item->getSelected())
00569 {
00570 ret.push_back(item);
00571 }
00572 }
00573 return ret;
00574 }
00575
00581 LLDynamicArray<LLUUID> LLScrollListCtrl::getSelectedIDs()
00582 {
00583 LLUUID selected_id;
00584 LLDynamicArray<LLUUID> ret;
00585
00586 item_list::const_iterator iter;
00587 for(iter = mItemList.begin(); iter != mItemList.end(); iter++)
00588 {
00589 LLScrollListItem* item = *iter;
00590 if (item->getSelected())
00591 {
00592 ret.push_back(item->getUUID());
00593 }
00594 }
00595 return ret;
00596 }
00597
00598
00599 S32 LLScrollListCtrl::getFirstSelectedIndex() const
00600 {
00601 S32 CurSelectedIndex = 0;
00602 item_list::const_iterator iter;
00603 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
00604 {
00605 LLScrollListItem* item = *iter;
00606 if (item->getSelected())
00607 {
00608 return CurSelectedIndex;
00609 }
00610 CurSelectedIndex++;
00611 }
00612
00613 return -1;
00614 }
00615
00616 LLScrollListItem* LLScrollListCtrl::getFirstData() const
00617 {
00618 if (mItemList.size() == 0)
00619 {
00620 return NULL;
00621 }
00622 return mItemList[0];
00623 }
00624
00625 LLScrollListItem* LLScrollListCtrl::getLastData() const
00626 {
00627 if (mItemList.size() == 0)
00628 {
00629 return NULL;
00630 }
00631 return mItemList[mItemList.size() - 1];
00632 }
00633
00634 std::vector<LLScrollListItem*> LLScrollListCtrl::getAllData() const
00635 {
00636 std::vector<LLScrollListItem*> ret;
00637 item_list::const_iterator iter;
00638 for(iter = mItemList.begin(); iter != mItemList.end(); iter++)
00639 {
00640 LLScrollListItem* item = *iter;
00641 ret.push_back(item);
00642 }
00643 return ret;
00644 }
00645
00646
00647 void LLScrollListCtrl::reshape( S32 width, S32 height, BOOL called_from_parent )
00648 {
00649 S32 old_height = mRect.getHeight();
00650 LLUICtrl::reshape( width, height, called_from_parent );
00651
00652 S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0);
00653
00654 mItemListRect.setOriginAndSize(
00655 mBorderThickness + LIST_BORDER_PAD,
00656 mBorderThickness + LIST_BORDER_PAD,
00657 mRect.getWidth() - 2*( mBorderThickness + LIST_BORDER_PAD ) - SCROLLBAR_SIZE,
00658 mRect.getHeight() - 2*( mBorderThickness + LIST_BORDER_PAD ) - heading_size );
00659
00660 mPageLines = mLineHeight? mItemListRect.getHeight() / mLineHeight : 0;
00661 if(old_height < height && getScrollPos() == mScrollbar->getDocPosMax())
00662 {
00663 setScrollPos(mScrollbar->getDocPosMax());
00664 }
00665 mScrollbar->setVisible(mPageLines < getItemCount());
00666 mScrollbar->setPageSize( mPageLines );
00667
00668 updateColumns();
00669 }
00670
00671
00672
00673 void LLScrollListCtrl::arrange(S32 max_width, S32 max_height)
00674 {
00675 S32 height = mLineHeight * (getItemCount() + 1);
00676 height = llmin( height, max_height );
00677
00678 S32 width = mRect.getWidth();
00679
00680 reshape( width, height );
00681 }
00682
00683
00684 LLRect LLScrollListCtrl::getRequiredRect()
00685 {
00686 S32 height = mLineHeight * (getItemCount() + 1);
00687 S32 width = mRect.getWidth();
00688
00689 return LLRect(0, height, width, 0);
00690 }
00691
00692
00693 BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos )
00694 {
00695 BOOL not_too_big = getItemCount() < mMaxItemCount;
00696 if (not_too_big)
00697 {
00698 switch( pos )
00699 {
00700 case ADD_TOP:
00701 mItemList.push_front(item);
00702 setSorted(FALSE);
00703 break;
00704
00705 case ADD_SORTED:
00706 if (mSortColumn == -1)
00707 {
00708 mSortColumn = 0;
00709 mSortAscending = TRUE;
00710 }
00711 mItemList.push_back(item);
00712 std::sort(mItemList.begin(), mItemList.end(), SortScrollListItem(mSortColumn, mSortAscending));
00713 break;
00714
00715 case ADD_BOTTOM:
00716 mItemList.push_back(item);
00717 setSorted(FALSE);
00718 break;
00719
00720 default:
00721 llassert(0);
00722 mItemList.push_back(item);
00723 setSorted(FALSE);
00724 break;
00725 }
00726
00727 updateLineHeight();
00728 mPageLines = mLineHeight ? mItemListRect.getHeight() / mLineHeight : 0;
00729 BOOL scrollbar_visible = mPageLines < getItemCount();
00730
00731 if (scrollbar_visible != mScrollbar->getVisible())
00732 {
00733 mScrollbar->setVisible(mPageLines < getItemCount());
00734 updateColumns();
00735 }
00736 mScrollbar->setPageSize( mPageLines );
00737
00738 mScrollbar->setDocSize( getItemCount() );
00739
00740 updateMaxContentWidth(item);
00741 }
00742
00743 return not_too_big;
00744 }
00745
00746 void LLScrollListCtrl::updateMaxContentWidth(LLScrollListItem* added_item)
00747 {
00748 const S32 HEADING_TEXT_PADDING = 30;
00749 const S32 COLUMN_TEXT_PADDING = 20;
00750
00751 std::map<LLString, LLScrollListColumn>::iterator column_itor;
00752 for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)
00753 {
00754 LLScrollListColumn* column = &column_itor->second;
00755
00756 if (!added_item)
00757 {
00758
00759 column->mMaxContentWidth = column->mHeader ? LLFontGL::sSansSerifSmall->getWidth(column->mLabel) + mColumnPadding + HEADING_TEXT_PADDING : 0;
00760 item_list::iterator iter;
00761 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
00762 {
00763 LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex);
00764 if (!cellp) continue;
00765
00766 column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getText()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
00767 }
00768 }
00769 else
00770 {
00771 LLScrollListCell* cellp = added_item->getColumn(column->mIndex);
00772 if (!cellp) continue;
00773
00774 column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getText()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
00775 }
00776 }
00777 }
00778
00779
00780
00781 void LLScrollListCtrl::updateLineHeight()
00782 {
00783 const S32 ROW_PAD = 2;
00784
00785 mLineHeight = 0;
00786 item_list::iterator iter;
00787 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
00788 {
00789 LLScrollListItem *itemp = *iter;
00790 S32 num_cols = itemp->getNumColumns();
00791 S32 i = 0;
00792 for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
00793 {
00794 mLineHeight = llmax( mLineHeight, cell->getHeight() + ROW_PAD );
00795 }
00796 }
00797 }
00798
00799 void LLScrollListCtrl::updateColumns()
00800 {
00801 mColumnsIndexed.resize(mColumns.size());
00802
00803 std::map<LLString, LLScrollListColumn>::iterator column_itor;
00804 bool first_dynamic = true;
00805 for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)
00806 {
00807 LLScrollListColumn *column = &column_itor->second;
00808 S32 new_width = column->mWidth;
00809 if (column->mRelWidth >= 0)
00810 {
00811 new_width = (S32)llround(column->mRelWidth*mItemListRect.getWidth());
00812 }
00813 else if (column->mDynamicWidth)
00814 {
00815 new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
00816 if(first_dynamic)
00817 {
00818 first_dynamic = false;
00819 new_width += (mScrollbar->getVisible() ? 0 : SCROLLBAR_SIZE);
00820 }
00821 }
00822
00823 if (new_width != column->mWidth)
00824 {
00825 column->mWidth = new_width;
00826 }
00827 mColumnsIndexed[column_itor->second.mIndex] = column;
00828 }
00829
00830 item_list::iterator iter;
00831 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
00832 {
00833 LLScrollListItem *itemp = *iter;
00834 S32 num_cols = itemp->getNumColumns();
00835 S32 i = 0;
00836 for (LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
00837 {
00838 if (i >= (S32)mColumnsIndexed.size()) break;
00839
00840 cell->setWidth(mColumnsIndexed[i]->mWidth);
00841 }
00842 }
00843
00844
00845 std::vector<LLScrollListColumn*>::iterator column_ordered_it;
00846 S32 left = mItemListRect.mLeft;
00847 LLColumnHeader* last_header = NULL;
00848 for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it)
00849 {
00850 if ((*column_ordered_it)->mWidth < 0)
00851 {
00852
00853 continue;
00854 }
00855 LLScrollListColumn* column = *column_ordered_it;
00856
00857 if (column->mHeader)
00858 {
00859 last_header = column->mHeader;
00860 S32 top = mItemListRect.mTop;
00861 S32 right = left + column->mWidth;
00862
00863 if (column->mIndex != (S32)mColumnsIndexed.size()-1)
00864 {
00865 right += mColumnPadding;
00866 }
00867 right = llmax(left, llmin(mItemListRect.getWidth(), right));
00868 S32 header_width = right - left;
00869
00870 last_header->reshape(header_width, mHeadingHeight);
00871 last_header->translate(left - last_header->getRect().mLeft, top - last_header->getRect().mBottom);
00872 last_header->setVisible(mDisplayColumnHeaders && header_width > 0);
00873 left = right;
00874 }
00875 }
00876
00877
00878
00879 if (last_header)
00880 {
00881 S32 header_strip_width = mItemListRect.getWidth() + (mScrollbar->getVisible() ? 0 : SCROLLBAR_SIZE);
00882 S32 new_width = llmax(0, mItemListRect.mLeft + header_strip_width - last_header->getRect().mLeft);
00883 last_header->reshape(new_width, last_header->getRect().getHeight());
00884 last_header->setVisible(mDisplayColumnHeaders && new_width > 0);
00885 }
00886
00887 }
00888
00889 void LLScrollListCtrl::setDisplayHeading(BOOL display)
00890 {
00891 mDisplayColumnHeaders = display;
00892
00893 updateColumns();
00894
00895 setHeadingHeight(mHeadingHeight);
00896 }
00897
00898 void LLScrollListCtrl::setHeadingHeight(S32 heading_height)
00899 {
00900 mHeadingHeight = heading_height;
00901
00902 reshape(mRect.getWidth(), mRect.getHeight());
00903
00904
00905 mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0));
00906 }
00907
00908 void LLScrollListCtrl::setCollapseEmptyColumns(BOOL collapse)
00909 {
00910 mCollapseEmptyColumns = collapse;
00911 }
00912
00913 BOOL LLScrollListCtrl::selectFirstItem()
00914 {
00915 BOOL success = FALSE;
00916
00917
00918 BOOL first_item = TRUE;
00919
00920 item_list::iterator iter;
00921 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
00922 {
00923 LLScrollListItem *itemp = *iter;
00924 if( first_item && itemp->getEnabled() )
00925 {
00926 if (!itemp->getSelected())
00927 {
00928 selectItem(itemp);
00929 }
00930 success = TRUE;
00931 mOriginalSelection = 0;
00932 }
00933 else
00934 {
00935 deselectItem(itemp);
00936 }
00937 first_item = FALSE;
00938 }
00939 if (mCommitOnSelectionChange)
00940 {
00941 commitIfChanged();
00942 }
00943 return success;
00944 }
00945
00946
00947 BOOL LLScrollListCtrl::selectNthItem( S32 target_index )
00948 {
00949
00950 BOOL success = FALSE;
00951 S32 index = 0;
00952
00953 target_index = llclamp(target_index, 0, (S32)mItemList.size() - 1);
00954
00955 item_list::iterator iter;
00956 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
00957 {
00958 LLScrollListItem *itemp = *iter;
00959 if( target_index == index )
00960 {
00961 if( itemp->getEnabled() )
00962 {
00963 selectItem(itemp);
00964 success = TRUE;
00965 mOriginalSelection = target_index;
00966 }
00967 }
00968 else
00969 {
00970 deselectItem(itemp);
00971 }
00972 index++;
00973 }
00974
00975 if (mCommitOnSelectionChange)
00976 {
00977 commitIfChanged();
00978 }
00979
00980 mSearchString.clear();
00981
00982 return success;
00983 }
00984
00985
00986 void LLScrollListCtrl::swapWithNext(S32 index)
00987 {
00988 if (index >= ((S32)mItemList.size() - 1))
00989 {
00990
00991 return;
00992 }
00993 LLScrollListItem *cur_itemp = mItemList[index];
00994 mItemList[index] = mItemList[index + 1];
00995 mItemList[index + 1] = cur_itemp;
00996 }
00997
00998
00999 void LLScrollListCtrl::swapWithPrevious(S32 index)
01000 {
01001 if (index <= 0)
01002 {
01003
01004 }
01005
01006 LLScrollListItem *cur_itemp = mItemList[index];
01007 mItemList[index] = mItemList[index - 1];
01008 mItemList[index - 1] = cur_itemp;
01009 }
01010
01011
01012 void LLScrollListCtrl::deleteSingleItem(S32 target_index)
01013 {
01014 if (target_index >= (S32)mItemList.size())
01015 {
01016 return;
01017 }
01018
01019 LLScrollListItem *itemp;
01020 itemp = mItemList[target_index];
01021 if (itemp == mLastSelected)
01022 {
01023 mLastSelected = NULL;
01024 }
01025 delete itemp;
01026 mItemList.erase(mItemList.begin() + target_index);
01027 updateMaxContentWidth(NULL);
01028 }
01029
01030 void LLScrollListCtrl::deleteSelectedItems()
01031 {
01032 item_list::iterator iter;
01033 for (iter = mItemList.begin(); iter < mItemList.end(); )
01034 {
01035 LLScrollListItem* itemp = *iter;
01036 if (itemp->getSelected())
01037 {
01038 delete itemp;
01039 iter = mItemList.erase(iter);
01040 }
01041 else
01042 {
01043 iter++;
01044 }
01045 }
01046 mLastSelected = NULL;
01047 updateMaxContentWidth(NULL);
01048 }
01049
01050 void LLScrollListCtrl::highlightNthItem(S32 target_index)
01051 {
01052 if (mHighlightedItem != target_index)
01053 {
01054 mHighlightedItem = target_index;
01055 }
01056 }
01057
01058 S32 LLScrollListCtrl::selectMultiple( LLDynamicArray<LLUUID> ids )
01059 {
01060 item_list::iterator iter;
01061 S32 count = 0;
01062 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
01063 {
01064 LLScrollListItem* item = *iter;
01065 LLDynamicArray<LLUUID>::iterator iditr;
01066 for(iditr = ids.begin(); iditr != ids.end(); ++iditr)
01067 {
01068 if (item->getEnabled() && (item->getUUID() == (*iditr)))
01069 {
01070 selectItem(item,FALSE);
01071 ++count;
01072 break;
01073 }
01074 }
01075 if(ids.end() != iditr) ids.erase(iditr);
01076 }
01077
01078 if (mCommitOnSelectionChange)
01079 {
01080 commitIfChanged();
01081 }
01082 return count;
01083 }
01084
01085 S32 LLScrollListCtrl::getItemIndex( LLScrollListItem* target_item )
01086 {
01087 S32 index = 0;
01088 item_list::iterator iter;
01089 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
01090 {
01091 LLScrollListItem *itemp = *iter;
01092 if (target_item == itemp)
01093 {
01094 return index;
01095 }
01096 index++;
01097 }
01098 return -1;
01099 }
01100
01101 S32 LLScrollListCtrl::getItemIndex( LLUUID& target_id )
01102 {
01103 S32 index = 0;
01104 item_list::iterator iter;
01105 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
01106 {
01107 LLScrollListItem *itemp = *iter;
01108 if (target_id == itemp->getUUID())
01109 {
01110 return index;
01111 }
01112 index++;
01113 }
01114 return -1;
01115 }
01116
01117 void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
01118 {
01119 LLScrollListItem* prev_item = NULL;
01120
01121 if (!getFirstSelected())
01122 {
01123 selectFirstItem();
01124 }
01125 else
01126 {
01127 item_list::iterator iter;
01128 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
01129 {
01130 LLScrollListItem* cur_item = *iter;
01131
01132 if (cur_item->getSelected())
01133 {
01134 if (prev_item)
01135 {
01136 selectItem(prev_item, !extend_selection);
01137 }
01138 else
01139 {
01140 reportInvalidInput();
01141 }
01142 break;
01143 }
01144
01145 prev_item = cur_item;
01146 }
01147 }
01148
01149 if ((mCommitOnSelectionChange || mCommitOnKeyboardMovement))
01150 {
01151 commitIfChanged();
01152 }
01153
01154 mSearchString.clear();
01155 }
01156
01157
01158 void LLScrollListCtrl::selectNextItem( BOOL extend_selection)
01159 {
01160 if (!getFirstSelected())
01161 {
01162 selectFirstItem();
01163 }
01164 else
01165 {
01166 item_list::iterator iter;
01167 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
01168 {
01169 LLScrollListItem* item = *iter;
01170 if (item->getSelected())
01171 {
01172 if (++iter != mItemList.end())
01173 {
01174 LLScrollListItem *next_item = *iter;
01175 if (next_item)
01176 {
01177 selectItem(next_item, !extend_selection);
01178 }
01179 else
01180 {
01181 reportInvalidInput();
01182 }
01183 }
01184 break;
01185 }
01186 }
01187 }
01188
01189 if (mCommitOnKeyboardMovement)
01190 {
01191 onCommit();
01192 }
01193
01194 mSearchString.clear();
01195 }
01196
01197
01198
01199 void LLScrollListCtrl::deselectAllItems(BOOL no_commit_on_change)
01200 {
01201 item_list::iterator iter;
01202 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
01203 {
01204 LLScrollListItem* item = *iter;
01205 deselectItem(item);
01206 }
01207
01208 if (mCommitOnSelectionChange && !no_commit_on_change)
01209 {
01210 commitIfChanged();
01211 }
01212 }
01213
01215
01216
01217
01218 LLScrollListItem* LLScrollListCtrl::addSimpleItem(const LLString& item_text, EAddPosition pos, BOOL enabled)
01219 {
01220 LLScrollListItem* item = NULL;
01221 if (getItemCount() < mMaxItemCount)
01222 {
01223
01224 item = new LLScrollListItem( LLSD(item_text) );
01225 item->setEnabled(enabled);
01226 item->addColumn( item_text, gResMgr->getRes( LLFONT_SANSSERIF_SMALL ) );
01227 addItem( item, pos );
01228 }
01229 return item;
01230 }
01231
01232
01233
01234
01235 BOOL LLScrollListCtrl::selectSimpleItem(const LLString& label, BOOL case_sensitive)
01236 {
01237
01238 if (label.empty())
01239 {
01240 return FALSE;
01241 }
01242
01243 LLString target_text = label;
01244 if (!case_sensitive)
01245 {
01246 LLString::toLower(target_text);
01247 }
01248
01249 BOOL found = FALSE;
01250
01251 item_list::iterator iter;
01252 S32 index = 0;
01253 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
01254 {
01255 LLScrollListItem* item = *iter;
01256
01257 LLString item_text = item->getColumn(0)->getText();
01258 if (!case_sensitive)
01259 {
01260 LLString::toLower(item_text);
01261 }
01262 BOOL select = !found && item->getEnabled() && item_text == target_text;
01263 if (select)
01264 {
01265 selectItem(item);
01266 }
01267 found = found || select;
01268 index++;
01269 }
01270
01271 if (mCommitOnSelectionChange)
01272 {
01273 commitIfChanged();
01274 }
01275
01276 return found;
01277 }
01278
01279
01280 BOOL LLScrollListCtrl::selectSimpleItemByPrefix(const LLString& target, BOOL case_sensitive)
01281 {
01282 return selectSimpleItemByPrefix(utf8str_to_wstring(target), case_sensitive);
01283 }
01284
01285
01286
01287 BOOL LLScrollListCtrl::selectSimpleItemByPrefix(const LLWString& target, BOOL case_sensitive)
01288 {
01289 BOOL found = FALSE;
01290
01291 LLWString target_trimmed( target );
01292 S32 target_len = target_trimmed.size();
01293
01294 if( 0 == target_len )
01295 {
01296
01297 item_list::iterator iter;
01298 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
01299 {
01300 LLScrollListItem* item = *iter;
01301
01302 LLScrollListCell* cellp = item->getColumn(mSearchColumn);
01303 BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getText()[0]) : FALSE;
01304 if (select)
01305 {
01306 selectItem(item);
01307 found = TRUE;
01308 break;
01309 }
01310 }
01311 }
01312 else
01313 {
01314 if (!case_sensitive)
01315 {
01316
01317 LLWString::toLower(target_trimmed);
01318 }
01319
01320 for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
01321 {
01322 LLScrollListItem* item = *iter;
01323
01324
01325 LLScrollListCell* cellp = item->getColumn(mSearchColumn);
01326 if (!cellp)
01327 {
01328 continue;
01329 }
01330 LLWString item_label = utf8str_to_wstring(cellp->getText());
01331 if (!case_sensitive)
01332 {
01333 LLWString::toLower(item_label);
01334 }
01335
01336 LLWString trimmed_label = item_label;
01337 LLWString::trim(trimmed_label);
01338
01339 BOOL select = item->getEnabled() && trimmed_label.compare(0, target_trimmed.size(), target_trimmed) == 0;
01340
01341 if (select)
01342 {
01343
01344 S32 offset = item_label.find(target_trimmed);
01345 cellp->highlightText(offset, target_trimmed.size());
01346 selectItem(item);
01347 found = TRUE;
01348 break;
01349 }
01350 }
01351 }
01352
01353 if (mCommitOnSelectionChange)
01354 {
01355 commitIfChanged();
01356 }
01357
01358 return found;
01359 }
01360
01361 const LLString& LLScrollListCtrl::getSimpleSelectedItem(S32 column) const
01362 {
01363 LLScrollListItem* item;
01364
01365 item = getFirstSelected();
01366 if (item)
01367 {
01368 return item->getColumn(column)->getText();
01369 }
01370
01371 return LLString::null;
01372 }
01373
01375
01376
01377
01378 LLScrollListItem* LLScrollListCtrl::addStringUUIDItem(const LLString& item_text, const LLUUID& id, EAddPosition pos, BOOL enabled, S32 column_width)
01379 {
01380 LLScrollListItem* item = NULL;
01381 if (getItemCount() < mMaxItemCount)
01382 {
01383 item = new LLScrollListItem( enabled, NULL, id );
01384 item->addColumn(item_text, gResMgr->getRes(LLFONT_SANSSERIF_SMALL), column_width);
01385 addItem( item, pos );
01386 }
01387 return item;
01388 }
01389
01390 LLScrollListItem* LLScrollListCtrl::addSimpleItem(const LLString& item_text, LLSD sd, EAddPosition pos, BOOL enabled, S32 column_width)
01391 {
01392 LLScrollListItem* item = NULL;
01393 if (getItemCount() < mMaxItemCount)
01394 {
01395 item = new LLScrollListItem( sd );
01396 item->setEnabled(enabled);
01397 item->addColumn(item_text, gResMgr->getRes(LLFONT_SANSSERIF_SMALL), column_width);
01398 addItem( item, pos );
01399 }
01400 return item;
01401 }
01402
01403
01404
01405 BOOL LLScrollListCtrl::selectByID( const LLUUID& id )
01406 {
01407 return selectByValue( LLSD(id) );
01408 }
01409
01410 BOOL LLScrollListCtrl::setSelectedByValue(LLSD value, BOOL selected)
01411 {
01412 BOOL found = FALSE;
01413
01414 if (selected && !mAllowMultipleSelection) deselectAllItems(TRUE);
01415
01416 item_list::iterator iter;
01417 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
01418 {
01419 LLScrollListItem* item = *iter;
01420 if (item->getEnabled() && (item->getValue().asString() == value.asString()))
01421 {
01422 if (selected)
01423 {
01424 selectItem(item);
01425 }
01426 else
01427 {
01428 deselectItem(item);
01429 }
01430 found = TRUE;
01431 break;
01432 }
01433 }
01434
01435 if (mCommitOnSelectionChange)
01436 {
01437 commitIfChanged();
01438 }
01439
01440 return found;
01441 }
01442
01443 BOOL LLScrollListCtrl::isSelected(LLSD value)
01444 {
01445 item_list::iterator iter;
01446 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
01447 {
01448 LLScrollListItem* item = *iter;
01449 if (item->getValue().asString() == value.asString())
01450 {
01451 return item->getSelected();
01452 }
01453 }
01454 return FALSE;
01455 }
01456
01457 LLUUID LLScrollListCtrl::getStringUUIDSelectedItem()
01458 {
01459 LLScrollListItem* item = getFirstSelected();
01460
01461 if (item)
01462 {
01463 return item->getUUID();
01464 }
01465
01466 return LLUUID::null;
01467 }
01468
01469 LLSD LLScrollListCtrl::getSimpleSelectedValue()
01470 {
01471 LLScrollListItem* item = getFirstSelected();
01472
01473 if (item)
01474 {
01475 return item->getValue();
01476 }
01477 else
01478 {
01479 return LLSD();
01480 }
01481 }
01482
01483 void LLScrollListCtrl::drawItems()
01484 {
01485 S32 x = mItemListRect.mLeft;
01486 S32 y = mItemListRect.mTop - mLineHeight;
01487
01488
01489 S32 num_page_lines = mPageLines + 1;
01490
01491 LLRect item_rect;
01492
01493 LLGLSUIDefault gls_ui;
01494
01495 {
01496 LLRect clip_rect = mItemListRect;
01497 if(!mScrollbar->getVisible()) clip_rect.mRight += SCROLLBAR_SIZE;
01498 LLLocalClipRect clip(clip_rect);
01499
01500 S32 cur_x = x;
01501 S32 cur_y = y;
01502
01503 mDrewSelected = FALSE;
01504
01505 S32 line = 0;
01506 LLColor4 color;
01507 S32 max_columns = 0;
01508
01509 item_list::iterator iter;
01510 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
01511 {
01512 LLScrollListItem* item = *iter;
01513
01514 item_rect.setOriginAndSize(
01515 cur_x,
01516 cur_y,
01517 mScrollbar->getVisible() ? mItemListRect.getWidth() : mItemListRect.getWidth() + SCROLLBAR_SIZE,
01518 mLineHeight );
01519
01520
01521
01522 if (item->getSelected())
01523 {
01524 mDrewSelected = TRUE;
01525 }
01526
01527 max_columns = llmax(max_columns, item->getNumColumns());
01528
01529 LLRect bg_rect = item_rect;
01530
01531 bg_rect.stretch(LIST_BORDER_PAD, 0);
01532
01533 if( mScrollLines <= line && line < mScrollLines + num_page_lines )
01534 {
01535 if( item->getSelected() && mCanSelect)
01536 {
01537
01538 LLGLSNoTexture no_texture;
01539 glColor4fv(mBgSelectedColor.mV);
01540 gl_rect_2d( bg_rect );
01541
01542 color = mFgSelectedColor;
01543 }
01544 else if (mHighlightedItem == line && mCanSelect)
01545 {
01546 LLGLSNoTexture no_texture;
01547 glColor4fv(mHighlightedColor.mV);
01548 gl_rect_2d( bg_rect );
01549 color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
01550 }
01551 else
01552 {
01553 color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
01554 if (mDrawStripes && (line%2 == 0) && (max_columns > 1))
01555 {
01556 LLGLSNoTexture no_texture;
01557 glColor4fv(mBgStripeColor.mV);
01558 gl_rect_2d( bg_rect );
01559 }
01560 }
01561
01562 S32 line_x = cur_x;
01563 {
01564 S32 num_cols = item->getNumColumns();
01565 S32 cur_col = 0;
01566 S32 dynamic_width = 0;
01567 S32 dynamic_remainder = 0;
01568 bool first_dynamic = true;
01569 if(mNumDynamicWidthColumns > 0)
01570 {
01571 dynamic_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
01572 dynamic_remainder = (mItemListRect.getWidth() - mTotalStaticColumnWidth) % mNumDynamicWidthColumns;
01573 }
01574
01575 for (LLScrollListCell* cell = item->getColumn(0); cur_col < num_cols; cell = item->getColumn(++cur_col))
01576 {
01577 S32 cell_width = cell->getWidth();
01578
01579 if(mColumnsIndexed.size() > (U32)cur_col && mColumnsIndexed[cur_col] && mColumnsIndexed[cur_col]->mDynamicWidth)
01580 {
01581 cell_width = dynamic_width + (--dynamic_remainder ? 1 : 0);
01582 if(first_dynamic)
01583 {
01584 cell_width += mScrollbar->getVisible() ? 0 : SCROLLBAR_SIZE;
01585 first_dynamic = false;
01586 }
01587 cell->setWidth(cell_width);
01588 }
01589
01590 if (cell_width < 0
01591 || !cell->getVisible()) continue;
01592
01593 LLUI::pushMatrix();
01594 LLUI::translate((F32) cur_x, (F32) cur_y, 0.0f);
01595 S32 space_left = mItemListRect.mRight - cur_x;
01596 LLColor4 highlight_color = LLColor4::white;
01597 F32 type_ahead_timeout = LLUI::sConfigGroup->getF32("TypeAheadTimeout");
01598
01599 highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout, 0.4f, 0.f);
01600 cell->drawToWidth( space_left, color, highlight_color );
01601 LLUI::popMatrix();
01602
01603 cur_x += cell_width + mColumnPadding;
01604
01605 }
01606 }
01607 cur_x = line_x;
01608 cur_y -= mLineHeight;
01609 }
01610 line++;
01611 }
01612 }
01613 }
01614
01615
01616 void LLScrollListCtrl::draw()
01617 {
01618 if( getVisible() )
01619 {
01620 if (mNeedsScroll)
01621 {
01622 scrollToShowSelected();
01623 mNeedsScroll = FALSE;
01624 }
01625 LLRect background(0, mRect.getHeight(), mRect.getWidth(), 0);
01626
01627 if (mBackgroundVisible)
01628 {
01629 LLGLSNoTexture no_texture;
01630 glColor4fv( getEnabled() ? mBgWriteableColor.mV : mBgReadOnlyColor.mV );
01631 gl_rect_2d(background);
01632 }
01633
01634 drawItems();
01635
01636 if (mBorder)
01637 {
01638 mBorder->setKeyboardFocusHighlight(gFocusMgr.getKeyboardFocus() == this);
01639 }
01640
01641 LLUICtrl::draw();
01642 }
01643 }
01644
01645 void LLScrollListCtrl::setEnabled(BOOL enabled)
01646 {
01647 mCanSelect = enabled;
01648 setTabStop(enabled);
01649 mScrollbar->setTabStop(!enabled && mScrollbar->getPageSize() < mScrollbar->getDocSize());
01650 }
01651
01652 BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
01653 {
01654 BOOL handled = FALSE;
01655
01656 handled = mScrollbar->handleScrollWheel( 0, 0, clicks );
01657 return handled;
01658 }
01659
01660 BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
01661 {
01662 if (!mCanSelect) return FALSE;
01663
01664 BOOL selection_changed = FALSE;
01665
01666 LLScrollListItem* hit_item = hitItem(x, y);
01667 if( hit_item )
01668 {
01669 if( mAllowMultipleSelection )
01670 {
01671 if (mask & MASK_SHIFT)
01672 {
01673 if (mLastSelected == NULL)
01674 {
01675 selectItem(hit_item);
01676 }
01677 else
01678 {
01679
01680 bool selecting = false;
01681 item_list::iterator itor;
01682
01683
01684
01685 LLScrollListItem* lastSelected = mLastSelected;
01686 for (itor = mItemList.begin(); itor != mItemList.end(); ++itor)
01687 {
01688 if(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable)
01689 {
01690 if(mOnMaximumSelectCallback)
01691 {
01692 mOnMaximumSelectCallback(mCallbackUserData);
01693 }
01694 break;
01695 }
01696 LLScrollListItem *item = *itor;
01697 if (item == hit_item || item == lastSelected)
01698 {
01699 selectItem(item, FALSE);
01700 selecting = !selecting;
01701 }
01702 if (selecting)
01703 {
01704 selectItem(item, FALSE);
01705 }
01706 }
01707 }
01708 }
01709 else if (mask & MASK_CONTROL)
01710 {
01711 if (hit_item->getSelected())
01712 {
01713 deselectItem(hit_item);
01714 }
01715 else
01716 {
01717 if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable))
01718 {
01719 selectItem(hit_item, FALSE);
01720 }
01721 else
01722 {
01723 if(mOnMaximumSelectCallback)
01724 {
01725 mOnMaximumSelectCallback(mCallbackUserData);
01726 }
01727 }
01728 }
01729 }
01730 else
01731 {
01732 deselectAllItems(TRUE);
01733 selectItem(hit_item);
01734 }
01735 }
01736 else
01737 {
01738 selectItem(hit_item);
01739 }
01740
01741 hit_item->handleClick(x - mBorderThickness - LIST_BORDER_PAD,
01742 1, mask);
01743
01744 selection_changed = mSelectionChanged;
01745 if (mCommitOnSelectionChange)
01746 {
01747 commitIfChanged();
01748 }
01749
01750
01751 mSearchString.clear();
01752 }
01753 else
01754 {
01755
01756
01757 }
01758
01759 return selection_changed;
01760 }
01761
01762
01763 BOOL LLScrollListCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
01764 {
01765 BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
01766
01767 if( !handled )
01768 {
01769
01770 setFocus(TRUE);
01771
01772
01773 mSelectionChanged = FALSE;
01774
01775 gFocusMgr.setMouseCapture(this);
01776 selectItemAt(x, y, mask);
01777 mNeedsScroll = TRUE;
01778 }
01779
01780 return TRUE;
01781 }
01782
01783 BOOL LLScrollListCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
01784 {
01785 if (hasMouseCapture())
01786 {
01787
01788
01789 gFocusMgr.setMouseCapture(NULL);
01790 if(mask == MASK_NONE)
01791 {
01792 selectItemAt(x, y, mask);
01793 mNeedsScroll = TRUE;
01794 }
01795 }
01796
01797
01798 if (mItemListRect.pointInRect(x,y))
01799 {
01800 mDirty |= mSelectionChanged;
01801 mSelectionChanged = FALSE;
01802 onCommit();
01803 }
01804
01805 return LLUICtrl::handleMouseUp(x, y, mask);
01806 }
01807
01808 BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
01809 {
01810
01811 if(getVisible())
01812 {
01813
01814
01815 if (NULL == LLView::childrenHandleDoubleClick(x, y, mask))
01816 {
01817 if( mCanSelect && mOnDoubleClickCallback )
01818 {
01819 mOnDoubleClickCallback( mCallbackUserData );
01820 }
01821 }
01822 }
01823 return TRUE;
01824 }
01825
01826 LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y )
01827 {
01828
01829 LLScrollListItem* hit_item = NULL;
01830
01831 LLRect item_rect;
01832 item_rect.setLeftTopAndSize(
01833 mItemListRect.mLeft,
01834 mItemListRect.mTop,
01835 mItemListRect.getWidth(),
01836 mLineHeight );
01837
01838
01839 S32 num_page_lines = mPageLines + 1;
01840
01841 S32 line = 0;
01842 item_list::iterator iter;
01843 for(iter = mItemList.begin(); iter != mItemList.end(); iter++)
01844 {
01845 LLScrollListItem* item = *iter;
01846 if( mScrollLines <= line && line < mScrollLines + num_page_lines )
01847 {
01848 if( item->getEnabled() && item_rect.pointInRect( x, y ) )
01849 {
01850 hit_item = item;
01851 break;
01852 }
01853
01854 item_rect.translate(0, -mLineHeight);
01855 }
01856 line++;
01857 }
01858
01859 return hit_item;
01860 }
01861
01862
01863 BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
01864 {
01865 BOOL handled = FALSE;
01866
01867 if (hasMouseCapture())
01868 {
01869 if(mask == MASK_NONE)
01870 {
01871 selectItemAt(x, y, mask);
01872 mNeedsScroll = TRUE;
01873 }
01874 }
01875 else if (mCanSelect)
01876 {
01877 LLScrollListItem* item = hitItem(x, y);
01878 if (item)
01879 {
01880 highlightNthItem(getItemIndex(item));
01881 }
01882 else
01883 {
01884 highlightNthItem(-1);
01885 }
01886 }
01887
01888 handled = LLUICtrl::handleHover( x, y, mask );
01889
01890
01891
01892
01893
01894
01895
01896
01897 return handled;
01898 }
01899
01900
01901 BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent )
01902 {
01903 BOOL handled = FALSE;
01904
01905
01906 if (mCanSelect && !called_from_parent)
01907 {
01908
01909 mask = mask;
01910
01911 if (mask == MASK_NONE)
01912 {
01913 switch(key)
01914 {
01915 case KEY_UP:
01916 if (mAllowKeyboardMovement || hasFocus())
01917 {
01918
01919 selectPrevItem(FALSE);
01920 mNeedsScroll = TRUE;
01921 handled = TRUE;
01922 }
01923 break;
01924 case KEY_DOWN:
01925 if (mAllowKeyboardMovement || hasFocus())
01926 {
01927
01928 selectNextItem(FALSE);
01929 mNeedsScroll = TRUE;
01930 handled = TRUE;
01931 }
01932 break;
01933 case KEY_PAGE_UP:
01934 if (mAllowKeyboardMovement || hasFocus())
01935 {
01936 selectNthItem(getFirstSelectedIndex() - (mScrollbar->getPageSize() - 1));
01937 mNeedsScroll = TRUE;
01938 if (mCommitOnKeyboardMovement
01939 && !mCommitOnSelectionChange)
01940 {
01941 onCommit();
01942 }
01943 handled = TRUE;
01944 }
01945 break;
01946 case KEY_PAGE_DOWN:
01947 if (mAllowKeyboardMovement || hasFocus())
01948 {
01949 selectNthItem(getFirstSelectedIndex() + (mScrollbar->getPageSize() - 1));
01950 mNeedsScroll = TRUE;
01951 if (mCommitOnKeyboardMovement
01952 && !mCommitOnSelectionChange)
01953 {
01954 onCommit();
01955 }
01956 handled = TRUE;
01957 }
01958 break;
01959 case KEY_HOME:
01960 if (mAllowKeyboardMovement || hasFocus())
01961 {
01962 selectFirstItem();
01963 mNeedsScroll = TRUE;
01964 if (mCommitOnKeyboardMovement
01965 && !mCommitOnSelectionChange)
01966 {
01967 onCommit();
01968 }
01969 handled = TRUE;
01970 }
01971 break;
01972 case KEY_END:
01973 if (mAllowKeyboardMovement || hasFocus())
01974 {
01975 selectNthItem(getItemCount() - 1);
01976 mNeedsScroll = TRUE;
01977 if (mCommitOnKeyboardMovement
01978 && !mCommitOnSelectionChange)
01979 {
01980 onCommit();
01981 }
01982 handled = TRUE;
01983 }
01984 break;
01985 case KEY_RETURN:
01986
01987
01988
01989 if (!mCommitOnKeyboardMovement && mask == MASK_NONE && getVisible())
01990 {
01991 onCommit();
01992 mSearchString.clear();
01993 handled = TRUE;
01994 }
01995 break;
01996 case KEY_BACKSPACE:
01997 mSearchTimer.reset();
01998 if (mSearchString.size())
01999 {
02000 mSearchString.erase(mSearchString.size() - 1, 1);
02001 }
02002 if (mSearchString.empty())
02003 {
02004 if (getFirstSelected())
02005 {
02006 LLScrollListCell* cellp = getFirstSelected()->getColumn(mSearchColumn);
02007 if (cellp)
02008 {
02009 cellp->highlightText(0, 0);
02010 }
02011 }
02012 }
02013 else if (selectSimpleItemByPrefix(wstring_to_utf8str(mSearchString), FALSE))
02014 {
02015 mNeedsScroll = TRUE;
02016
02017 mSearchTimer.reset();
02018
02019 if (mCommitOnKeyboardMovement
02020 && !mCommitOnSelectionChange)
02021 {
02022 onCommit();
02023 }
02024 }
02025 break;
02026 default:
02027 break;
02028 }
02029 }
02030
02031 }
02032
02033 return handled;
02034 }
02035
02036 BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent)
02037 {
02038 if ((uni_char < 0x20) || (uni_char == 0x7F))
02039 {
02040 return FALSE;
02041 }
02042
02043
02044 if (mSearchTimer.getElapsedTimeF32() > LLUI::sConfigGroup->getF32("TypeAheadTimeout"))
02045 {
02046 mSearchString.clear();
02047 }
02048
02049
02050 uni_char = LLStringOps::toLower((llwchar)uni_char);
02051
02052 if (selectSimpleItemByPrefix(wstring_to_utf8str(mSearchString + (llwchar)uni_char), FALSE))
02053 {
02054
02055 mNeedsScroll = TRUE;
02056 mSearchString += uni_char;
02057 mSearchTimer.reset();
02058
02059 if (mCommitOnKeyboardMovement
02060 && !mCommitOnSelectionChange)
02061 {
02062 onCommit();
02063 }
02064 }
02065
02066 else if (isRepeatedChars(mSearchString + (llwchar)uni_char) && !mItemList.empty())
02067 {
02068
02069
02070 item_list::iterator start_iter = mItemList.begin();
02071 S32 first_selected = getFirstSelectedIndex();
02072
02073
02074 if (first_selected > 0)
02075 {
02076
02077 start_iter += first_selected;
02078 }
02079
02080
02081 item_list::iterator iter = start_iter;
02082 ++iter;
02083 if (iter == mItemList.end())
02084 {
02085 iter = mItemList.begin();
02086 }
02087
02088
02089 while(iter != start_iter)
02090 {
02091 LLScrollListItem* item = *iter;
02092
02093 LLScrollListCell* cellp = item->getColumn(mSearchColumn);
02094 if (cellp)
02095 {
02096
02097 LLWString item_label = utf8str_to_wstring(cellp->getText());
02098 if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char)
02099 {
02100 selectItem(item);
02101 mNeedsScroll = TRUE;
02102 cellp->highlightText(0, 1);
02103 mSearchTimer.reset();
02104
02105 if (mCommitOnKeyboardMovement
02106 && !mCommitOnSelectionChange)
02107 {
02108 onCommit();
02109 }
02110
02111 break;
02112 }
02113 }
02114
02115 ++iter;
02116 if (iter == mItemList.end())
02117 {
02118 iter = mItemList.begin();
02119 }
02120 }
02121 }
02122
02123 return TRUE;
02124 }
02125
02126
02127 void LLScrollListCtrl::reportInvalidInput()
02128 {
02129 make_ui_sound("UISndBadKeystroke");
02130 }
02131
02132 BOOL LLScrollListCtrl::isRepeatedChars(const LLWString& string) const
02133 {
02134 if (string.empty())
02135 {
02136 return FALSE;
02137 }
02138
02139 llwchar first_char = string[0];
02140
02141 for (U32 i = 0; i < string.size(); i++)
02142 {
02143 if (string[i] != first_char)
02144 {
02145 return FALSE;
02146 }
02147 }
02148
02149 return TRUE;
02150 }
02151
02152 void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_item)
02153 {
02154 if (!itemp) return;
02155
02156 if (!itemp->getSelected())
02157 {
02158 if (mLastSelected)
02159 {
02160 LLScrollListCell* cellp = mLastSelected->getColumn(mSearchColumn);
02161 if (cellp)
02162 {
02163 cellp->highlightText(0, 0);
02164 }
02165 }
02166 if (select_single_item)
02167 {
02168 deselectAllItems(TRUE);
02169 }
02170 itemp->setSelected(TRUE);
02171 mLastSelected = itemp;
02172 mSelectionChanged = TRUE;
02173 }
02174 }
02175
02176 void LLScrollListCtrl::deselectItem(LLScrollListItem* itemp)
02177 {
02178 if (!itemp) return;
02179
02180 if (itemp->getSelected())
02181 {
02182 if (mLastSelected == itemp)
02183 {
02184 mLastSelected = NULL;
02185 }
02186
02187 itemp->setSelected(FALSE);
02188 LLScrollListCell* cellp = itemp->getColumn(mSearchColumn);
02189 if (cellp)
02190 {
02191 cellp->highlightText(0, 0);
02192 }
02193 mSelectionChanged = TRUE;
02194 }
02195 }
02196
02197 void LLScrollListCtrl::commitIfChanged()
02198 {
02199 if (mSelectionChanged)
02200 {
02201 mDirty = TRUE;
02202 mSelectionChanged = FALSE;
02203 onCommit();
02204 }
02205 }
02206
02207 void LLScrollListCtrl::setSorted(BOOL sorted)
02208 {
02209 mSorted = sorted;
02210 }
02211
02212 BOOL LLScrollListCtrl::isSorted()
02213 {
02214 return mSorted;
02215 }
02216
02217
02218
02219 void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar, void* userdata )
02220 {
02221 LLScrollListCtrl* self = (LLScrollListCtrl*) userdata;
02222 self->mScrollLines = new_pos;
02223 }
02224
02225
02226
02227 void LLScrollListCtrl::sortByColumn(U32 column, BOOL ascending)
02228 {
02229 if (!mSorted || mSortColumn != column)
02230 {
02231 mSortColumn = column;
02232 std::sort(mItemList.begin(), mItemList.end(), SortScrollListItem(mSortColumn, mSortAscending));
02233 setSorted(TRUE);
02234 }
02235
02236
02237 if(mSortAscending != ascending)
02238 {
02239 std::reverse(mItemList.begin(), mItemList.end());
02240 mSortAscending = ascending;
02241 }
02242 }
02243
02251 void LLScrollListCtrl::sort()
02252 {
02253 std::sort(mItemList.begin(), mItemList.end(), SortScrollListItem(mSortColumn, mSortAscending));
02254 }
02255
02256 void LLScrollListCtrl::sortByColumn(LLString name, BOOL ascending)
02257 {
02258 if (name.empty())
02259 {
02260 sortByColumn(mSortColumn, mSortAscending);
02261 return;
02262 }
02263
02264 std::map<LLString, LLScrollListColumn>::iterator itor = mColumns.find(name);
02265 if (itor != mColumns.end())
02266 {
02267 sortByColumn((*itor).second.mIndex, ascending);
02268 }
02269 }
02270
02271 S32 LLScrollListCtrl::getScrollPos()
02272 {
02273 return mScrollbar->getDocPos();
02274 }
02275
02276
02277 void LLScrollListCtrl::setScrollPos( S32 pos )
02278 {
02279 mScrollbar->setDocPos( pos );
02280
02281 onScrollChange(mScrollbar->getDocPos(), mScrollbar, this);
02282 }
02283
02284
02285 void LLScrollListCtrl::scrollToShowSelected()
02286 {
02287
02288
02289 if (hasMouseCapture())
02290 {
02291 return;
02292 }
02293
02294 S32 index = getFirstSelectedIndex();
02295 if (index < 0)
02296 {
02297 return;
02298 }
02299
02300 LLScrollListItem* item = mItemList[index];
02301 if (!item)
02302 {
02303
02304 return;
02305 }
02306
02307 S32 lowest = mScrollLines;
02308 S32 highest = mScrollLines + mPageLines;
02309
02310 if (index < lowest)
02311 {
02312
02313 setScrollPos(index);
02314 }
02315 else if (highest <= index)
02316 {
02317 setScrollPos(index - mPageLines + 1);
02318 }
02319 }
02320
02321
02322 LLXMLNodePtr LLScrollListCtrl::getXML(bool save_children) const
02323 {
02324 LLXMLNodePtr node = LLUICtrl::getXML();
02325
02326
02327
02328 node->createChild("multi_select", TRUE)->setBoolValue(mAllowMultipleSelection);
02329
02330 node->createChild("draw_border", TRUE)->setBoolValue((mBorder != NULL));
02331
02332 node->createChild("draw_heading", TRUE)->setBoolValue(mDisplayColumnHeaders);
02333
02334 node->createChild("background_visible", TRUE)->setBoolValue(mBackgroundVisible);
02335
02336 node->createChild("draw_stripes", TRUE)->setBoolValue(mDrawStripes);
02337
02338 node->createChild("column_padding", TRUE)->setIntValue(mColumnPadding);
02339
02340 addColorXML(node, mBgWriteableColor, "bg_writeable_color", "ScrollBgWriteableColor");
02341 addColorXML(node, mBgReadOnlyColor, "bg_read_only_color", "ScrollBgReadOnlyColor");
02342 addColorXML(node, mBgSelectedColor, "bg_selected_color", "ScrollSelectedBGColor");
02343 addColorXML(node, mBgStripeColor, "bg_stripe_color", "ScrollBGStripeColor");
02344 addColorXML(node, mFgSelectedColor, "fg_selected_color", "ScrollSelectedFGColor");
02345 addColorXML(node, mFgUnselectedColor, "fg_unselected_color", "ScrollUnselectedColor");
02346 addColorXML(node, mFgDisabledColor, "fg_disable_color", "ScrollDisabledColor");
02347 addColorXML(node, mHighlightedColor, "highlighted_color", "ScrollHighlightedColor");
02348
02349
02350
02351 std::map<LLString, LLScrollListColumn>::const_iterator itor;
02352 std::vector<const LLScrollListColumn*> sorted_list;
02353 sorted_list.resize(mColumns.size());
02354 for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
02355 {
02356 sorted_list[itor->second.mIndex] = &itor->second;
02357 }
02358
02359 std::vector<const LLScrollListColumn*>::iterator itor2;
02360 for (itor2 = sorted_list.begin(); itor2 != sorted_list.end(); ++itor2)
02361 {
02362 LLXMLNodePtr child_node = node->createChild("column", FALSE);
02363 const LLScrollListColumn *column = *itor2;
02364
02365 child_node->createChild("name", TRUE)->setStringValue(column->mName);
02366 child_node->createChild("label", TRUE)->setStringValue(column->mLabel);
02367 child_node->createChild("width", TRUE)->setIntValue(column->mWidth);
02368 }
02369
02370 return node;
02371 }
02372
02373 void LLScrollListCtrl::setScrollListParameters(LLXMLNodePtr node)
02374 {
02375
02376
02377
02378 LLColor4 color;
02379 if(node->hasAttribute("fg_unselected_color"))
02380 {
02381 LLUICtrlFactory::getAttributeColor(node,"fg_unselected_color", color);
02382 setFgUnselectedColor(color);
02383 }
02384 if(node->hasAttribute("fg_selected_color"))
02385 {
02386 LLUICtrlFactory::getAttributeColor(node,"fg_selected_color", color);
02387 setFgSelectedColor(color);
02388 }
02389 if(node->hasAttribute("bg_selected_color"))
02390 {
02391 LLUICtrlFactory::getAttributeColor(node,"bg_selected_color", color);
02392 setBgSelectedColor(color);
02393 }
02394 if(node->hasAttribute("fg_disable_color"))
02395 {
02396 LLUICtrlFactory::getAttributeColor(node,"fg_disable_color", color);
02397 setFgDisableColor(color);
02398 }
02399 if(node->hasAttribute("bg_writeable_color"))
02400 {
02401 LLUICtrlFactory::getAttributeColor(node,"bg_writeable_color", color);
02402 setBgWriteableColor(color);
02403 }
02404 if(node->hasAttribute("bg_read_only_color"))
02405 {
02406 LLUICtrlFactory::getAttributeColor(node,"bg_read_only_color", color);
02407 setReadOnlyBgColor(color);
02408 }
02409 if (LLUICtrlFactory::getAttributeColor(node,"bg_stripe_color", color))
02410 {
02411 setBgStripeColor(color);
02412 }
02413 if (LLUICtrlFactory::getAttributeColor(node,"highlighted_color", color))
02414 {
02415 setHighlightedColor(color);
02416 }
02417
02418 if(node->hasAttribute("background_visible"))
02419 {
02420 BOOL background_visible;
02421 node->getAttributeBOOL("background_visible", background_visible);
02422 setBackgroundVisible(background_visible);
02423 }
02424
02425 if(node->hasAttribute("draw_stripes"))
02426 {
02427 BOOL draw_stripes;
02428 node->getAttributeBOOL("draw_stripes", draw_stripes);
02429 setDrawStripes(draw_stripes);
02430 }
02431
02432 if(node->hasAttribute("column_padding"))
02433 {
02434 S32 column_padding;
02435 node->getAttributeS32("column_padding", column_padding);
02436 setColumnPadding(column_padding);
02437 }
02438 }
02439
02440
02441 LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
02442 {
02443 LLString name("scroll_list");
02444 node->getAttributeString("name", name);
02445
02446 LLRect rect;
02447 createRect(node, rect, parent, LLRect());
02448
02449 BOOL multi_select = FALSE;
02450 node->getAttributeBOOL("multi_select", multi_select);
02451
02452 BOOL draw_border = TRUE;
02453 node->getAttributeBOOL("draw_border", draw_border);
02454
02455 BOOL draw_heading = FALSE;
02456 node->getAttributeBOOL("draw_heading", draw_heading);
02457
02458 BOOL collapse_empty_columns = FALSE;
02459 node->getAttributeBOOL("collapse_empty_columns", collapse_empty_columns);
02460
02461 S32 search_column = 0;
02462 node->getAttributeS32("search_column", search_column);
02463
02464 LLUICtrlCallback callback = NULL;
02465
02466 LLScrollListCtrl* scroll_list = new LLScrollListCtrl(
02467 name,
02468 rect,
02469 callback,
02470 NULL,
02471 multi_select,
02472 draw_border);
02473
02474 scroll_list->setDisplayHeading(draw_heading);
02475 if (node->hasAttribute("heading_height"))
02476 {
02477 S32 heading_height;
02478 node->getAttributeS32("heading_height", heading_height);
02479 scroll_list->setHeadingHeight(heading_height);
02480 }
02481 scroll_list->setCollapseEmptyColumns(collapse_empty_columns);
02482
02483 scroll_list->setScrollListParameters(node);
02484
02485 scroll_list->initFromXML(node, parent);
02486
02487 scroll_list->setSearchColumn(search_column);
02488
02489 LLSD columns;
02490 S32 index = 0;
02491 LLXMLNodePtr child;
02492 S32 total_static = 0, num_dynamic = 0;
02493 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
02494 {
02495 if (child->hasName("column"))
02496 {
02497 LLString labelname("");
02498 child->getAttributeString("label", labelname);
02499
02500 LLString columnname(labelname);
02501 child->getAttributeString("name", columnname);
02502
02503 LLString sortname(columnname);
02504 child->getAttributeString("sort", sortname);
02505
02506 BOOL sort_ascending = TRUE;
02507 child->getAttributeBOOL("sort_ascending", sort_ascending);
02508
02509 LLString imagename;
02510 child->getAttributeString("image", imagename);
02511
02512 BOOL columndynamicwidth = FALSE;
02513 child->getAttributeBOOL("dynamicwidth", columndynamicwidth);
02514
02515 S32 columnwidth = -1;
02516 child->getAttributeS32("width", columnwidth);
02517
02518 if(!columndynamicwidth) total_static += columnwidth;
02519 else ++num_dynamic;
02520
02521 F32 columnrelwidth = 0.f;
02522 child->getAttributeF32("relwidth", columnrelwidth);
02523
02524 LLFontGL::HAlign h_align = LLFontGL::LEFT;
02525 h_align = LLView::selectFontHAlign(child);
02526
02527 columns[index]["name"] = columnname;
02528 columns[index]["sort"] = sortname;
02529 columns[index]["sort_ascending"] = sort_ascending;
02530 columns[index]["image"] = imagename;
02531 columns[index]["label"] = labelname;
02532 columns[index]["width"] = columnwidth;
02533 columns[index]["relwidth"] = columnrelwidth;
02534 columns[index]["dynamicwidth"] = columndynamicwidth;
02535 columns[index]["halign"] = (S32)h_align;
02536 index++;
02537 }
02538 }
02539 scroll_list->setNumDynamicColumns(num_dynamic);
02540 scroll_list->setTotalStaticColumnWidth(total_static);
02541 scroll_list->setColumnHeadings(columns);
02542
02543 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
02544 {
02545 if (child->hasName("row"))
02546 {
02547 LLUUID id;
02548 child->getAttributeUUID("id", id);
02549
02550 LLSD row;
02551
02552 row["id"] = id;
02553
02554 S32 column_idx = 0;
02555 LLXMLNodePtr row_child;
02556 for (row_child = child->getFirstChild(); row_child.notNull(); row_child = row_child->getNextSibling())
02557 {
02558 if (row_child->hasName("column"))
02559 {
02560 LLString value = row_child->getTextContents();
02561
02562 LLString columnname("");
02563 row_child->getAttributeString("name", columnname);
02564
02565 LLString font("");
02566 row_child->getAttributeString("font", font);
02567
02568 LLString font_style("");
02569 row_child->getAttributeString("font-style", font_style);
02570
02571 row["columns"][column_idx]["column"] = columnname;
02572 row["columns"][column_idx]["value"] = value;
02573 row["columns"][column_idx]["font"] = font;
02574 row["columns"][column_idx]["font-style"] = font_style;
02575 column_idx++;
02576 }
02577 }
02578 scroll_list->addElement(row);
02579 }
02580 }
02581
02582 LLString contents = node->getTextContents();
02583 if (!contents.empty())
02584 {
02585 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
02586 boost::char_separator<char> sep("\t\n");
02587 tokenizer tokens(contents, sep);
02588 tokenizer::iterator token_iter = tokens.begin();
02589
02590 while(token_iter != tokens.end())
02591 {
02592 const char* line = token_iter->c_str();
02593 scroll_list->addSimpleItem(line);
02594 ++token_iter;
02595 }
02596 }
02597
02598 return scroll_list;
02599 }
02600
02601
02602
02603
02604 void LLScrollListCtrl::copy()
02605 {
02606 LLString buffer;
02607
02608 std::vector<LLScrollListItem*> items = getAllSelected();
02609 std::vector<LLScrollListItem*>::iterator itor;
02610 for (itor = items.begin(); itor != items.end(); ++itor)
02611 {
02612 buffer += (*itor)->getContentsCSV() + "\n";
02613 }
02614 gClipboard.copyFromSubstring(utf8str_to_wstring(buffer), 0, buffer.length());
02615 }
02616
02617
02618 BOOL LLScrollListCtrl::canCopy()
02619 {
02620 return (getFirstSelected() != NULL);
02621 }
02622
02623
02624 void LLScrollListCtrl::cut()
02625 {
02626 copy();
02627 doDelete();
02628 }
02629
02630
02631 BOOL LLScrollListCtrl::canCut()
02632 {
02633 return canCopy() && canDoDelete();
02634 }
02635
02636
02637 void LLScrollListCtrl::doDelete()
02638 {
02639
02640 }
02641
02642
02643 BOOL LLScrollListCtrl::canDoDelete()
02644 {
02645
02646 return FALSE;
02647 }
02648
02649
02650 void LLScrollListCtrl::selectAll()
02651 {
02652
02653 item_list::iterator iter;
02654 for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
02655 {
02656 LLScrollListItem *itemp = *iter;
02657 if( itemp->getEnabled() )
02658 {
02659 selectItem(itemp, FALSE);
02660 }
02661 }
02662
02663 if (mCommitOnSelectionChange)
02664 {
02665 commitIfChanged();
02666 }
02667 }
02668
02669
02670 BOOL LLScrollListCtrl::canSelectAll()
02671 {
02672 return getCanSelect() && mAllowMultipleSelection && !(mMaxSelectable > 0 && mItemList.size() > mMaxSelectable);
02673 }
02674
02675
02676 void LLScrollListCtrl::deselect()
02677 {
02678 deselectAllItems();
02679 }
02680
02681
02682 BOOL LLScrollListCtrl::canDeselect()
02683 {
02684 return getCanSelect();
02685 }
02686
02687 void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
02688 {
02689 LLString name = column["name"].asString();
02690 if (mColumns.empty())
02691 {
02692 mDefaultColumn = 0;
02693 }
02694
02695 if (name.empty())
02696 {
02697 std::ostringstream new_name;
02698 new_name << mColumnsIndexed.size();
02699 name = new_name.str();
02700 }
02701 if (mColumns.find(name) == mColumns.end())
02702 {
02703
02704 mColumns[name] = LLScrollListColumn(column);
02705 LLScrollListColumn* new_column = &mColumns[name];
02706 new_column->mParentCtrl = this;
02707 new_column->mIndex = mColumns.size()-1;
02708
02709
02710 if (new_column->mWidth > 0 || new_column->mRelWidth > 0 || new_column->mDynamicWidth)
02711 {
02712 if (new_column->mRelWidth >= 0)
02713 {
02714 new_column->mWidth = (S32)llround(new_column->mRelWidth*mItemListRect.getWidth());
02715 }
02716 else if(new_column->mDynamicWidth)
02717 {
02718 new_column->mWidth = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
02719 }
02720 S32 top = mItemListRect.mTop;
02721 S32 left = mItemListRect.mLeft;
02722 {
02723 std::map<LLString, LLScrollListColumn>::iterator itor;
02724 for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
02725 {
02726 if (itor->second.mIndex < new_column->mIndex &&
02727 itor->second.mWidth > 0)
02728 {
02729 left += itor->second.mWidth + mColumnPadding;
02730 }
02731 }
02732 }
02733 LLString button_name = "btn_" + name;
02734 S32 right = left+new_column->mWidth;
02735 if (new_column->mIndex != (S32)mColumns.size()-1)
02736 {
02737 right += mColumnPadding;
02738 }
02739 LLRect temp_rect = LLRect(left,top+mHeadingHeight,right,top);
02740 new_column->mHeader = new LLColumnHeader(button_name, temp_rect, new_column);
02741 if(column["image"].asString() != "")
02742 {
02743
02744 new_column->mHeader->setImage(column["image"].asString());
02745 }
02746 else
02747 {
02748 new_column->mHeader->setLabel(new_column->mLabel);
02749
02750 }
02751
02752
02753 new_column->mHeader->setTabStop(FALSE);
02754 addChild(new_column->mHeader);
02755 new_column->mHeader->setVisible(mDisplayColumnHeaders);
02756
02757
02758
02759 removeChild(mScrollbar);
02760 addChild(mScrollbar);
02761
02762 }
02763 }
02764 updateColumns();
02765 }
02766
02767
02768 void LLScrollListCtrl::onClickColumn(void *userdata)
02769 {
02770 LLScrollListColumn *info = (LLScrollListColumn*)userdata;
02771 if (!info) return;
02772
02773 LLScrollListCtrl *parent = info->mParentCtrl;
02774 if (!parent) return;
02775
02776 U32 column_index = info->mIndex;
02777
02778 LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex];
02779 bool ascending = column->mSortAscending;
02780 if (column->mSortingColumn != column->mName)
02781 {
02782 if (parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end())
02783 {
02784 LLScrollListColumn& info_redir = parent->mColumns[column->mSortingColumn];
02785 column_index = info_redir.mIndex;
02786 }
02787 }
02788
02789 if (column_index == parent->mSortColumn)
02790 {
02791 ascending = !parent->mSortAscending;
02792 }
02793
02794 parent->sortByColumn(column_index, ascending);
02795
02796 if (parent->mOnSortChangedCallback)
02797 {
02798 parent->mOnSortChangedCallback(parent->getCallbackUserData());
02799 }
02800 }
02801
02802 std::string LLScrollListCtrl::getSortColumnName()
02803 {
02804 LLScrollListColumn* column = mSortColumn >= 0 ? mColumnsIndexed[mSortColumn] : NULL;
02805
02806 if (column) return column->mName;
02807 else return "";
02808 }
02809
02810 void LLScrollListCtrl::clearColumns()
02811 {
02812 std::map<LLString, LLScrollListColumn>::iterator itor;
02813 for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
02814 {
02815 LLColumnHeader *header = itor->second.mHeader;
02816 if (header)
02817 {
02818 removeChild(header);
02819 delete header;
02820 }
02821 }
02822 mColumns.clear();
02823 }
02824
02825 void LLScrollListCtrl::setColumnLabel(const LLString& column, const LLString& label)
02826 {
02827 std::map<LLString, LLScrollListColumn>::iterator itor = mColumns.find(column);
02828 if (itor != mColumns.end())
02829 {
02830 itor->second.mLabel = label;
02831 if (itor->second.mHeader)
02832 {
02833 itor->second.mHeader->setLabel(label);
02834 }
02835 }
02836 }
02837
02838 LLScrollListColumn* LLScrollListCtrl::getColumn(S32 index)
02839 {
02840 if (index < 0 || index >= (S32)mColumnsIndexed.size())
02841 {
02842 return NULL;
02843 }
02844 return mColumnsIndexed[index];
02845 }
02846
02847 void LLScrollListCtrl::setColumnHeadings(LLSD headings)
02848 {
02849 mColumns.clear();
02850 LLSD::array_const_iterator itor;
02851 for (itor = headings.beginArray(); itor != headings.endArray(); ++itor)
02852 {
02853 addColumn(*itor);
02854 }
02855 }
02856
02857 LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition pos, void* userdata)
02858 {
02859
02860 LLSD id = value["id"];
02861
02862 LLScrollListItem *new_item = new LLScrollListItem(id, userdata);
02863 if (value.has("enabled"))
02864 {
02865 new_item->setEnabled( value["enabled"].asBoolean() );
02866 }
02867
02868 new_item->setNumColumns(mColumns.size());
02869
02870
02871 LLSD columns = value["columns"];
02872 LLSD::array_const_iterator itor;
02873 S32 col_index = 0 ;
02874 for (itor = columns.beginArray(); itor != columns.endArray(); ++itor)
02875 {
02876 LLString column = (*itor)["column"].asString();
02877
02878 if (mColumns.size() == 0)
02879 {
02880 mDefaultColumn = 0;
02881 }
02882
02883 LLScrollListColumn* columnp = NULL;
02884
02885
02886 if (column.empty())
02887 {
02888 std::ostringstream new_name;
02889 new_name << col_index;
02890 column = new_name.str();
02891 }
02892
02893 std::map<LLString, LLScrollListColumn>::iterator column_itor;
02894 column_itor = mColumns.find(column);
02895 if (column_itor != mColumns.end())
02896 {
02897 columnp = &column_itor->second;
02898 }
02899
02900
02901 if (!columnp)
02902 {
02903 LLSD new_column;
02904 new_column["name"] = column;
02905 new_column["label"] = column;
02906 new_column["width"] = (*itor)["width"];
02907 addColumn(new_column);
02908 columnp = &mColumns.find(column)->second;
02909 new_item->setNumColumns(mColumns.size());
02910 }
02911
02912 S32 index = columnp->mIndex;
02913 S32 width = columnp->mWidth;
02914 LLFontGL::HAlign font_alignment = columnp->mFontAlignment;
02915
02916 LLSD value = (*itor)["value"];
02917 LLString fontname = (*itor)["font"].asString();
02918 LLString fontstyle = (*itor)["font-style"].asString();
02919 LLString type = (*itor)["type"].asString();
02920 BOOL has_color = (*itor).has("color");
02921 LLColor4 color = ((*itor)["color"]);
02922
02923 const LLFontGL *font = gResMgr->getRes(fontname);
02924 if (!font)
02925 {
02926 font = gResMgr->getRes( LLFONT_SANSSERIF_SMALL );
02927 }
02928 U8 font_style = LLFontGL::getStyleFromString(fontstyle);
02929
02930 if (type == "icon")
02931 {
02932 LLUUID image_id = value.asUUID();
02933 LLImageGL* icon = LLUI::sImageProvider->getUIImageByID(image_id);
02934 LLScrollListIcon* cell = new LLScrollListIcon(icon, width, image_id);
02935 if (has_color)
02936 {
02937 cell->setColor(color);
02938 }
02939 new_item->setColumn(index, cell);
02940 }
02941 else if (type == "checkbox")
02942 {
02943 LLCheckBoxCtrl* ctrl = new LLCheckBoxCtrl(value.asString(),
02944 LLRect(0, 0, width, width), "label");
02945 LLScrollListCheck* cell = new LLScrollListCheck(ctrl,width);
02946 if (has_color)
02947 {
02948 cell->setColor(color);
02949 }
02950 new_item->setColumn(index, cell);
02951 }
02952 else if (type == "separator")
02953 {
02954 LLScrollListSeparator* cell = new LLScrollListSeparator(width);
02955 if (has_color)
02956 {
02957 cell->setColor(color);
02958 }
02959 new_item->setColumn(index, cell);
02960 }
02961 else
02962 {
02963 LLScrollListText* cell = new LLScrollListText(value.asString(), font, width, font_style, font_alignment);
02964 if (has_color)
02965 {
02966 cell->setColor(color);
02967 }
02968 new_item->setColumn(index, cell);
02969 if (columnp->mHeader && !value.asString().empty())
02970 {
02971 columnp->mHeader->setHasResizableElement(TRUE);
02972 }
02973 }
02974
02975 col_index++;
02976 }
02977
02978 S32 num_columns = mColumns.size();
02979 for (S32 column = 0; column < num_columns; ++column)
02980 {
02981 if (new_item->getColumn(column) == NULL)
02982 {
02983 LLScrollListColumn* column_ptr = mColumnsIndexed[column];
02984 new_item->setColumn(column, new LLScrollListText("", gResMgr->getRes( LLFONT_SANSSERIF_SMALL ), column_ptr->mWidth, LLFontGL::NORMAL));
02985 }
02986 }
02987
02988 addItem(new_item, pos);
02989
02990 return new_item;
02991 }
02992
02993 LLScrollListItem* LLScrollListCtrl::addSimpleElement(const LLString& value, EAddPosition pos, const LLSD& id)
02994 {
02995 LLSD entry_id = id;
02996
02997 if (id.isUndefined())
02998 {
02999 entry_id = value;
03000 }
03001
03002 LLScrollListItem *new_item = new LLScrollListItem(entry_id);
03003
03004 const LLFontGL *font = gResMgr->getRes( LLFONT_SANSSERIF_SMALL );
03005
03006 new_item->addColumn(value, font, getRect().getWidth());
03007
03008 addItem(new_item, pos);
03009 return new_item;
03010 }
03011
03012 void LLScrollListCtrl::setValue(const LLSD& value )
03013 {
03014 LLSD::array_const_iterator itor;
03015 for (itor = value.beginArray(); itor != value.endArray(); ++itor)
03016 {
03017 addElement(*itor);
03018 }
03019 }
03020
03021 LLSD LLScrollListCtrl::getValue() const
03022 {
03023 LLScrollListItem *item = getFirstSelected();
03024 if (!item) return LLSD();
03025 return item->getValue();
03026 }
03027
03028 BOOL LLScrollListCtrl::operateOnSelection(EOperation op)
03029 {
03030 if (op == OP_DELETE)
03031 {
03032 deleteSelectedItems();
03033 return TRUE;
03034 }
03035 else if (op == OP_DESELECT)
03036 {
03037 deselectAllItems();
03038 }
03039 return FALSE;
03040 }
03041
03042 BOOL LLScrollListCtrl::operateOnAll(EOperation op)
03043 {
03044 if (op == OP_DELETE)
03045 {
03046 clearRows();
03047 return TRUE;
03048 }
03049 else if (op == OP_DESELECT)
03050 {
03051 deselectAllItems();
03052 }
03053 else if (op == OP_SELECT)
03054 {
03055 selectAll();
03056 }
03057 return FALSE;
03058 }
03059
03060 void LLScrollListCtrl::setFocus(BOOL b)
03061 {
03062 mSearchString.clear();
03063
03064 if (!getFirstSelected())
03065 {
03066 selectFirstItem();
03067
03068 }
03069 LLUICtrl::setFocus(b);
03070 }
03071
03072
03073
03074 BOOL LLScrollListCtrl::isDirty() const
03075 {
03076 BOOL grubby = mDirty;
03077 if ( !mAllowMultipleSelection )
03078 {
03079 grubby = (mOriginalSelection != getFirstSelectedIndex());
03080 }
03081 return grubby;
03082 }
03083
03084
03085 void LLScrollListCtrl::resetDirty()
03086 {
03087 mDirty = FALSE;
03088 mOriginalSelection = getFirstSelectedIndex();
03089 }
03090
03091
03092
03093 void LLScrollListCtrl::onFocusReceived()
03094 {
03095
03096 mSelectionChanged = FALSE;
03097 }
03098
03099
03100 void LLScrollListCtrl::onFocusLost()
03101 {
03102 if (mIsPopup)
03103 {
03104 if (getParent())
03105 {
03106 getParent()->onFocusLost();
03107 }
03108 }
03109 if (hasMouseCapture())
03110 {
03111 gFocusMgr.setMouseCapture(NULL);
03112 }
03113 LLUICtrl::onFocusLost();
03114 }
03115
03116 LLColumnHeader::LLColumnHeader(const LLString& label, const LLRect &rect, LLScrollListColumn* column, const LLFontGL* fontp) :
03117 LLComboBox(label, rect, label, NULL, NULL),
03118 mColumn(column),
03119 mOrigLabel(label),
03120 mShowSortOptions(FALSE),
03121 mHasResizableElement(FALSE)
03122 {
03123 mListPosition = LLComboBox::ABOVE;
03124 setCommitCallback(onSelectSort);
03125 setCallbackUserData(this);
03126 mButton->setTabStop(FALSE);
03127
03128 mButton->setHeldDownDelay(LLUI::sConfigGroup->getF32("ColumnHeaderDropDownDelay"), 2);
03129 mButton->setHeldDownCallback(onHeldDown);
03130 mButton->setClickedCallback(onClick);
03131 mButton->setMouseDownCallback(onMouseDown);
03132
03133 mButton->setCallbackUserData(this);
03134
03135 mAscendingText = "[LOW]...[HIGH](Ascending)";
03136 mDescendingText = "[HIGH]...[LOW](Descending)";
03137
03138 mList->reshape(llmax(mList->getRect().getWidth(), 110, mRect.getWidth()), mList->getRect().getHeight());
03139
03140
03141 const S32 RESIZE_BAR_THICKNESS = 3;
03142 mResizeBar = new LLResizeBar(
03143 "resizebar",
03144 this,
03145 LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0),
03146 MIN_COLUMN_WIDTH, S32_MAX, LLResizeBar::RIGHT );
03147 addChild(mResizeBar);
03148
03149 mResizeBar->setEnabled(FALSE);
03150 }
03151
03152 LLColumnHeader::~LLColumnHeader()
03153 {
03154 }
03155
03156 void LLColumnHeader::draw()
03157 {
03158 if( getVisible() )
03159 {
03160 mDrawArrow = !mColumn->mLabel.empty() && mColumn->mParentCtrl->isSorted() && mColumn->mParentCtrl->getSortColumnName() == mColumn->mSortingColumn;
03161
03162 BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
03163 mArrowImage = is_ascending ? LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("up_arrow.tga")))
03164 : LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("down_arrow.tga")));
03165
03166
03167
03168
03169
03170
03171
03172
03173 LLComboBox::draw();
03174
03175 if (mList->getVisible())
03176 {
03177
03178 mColumn->mParentCtrl->sortByColumn(mColumn->mSortingColumn, getCurrentIndex() == 0);
03179 }
03180
03181 }
03182 }
03183
03184 BOOL LLColumnHeader::handleDoubleClick(S32 x, S32 y, MASK mask)
03185 {
03186 if (canResize() && mResizeBar->getRect().pointInRect(x, y))
03187 {
03188
03189 LLRect column_rect = getRect();
03190 column_rect.mRight = column_rect.mLeft + mColumn->mMaxContentWidth;
03191 userSetShape(column_rect);
03192 }
03193 else
03194 {
03195 onClick(this);
03196 }
03197 return TRUE;
03198 }
03199
03200 void LLColumnHeader::setImage(const LLString &image_name)
03201 {
03202 if (mButton)
03203 {
03204 mButton->setImageSelected(image_name);
03205 mButton->setImageUnselected(image_name);
03206 }
03207 }
03208
03209
03210 void LLColumnHeader::onClick(void* user_data)
03211 {
03212 LLColumnHeader* headerp = (LLColumnHeader*)user_data;
03213 if (!headerp) return;
03214
03215 LLScrollListColumn* column = headerp->mColumn;
03216 if (!column) return;
03217
03218 if (headerp->mList->getVisible())
03219 {
03220 headerp->hideList();
03221 }
03222
03223 LLScrollListCtrl::onClickColumn(column);
03224
03225
03226 headerp->mList->selectNthItem(column->mParentCtrl->getSortAscending() ? 0 : 1);
03227 }
03228
03229
03230 void LLColumnHeader::onMouseDown(void* user_data)
03231 {
03232
03233 return;
03234 }
03235
03236
03237 void LLColumnHeader::onHeldDown(void* user_data)
03238 {
03239 LLColumnHeader* headerp = (LLColumnHeader*)user_data;
03240 headerp->showList();
03241 }
03242
03243 void LLColumnHeader::showList()
03244 {
03245 if (mShowSortOptions)
03246 {
03247
03248 mOrigLabel = mButton->getLabelSelected();
03249
03250
03251 mColumn->mParentCtrl->sortByColumn(mColumn->mSortingColumn, mColumn->mParentCtrl->getSortAscending());
03252
03253 LLString low_item_text;
03254 LLString high_item_text;
03255
03256 LLScrollListItem* itemp = mColumn->mParentCtrl->getFirstData();
03257 if (itemp)
03258 {
03259 LLScrollListCell* cell = itemp->getColumn(mColumn->mIndex);
03260 if (cell && cell->isText())
03261 {
03262 if (mColumn->mParentCtrl->getSortAscending())
03263 {
03264 low_item_text = cell->getText();
03265 }
03266 else
03267 {
03268 high_item_text = cell->getText();
03269 }
03270 }
03271 }
03272
03273 itemp = mColumn->mParentCtrl->getLastData();
03274 if (itemp)
03275 {
03276 LLScrollListCell* cell = itemp->getColumn(mColumn->mIndex);
03277 if (cell && cell->isText())
03278 {
03279 if (mColumn->mParentCtrl->getSortAscending())
03280 {
03281 high_item_text = cell->getText();
03282 }
03283 else
03284 {
03285 low_item_text = cell->getText();
03286 }
03287 }
03288 }
03289
03290 LLString::truncate(low_item_text, 3);
03291 LLString::truncate(high_item_text, 3);
03292
03293 LLString ascending_string;
03294 LLString descending_string;
03295
03296 if (low_item_text.empty() || high_item_text.empty())
03297 {
03298 ascending_string = "Ascending";
03299 descending_string = "Descending";
03300 }
03301 else
03302 {
03303 mAscendingText.setArg("[LOW]", low_item_text);
03304 mAscendingText.setArg("[HIGH]", high_item_text);
03305 mDescendingText.setArg("[LOW]", low_item_text);
03306 mDescendingText.setArg("[HIGH]", high_item_text);
03307 ascending_string = mAscendingText.getString();
03308 descending_string = mDescendingText.getString();
03309 }
03310
03311 S32 text_width = LLFontGL::sSansSerifSmall->getWidth(ascending_string);
03312 text_width = llmax(text_width, LLFontGL::sSansSerifSmall->getWidth(descending_string)) + 10;
03313 text_width = llmax(text_width, mRect.getWidth() - 30);
03314
03315 mList->getColumn(0)->mWidth = text_width;
03316 ((LLScrollListText*)mList->getFirstData()->getColumn(0))->setText(ascending_string);
03317 ((LLScrollListText*)mList->getLastData()->getColumn(0))->setText(descending_string);
03318
03319 mList->reshape(llmax(text_width + 30, 110, mRect.getWidth()), mList->getRect().getHeight());
03320
03321 LLComboBox::showList();
03322 }
03323 }
03324
03325
03326 void LLColumnHeader::onSelectSort(LLUICtrl* ctrl, void* user_data)
03327 {
03328 LLColumnHeader* headerp = (LLColumnHeader*)user_data;
03329 if (!headerp) return;
03330
03331 LLScrollListColumn* column = headerp->mColumn;
03332 if (!column) return;
03333 LLScrollListCtrl *parent = column->mParentCtrl;
03334 if (!parent) return;
03335
03336 if (headerp->getCurrentIndex() == 0)
03337 {
03338
03339 parent->sortByColumn(column->mSortingColumn, TRUE);
03340 }
03341 else
03342 {
03343
03344 parent->sortByColumn(column->mSortingColumn, FALSE);
03345 }
03346
03347
03348 headerp->setLabel(headerp->mOrigLabel);
03349 }
03350
03351 LLView* LLColumnHeader::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding)
03352 {
03353
03354 llassert(snap_edge == SNAP_RIGHT);
03355
03356
03357 threshold = llmin(threshold, 15);
03358
03359 LLRect snap_rect = getSnapRect();
03360
03361 S32 snap_delta = mColumn->mMaxContentWidth - snap_rect.getWidth();
03362
03363
03364 if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 )
03365 {
03366 new_edge_val = snap_rect.mRight + snap_delta;
03367 }
03368 else
03369 {
03370 LLScrollListColumn* next_column = mColumn->mParentCtrl->getColumn(mColumn->mIndex + 1);
03371 while (next_column)
03372 {
03373 if (next_column->mHeader)
03374 {
03375 snap_delta = (next_column->mHeader->getSnapRect().mRight - next_column->mMaxContentWidth) - snap_rect.mRight;
03376 if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 )
03377 {
03378 new_edge_val = snap_rect.mRight + snap_delta;
03379 }
03380 break;
03381 }
03382 next_column = mColumn->mParentCtrl->getColumn(next_column->mIndex + 1);
03383 }
03384 }
03385
03386 return this;
03387 }
03388
03389 void LLColumnHeader::userSetShape(const LLRect& new_rect)
03390 {
03391 S32 new_width = new_rect.getWidth();
03392 S32 delta_width = new_width - (mRect.getWidth() + mColumn->mParentCtrl->getColumnPadding());
03393
03394 if (delta_width != 0)
03395 {
03396 S32 remaining_width = delta_width;
03397 S32 col;
03398 for (col = mColumn->mIndex + 1; col < mColumn->mParentCtrl->getNumColumns(); col++)
03399 {
03400 LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
03401 if (!columnp) break;
03402
03403 if (columnp->mHeader && columnp->mHeader->canResize())
03404 {
03405
03406 S32 resize_buffer_amt = llmax(0, columnp->mWidth - MIN_COLUMN_WIDTH);
03407
03408
03409 if (delta_width < 0)
03410 {
03411 if (!columnp->mDynamicWidth && columnp->mWidth > 0)
03412 {
03413
03414 columnp->mWidth -= remaining_width;
03415 if (columnp->mRelWidth > 0.f)
03416 {
03417 columnp->mRelWidth = (F32)columnp->mWidth / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
03418 }
03419 }
03420 break;
03421 }
03422 else
03423 {
03424
03425 remaining_width -= resize_buffer_amt;
03426
03427 if (!columnp->mDynamicWidth && columnp->mWidth > 0)
03428 {
03429 columnp->mWidth -= llmin(columnp->mWidth - MIN_COLUMN_WIDTH, delta_width);
03430 if (columnp->mRelWidth > 0.f)
03431 {
03432 columnp->mRelWidth = (F32)columnp->mWidth / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
03433 }
03434 }
03435
03436 if (remaining_width <= 0)
03437 {
03438
03439 break;
03440 }
03441 }
03442 }
03443 }
03444
03445
03446 if (delta_width > 0)
03447 {
03448 delta_width -= llmax(remaining_width, 0);
03449 }
03450
03451
03452 new_width = mRect.getWidth() + delta_width - mColumn->mParentCtrl->getColumnPadding();
03453
03454
03455 mColumn->mWidth = new_width;
03456
03457
03458 if (mColumn->mRelWidth > 0.f)
03459 {
03460 mColumn->mRelWidth = (F32)new_width / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
03461 }
03462
03463
03464 mColumn->mParentCtrl->updateColumns();
03465 }
03466 }
03467
03468 void LLColumnHeader::setHasResizableElement(BOOL resizable)
03469 {
03470
03471 if (mColumn->mDynamicWidth) return;
03472
03473 if (resizable != mHasResizableElement)
03474 {
03475 mHasResizableElement = resizable;
03476
03477 S32 num_resizable_columns = 0;
03478 S32 col;
03479 for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
03480 {
03481 LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
03482 if (columnp->mHeader && columnp->mHeader->canResize())
03483 {
03484 num_resizable_columns++;
03485 }
03486 }
03487
03488 S32 num_resizers_enabled = 0;
03489
03490
03491 for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
03492 {
03493 LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
03494 if (!columnp->mHeader) continue;
03495 BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize();
03496 columnp->mHeader->enableResizeBar(enable);
03497 if (enable)
03498 {
03499 num_resizers_enabled++;
03500 }
03501 }
03502 }
03503 }
03504
03505 void LLColumnHeader::enableResizeBar(BOOL enable)
03506 {
03507
03508 if (!mColumn->mDynamicWidth)
03509 {
03510 mResizeBar->setEnabled(enable);
03511 }
03512 }
03513
03514 BOOL LLColumnHeader::canResize()
03515 {
03516 return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth);
03517 }