bool BListView::_MoveItem(int32 from, int32 to) { // remember item frames before doing anything BRect frameFrom = ItemFrame(from); BRect frameTo = ItemFrame(to); if (!fList.MoveItem(from, to)) return false; // track anchor item if (fAnchorIndex == from) fAnchorIndex = to; // track selection if (ItemAt(to)->IsSelected()) { _RescanSelection(from, to); // though the actually selected items stayed the // same, the selection has still changed SelectionChanged(); } _RecalcItemTops((to > from) ? from : to); // take care of invalidation if (Window()) { // NOTE: window looper is assumed to be locked! Invalidate(frameFrom | frameTo); } return true; }
BListItem* BListView::RemoveItem(int32 index) { BListItem *item = ItemAt(index); if (!item) return NULL; if (item->IsSelected()) Deselect(index); if (!fList.RemoveItem(item)) return NULL; if (fFirstSelected != -1 && index < fFirstSelected) fFirstSelected--; if (fLastSelected != -1 && index < fLastSelected) fLastSelected--; if (fAnchorIndex != -1 && index < fAnchorIndex) fAnchorIndex--; _RecalcItemTops(index); _InvalidateFrom(index); _FixupScrollBar(); return item; }
bool BListView::AddList(BList* list, int32 index) { if (!fList.AddList(list, index)) return false; int32 count = fList.CountItems(); if (fFirstSelected != -1 && index < fFirstSelected) fFirstSelected += count; if (fLastSelected != -1 && index < fLastSelected) fLastSelected += count; if (Window()) { BFont font; GetFont(&font); for (int32 i = index; i <= (index + list->CountItems() - 1); i++) { ItemAt(i)->SetTop((i > 0) ? ItemAt(i - 1)->Bottom() + 1.0 : 0.0); ItemAt(i)->Update(this, &font); } _RecalcItemTops(index + list->CountItems() - 1); _FixupScrollBar(); Invalidate(); // TODO } return true; }
bool BListView::AddItem(BListItem *item, int32 index) { if (!fList.AddItem(item, index)) return false; if (fFirstSelected != -1 && index <= fFirstSelected) fFirstSelected++; if (fLastSelected != -1 && index <= fLastSelected) fLastSelected++; if (Window()) { BFont font; GetFont(&font); item->SetTop((index > 0) ? ItemAt(index - 1)->Bottom() + 1.0 : 0.0); item->Update(this, &font); _RecalcItemTops(index + 1); _FixupScrollBar(); _InvalidateFrom(index); } return true; }
bool BListView::_SwapItems(int32 a, int32 b) { // remember frames of items before anyhing happens, // the tricky situation is when the two items have // a different height BRect aFrame = ItemFrame(a); BRect bFrame = ItemFrame(b); if (!fList.SwapItems(a, b)) return false; if (a == b) { // nothing to do, but success nevertheless return true; } // track anchor item if (fAnchorIndex == a) fAnchorIndex = b; else if (fAnchorIndex == b) fAnchorIndex = a; // track selection // NOTE: this is only important if the selection status // of both items is not the same int32 first = min_c(a, b); int32 last = max_c(a, b); if (ItemAt(a)->IsSelected() != ItemAt(b)->IsSelected()) { if (first < fFirstSelected || last > fLastSelected) { _RescanSelection(min_c(first, fFirstSelected), max_c(last, fLastSelected)); } // though the actually selected items stayed the // same, the selection has still changed SelectionChanged(); } ItemAt(a)->SetTop(aFrame.top); ItemAt(b)->SetTop(bFrame.top); // take care of invalidation if (Window()) { // NOTE: window looper is assumed to be locked! if (aFrame.Height() != bFrame.Height()) { _RecalcItemTops(first, last); // items in between shifted visually Invalidate(aFrame | bFrame); } else { Invalidate(aFrame); Invalidate(bFrame); } } return true; }
void BListView::SortItems(int (*cmp)(const void *, const void *)) { if (_DeselectAll(-1, -1)) { SelectionChanged(); InvokeNotify(fSelectMessage, B_CONTROL_MODIFIED); } fList.SortItems(cmp); _RecalcItemTops(0); Invalidate(); }
bool BListView::RemoveItems(int32 index, int32 count) { if (index >= fList.CountItems()) index = -1; if (index < 0) return false; if (fAnchorIndex != -1 && index < fAnchorIndex) fAnchorIndex = index; fList.RemoveItems(index, count); if (index < fList.CountItems()) _RecalcItemTops(index); Invalidate(); return true; }
bool BListView::_ReplaceItem(int32 index, BListItem* item) { if (item == NULL) return false; BListItem* old = ItemAt(index); if (!old) return false; BRect frame = ItemFrame(index); bool selectionChanged = old->IsSelected() != item->IsSelected(); // replace item if (!fList.ReplaceItem(index, item)) return false; // tack selection if (selectionChanged) { int32 start = min_c(fFirstSelected, index); int32 end = max_c(fLastSelected, index); _RescanSelection(start, end); SelectionChanged(); } _RecalcItemTops(index); bool itemHeightChanged = frame != ItemFrame(index); // take care of invalidation if (Window()) { // NOTE: window looper is assumed to be locked! if (itemHeightChanged) _InvalidateFrom(index); else Invalidate(frame); } if (itemHeightChanged) _FixupScrollBar(); return true; }
bool BOutlineListView::_SwapItems(int32 first, int32 second) { // same item, do nothing if (first == second) return true; // fail, first item out of bounds if ((first < 0) || (first >= CountItems())) return false; // fail, second item out of bounds if ((second < 0) || (second >= CountItems())) return false; int32 firstIndex = min_c(first, second); int32 secondIndex = max_c(first, second); BListItem* firstItem = ItemAt(firstIndex); BListItem* secondItem = ItemAt(secondIndex); BList firstSubItems, secondSubItems; if (Superitem(firstItem) != Superitem(secondItem)) return false; if (!firstItem->IsItemVisible() || !secondItem->IsItemVisible()) return false; int32 fullFirstIndex = _FullListIndex(firstIndex); int32 fullSecondIndex = _FullListIndex(secondIndex); _GetSubItems(fFullList, firstSubItems, firstItem, fullFirstIndex + 1); _GetSubItems(fFullList, secondSubItems, secondItem, fullSecondIndex + 1); _DoSwap(fFullList, fullFirstIndex, fullSecondIndex, &firstSubItems, &secondSubItems); _CullInvisibleItems(firstSubItems); _CullInvisibleItems(secondSubItems); _DoSwap(fList, firstIndex, secondIndex, &firstSubItems, &secondSubItems); _RecalcItemTops(firstIndex); _RescanSelection(firstIndex, secondIndex + secondSubItems.CountItems()); Invalidate(Bounds()); return true; }
void BOutlineListView::SortItemsUnder(BListItem* underItem, bool oneLevelOnly, int (*compareFunc)(const BListItem* a, const BListItem* b)) { // This method is quite complicated: basically, it creates a real tree // from the items of the full list, sorts them as needed, and then // populates the entries back into the full and display lists int32 firstIndex = FullListIndexOf(underItem) + 1; int32 lastIndex = firstIndex; BList* tree = _BuildTree(underItem, lastIndex); _SortTree(tree, oneLevelOnly, compareFunc); // Populate to the full list _PopulateTree(tree, fFullList, firstIndex, false); if (underItem == NULL || (underItem->IsItemVisible() && underItem->IsExpanded())) { // Populate to BListView's list firstIndex = fList.IndexOf(underItem) + 1; lastIndex = firstIndex; _PopulateTree(tree, fList, lastIndex, true); if (fFirstSelected != -1) { // update selection hints fFirstSelected = _CalcFirstSelected(0); fLastSelected = _CalcLastSelected(CountItems()); } // only invalidate what may have changed _RecalcItemTops(firstIndex); BRect top = ItemFrame(firstIndex); BRect bottom = ItemFrame(lastIndex - 1); BRect update(top.left, top.top, bottom.right, bottom.bottom); Invalidate(update); } _DestructTree(tree); }
void BOutlineListView::ExpandOrCollapse(BListItem* item, bool expand) { if (item->IsExpanded() == expand || !FullListHasItem(item)) return; item->fExpanded = expand; // TODO: merge these cases together, they are pretty similar if (expand) { uint32 level = item->fLevel; int32 fullIndex = FullListIndexOf(item); int32 index = IndexOf(item) + 1; int32 startIndex = index; int32 count = FullListCountItems() - fullIndex - 1; BListItem** items = (BListItem**)fFullList.Items() + fullIndex + 1; BFont font; GetFont(&font); while (count-- > 0) { item = items[0]; if (item->fLevel <= level) break; if (!item->IsItemVisible()) { // fix selection hints if (index <= fFirstSelected) fFirstSelected++; if (index <= fLastSelected) fLastSelected++; fList.AddItem(item, index++); item->Update(this, &font); item->SetItemVisible(true); } if (item->HasSubitems() && !item->IsExpanded()) { // Skip hidden children uint32 subLevel = item->fLevel; items++; while (--count > 0 && items[0]->fLevel > subLevel) items++; } else items++; } _RecalcItemTops(startIndex); } else { // collapse uint32 level = item->fLevel; int32 fullIndex = FullListIndexOf(item); int32 index = IndexOf(item); int32 startIndex = index; int32 max = FullListCountItems() - fullIndex - 1; int32 count = 0; bool selectionChanged = false; BListItem** items = (BListItem**)fFullList.Items() + fullIndex + 1; while (max-- > 0) { item = items[0]; if (item->fLevel <= level) break; if (item->IsItemVisible()) { fList.RemoveItem(item); item->SetItemVisible(false); if (item->IsSelected()) { selectionChanged = true; item->Deselect(); } count++; } items++; } _RecalcItemTops(startIndex); // fix selection hints // if the selected item was just removed by collapsing, select its // parent if (ListType() == B_SINGLE_SELECTION_LIST && selectionChanged) fFirstSelected = fLastSelected = index; if (index < fFirstSelected && index + count < fFirstSelected) { // all items removed were higher than the selection range, // adjust the indexes to correspond to their new visible positions fFirstSelected -= count; fLastSelected -= count; } int32 maxIndex = fList.CountItems() - 1; if (fFirstSelected > maxIndex) fFirstSelected = maxIndex; if (fLastSelected > maxIndex) fLastSelected = maxIndex; if (selectionChanged) SelectionChanged(); } _FixupScrollBar(); Invalidate(); }