bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select) { llassert(item_pair); if (!mAllowSelection && select) return false; if (isSelected(item_pair) == select) return true; //already in specified selection state if (select) { mSelectedItemPairs.push_back(item_pair); } else { mSelectedItemPairs.remove(item_pair); } //a way of notifying panel of selection state changes LLPanel* item = item_pair->first; item->setValue(select ? SELECTED_EVENT : UNSELECTED_EVENT); if (mCommitOnSelectionChange) { onCommit(); } // Stretch selected item rect to ensure it won't be clipped mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); return true; }
bool LLFlatListView::selectAll() { if (!mAllowSelection) return false; mSelectedItemPairs.clear(); for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) { item_pair_t* item_pair = *it; mSelectedItemPairs.push_back(item_pair); //a way of notifying panel of selection state changes LLPanel* item = item_pair->first; item->setValue(SELECTED_EVENT); } if (mCommitOnSelectionChange) { onCommit(); } // Stretch selected item rect to ensure it won't be clipped mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); return true; }
LLFlatListView::LLFlatListView(const LLFlatListView::Params& p) : LLScrollContainer(p) , mItemComparator(NULL) , mItemsPanel(NULL) , mItemPad(p.item_pad) , mAllowSelection(p.allow_select) , mMultipleSelection(p.multi_select) , mKeepOneItemSelected(p.keep_one_selected) , mCommitOnSelectionChange(false) , mPrevNotifyParentRect(LLRect()) , mNoItemsCommentTextbox(NULL) , mIsConsecutiveSelection(false) , mKeepSelectionVisibleOnReshape(p.keep_selection_visible_on_reshape) { mBorderThickness = getBorderWidth(); LLRect scroll_rect = getRect(); LLRect items_rect; setItemsNoScrollWidth(scroll_rect.getWidth()); items_rect.setLeftTopAndSize(mBorderThickness, scroll_rect.getHeight() - mBorderThickness, mItemsNoScrollWidth, 0); LLPanel::Params pp; pp.rect(items_rect); mItemsPanel = LLUICtrlFactory::create<LLPanel> (pp); addChild(mItemsPanel); //we don't need to stretch in vertical direction on reshaping by a parent //no bottom following! mItemsPanel->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); LLViewBorder::Params params; params.name("scroll border"); params.rect(getLastSelectedItemRect()); params.visible(false); params.bevel_style(LLViewBorder::BEVEL_IN); mSelectedItemsBorder = LLUICtrlFactory::create<LLViewBorder> (params); mItemsPanel->addChild( mSelectedItemsBorder ); { // create textbox for "No Items" comment text LLTextBox::Params text_p = p.no_items_text; if (!text_p.rect.isProvided()) { LLRect comment_rect = getRect(); comment_rect.setOriginAndSize(0, 0, comment_rect.getWidth(), comment_rect.getHeight()); comment_rect.stretch(-getBorderWidth()); text_p.rect(comment_rect); } text_p.border_visible(false); if (!text_p.follows.isProvided()) { text_p.follows.flags(FOLLOWS_ALL); } mNoItemsCommentTextbox = LLUICtrlFactory::create<LLTextBox>(text_p, this); } };
void LLFlatListView::ensureSelectedVisible() { LLRect selected_rc = getLastSelectedItemRect(); if ( selected_rc.isValid() ) { scrollToShowRect(selected_rc); } }
void LLFlatListView::resetSelection(bool no_commit_on_deselection /*= false*/) { if (mSelectedItemPairs.empty()) return; for (pairs_iterator_t it= mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) { item_pair_t* pair_to_deselect = *it; LLPanel* item = pair_to_deselect->first; item->setValue(UNSELECTED_EVENT); } mSelectedItemPairs.clear(); if (mCommitOnSelectionChange && !no_commit_on_deselection) { onCommit(); } // Stretch selected item rect to ensure it won't be clipped mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); }
void LLFlatListView::rearrangeItems() { static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); setNoItemsCommentVisible(mItemPairs.empty()); if (mItemPairs.empty()) return; //calculating required height - assuming items can be of different height //list should accommodate all its items S32 height = 0; S32 invisible_children_count = 0; pairs_iterator_t it = mItemPairs.begin(); for (; it != mItemPairs.end(); ++it) { LLPanel* item = (*it)->first; // skip invisible child if (!item->getVisible()) { ++invisible_children_count; continue; } height += item->getRect().getHeight(); } // add paddings between items, excluding invisible ones height += mItemPad * (mItemPairs.size() - invisible_children_count - 1); LLRect rc = mItemsPanel->getRect(); S32 width = mItemsNoScrollWidth; // update width to avoid horizontal scrollbar if (height > getRect().getHeight() - 2 * mBorderThickness) width -= scrollbar_size; //changes the bottom, end of the list goes down in the scroll container rc.setLeftTopAndSize(rc.mLeft, rc.mTop, width, height); mItemsPanel->setRect(rc); //reshaping items S32 item_new_top = height; pairs_iterator_t it2, first_it = mItemPairs.begin(); for (it2 = first_it; it2 != mItemPairs.end(); ++it2) { LLPanel* item = (*it2)->first; // skip invisible child if (!item->getVisible()) continue; LLRect rc = item->getRect(); rc.setLeftTopAndSize(rc.mLeft, item_new_top, width, rc.getHeight()); item->reshape(rc.getWidth(), rc.getHeight()); item->setRect(rc); // move top for next item in list item_new_top -= (rc.getHeight() + mItemPad); } // Stretch selected item rect to ensure it won't be clipped mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); }
void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) { if (!item_pair) return; if (!item_pair->first) { llwarning("Attempt to selet an item pair containing null panel item", 0); return; } setFocus(TRUE); bool select_item = !isSelected(item_pair); //*TODO find a better place for that enforcing stuff if (mKeepOneItemSelected && numSelected() == 1 && !select_item) return; if ( (mask & MASK_SHIFT) && !(mask & MASK_CONTROL) && mMultipleSelection && !mSelectedItemPairs.empty() ) { item_pair_t* last_selected_pair = mSelectedItemPairs.back(); // If item_pair is already selected - do nothing if (last_selected_pair == item_pair) return; bool grab_items = false; bool reverse = false; pairs_list_t pairs_to_select; // Pick out items from list between last selected and current clicked item_pair. for (pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); iter != iter_end; ++iter) { item_pair_t* cur = *iter; if (cur == last_selected_pair || cur == item_pair) { // We've got reverse selection if last grabed item isn't a new selection. reverse = grab_items && (cur != item_pair); grab_items = !grab_items; // Skip last selected and current clicked item pairs. continue; } if (!cur->first->getVisible()) { // Skip invisible item pairs. continue; } if (grab_items) { pairs_to_select.push_back(cur); } } if (reverse) { pairs_to_select.reverse(); } pairs_to_select.push_back(item_pair); for (pairs_iterator_t iter = pairs_to_select.begin(), iter_end = pairs_to_select.end(); iter != iter_end; ++iter) { item_pair_t* pair_to_select = *iter; if (isSelected(pair_to_select)) { // Item was already selected but there is a need to keep order from last selected pair to new selection. // Do it here to prevent extra mCommitOnSelectionChange in selectItemPair(). mSelectedItemPairs.remove(pair_to_select); mSelectedItemPairs.push_back(pair_to_select); } else { selectItemPair(pair_to_select, true); } } if (!select_item) { // Update last selected item border. mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); } return; } //no need to do additional commit on selection reset if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection(true); //only CTRL usage allows to deselect an item, usual clicking on an item cannot deselect it if (mask & MASK_CONTROL) selectItemPair(item_pair, select_item); else selectItemPair(item_pair, true); }