a bunch of ListView fixes:

* removed weird stuff that seemed to have no purpose in life
* added more comments where I had to figure things out
* fWidth is now adjusted in FrameResized()
* ListView scrolls up when items are removed at the end and
  there would be empty room
* fixed SwapItems(), MoveItem() and ReplaceItem() by making
  DoMiscellaneous() use the private implementations instead
  of calling the public ones again resulting in an endless
  loop
* renamed private methods with underscore
* removed more unused/empty private methods
* some slight performance increases here and there
* more correct tracking of fFirstSelected and fLastSelected,
  at least I cannot reproduce one crash in the WonderBrush
  Layer list anymore

even more cleanup and testing would not hurt though...



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17487 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2006-05-17 00:12:14 +00:00
parent c1a34c9be2
commit a2a6a329e8
2 changed files with 136 additions and 82 deletions
+4 -6
View File
@@ -165,12 +165,10 @@ class BListView : public BView, public BInvoker
int32 _CalcLastSelected(int32 before); int32 _CalcLastSelected(int32 before);
virtual void DrawItem(BListItem *item, BRect itemRect, bool complete = false); virtual void DrawItem(BListItem *item, BRect itemRect, bool complete = false);
bool DoSwapItems(int32 a, int32 b); bool _SwapItems(int32 a, int32 b);
bool DoMoveItem(int32 from, int32 to); bool _MoveItem(int32 from, int32 to);
bool DoReplaceItem(int32 index, BListItem *item); bool _ReplaceItem(int32 index, BListItem *item);
void RescanSelection(int32 from, int32 to); void _RescanSelection(int32 from, int32 to);
void DoMouseUp(BPoint where);
void DoMouseMoved(BPoint where);
BList fList; BList fList;
list_view_type fListType; list_view_type fListType;
+132 -76
View File
@@ -335,12 +335,6 @@ BListView::MouseDown(BPoint point)
void void
BListView::MouseUp(BPoint pt) BListView::MouseUp(BPoint pt)
{ {
if (fWidth == 0)
return;
DoMouseMoved(pt);
DoMouseUp(pt);
fTrack->item_index = -1; fTrack->item_index = -1;
fTrack->try_drag = false; fTrack->try_drag = false;
} }
@@ -349,13 +343,14 @@ BListView::MouseUp(BPoint pt)
void void
BListView::MouseMoved(BPoint pt, uint32 code, const BMessage *msg) BListView::MouseMoved(BPoint pt, uint32 code, const BMessage *msg)
{ {
if (fTrack->item_index == -1) if (fTrack->item_index == -1) {
// mouse was not clicked above any item
// or no mouse button pressed
return; return;
}
if (_TryInitiateDrag(pt)) if (_TryInitiateDrag(pt))
return; return;
DoMouseMoved(pt);
} }
// KeyDown // KeyDown
@@ -440,7 +435,7 @@ BListView::MakeFocus(bool focused)
void void
BListView::FrameResized(float width, float height) BListView::FrameResized(float width, float height)
{ {
// TODO fWidth = Bounds().right;
_FixupScrollBar(); _FixupScrollBar();
} }
@@ -1096,24 +1091,18 @@ BListView::DoMiscellaneous(MiscCode code, MiscData *data)
if (code > B_SWAP_OP) if (code > B_SWAP_OP)
return false; return false;
switch (code) switch (code) {
{
case B_NO_OP: case B_NO_OP:
{
break; break;
}
case B_REPLACE_OP: case B_REPLACE_OP:
{ return _ReplaceItem(data->replace.index, data->replace.item);
return ReplaceItem(data->replace.index, data->replace.item);
}
case B_MOVE_OP: case B_MOVE_OP:
{ return _MoveItem(data->move.from, data->move.to);
return MoveItem(data->move.from, data->move.to);
}
case B_SWAP_OP: case B_SWAP_OP:
{ return _SwapItems(data->swap.a, data->swap.b);
return SwapItems(data->swap.a, data->swap.b);
}
} }
return false; return false;
@@ -1162,13 +1151,17 @@ BListView::_FixupScrollBar()
} }
if (bounds.Height() > itemHeight) { if (bounds.Height() > itemHeight) {
// no scrolling
vertScroller->SetRange(0.0, 0.0); vertScroller->SetRange(0.0, 0.0);
vertScroller->SetValue(0.0); vertScroller->SetValue(0.0);
// also scrolls ListView to the top
} else { } else {
// TODO: what about removing items from a scrolled
// list view? Doesn't "value" have to be adjusted?
vertScroller->SetRange(0.0, itemHeight - bounds.Height() - 1.0); vertScroller->SetRange(0.0, itemHeight - bounds.Height() - 1.0);
vertScroller->SetProportion(bounds.Height () / itemHeight); vertScroller->SetProportion(bounds.Height () / itemHeight);
// scroll up if there is empty room on bottom
if (itemHeight < bounds.bottom) {
ScrollBy(0.0, bounds.bottom - itemHeight);
}
} }
if (count != 0) { if (count != 0) {
@@ -1231,17 +1224,21 @@ BListView::_Select(int32 index, bool extend)
BListItem* item = ItemAt(index); BListItem* item = ItemAt(index);
if (!item->IsEnabled() || item->IsSelected()) { if (!item->IsEnabled() || item->IsSelected()) {
// if the item is already selected, or can't be selected, we're done here // if the item is already selected, or can't be selected,
// we're done here
return changed; return changed;
} }
// keep track of first and last selected item
if (fFirstSelected == -1) { if (fFirstSelected == -1) {
// no previous selection
fFirstSelected = index; fFirstSelected = index;
fLastSelected = index; fLastSelected = index;
} else if (index < fFirstSelected) } else if (index < fFirstSelected) {
fFirstSelected = index; fFirstSelected = index;
else if (index > fLastSelected) } else if (index > fLastSelected) {
fLastSelected = index; fLastSelected = index;
}
ItemAt(index)->Select(); ItemAt(index)->Select();
if (Window()) if (Window())
@@ -1359,8 +1356,8 @@ BListView::_DeselectAll(int32 exceptFrom, int32 exceptTo)
return false; return false;
if (exceptFrom != -1) { if (exceptFrom != -1) {
fFirstSelected = _CalcFirstSelected(fFirstSelected); fFirstSelected = _CalcFirstSelected(exceptFrom);
fLastSelected = _CalcLastSelected(fLastSelected); fLastSelected = _CalcLastSelected(exceptTo);
} else } else
fFirstSelected = fLastSelected = -1; fFirstSelected = fLastSelected = -1;
@@ -1391,7 +1388,8 @@ BListView::_CalcFirstSelected(int32 after)
if (after >= CountItems()) if (after >= CountItems())
return -1; return -1;
for (int32 i = after; i < CountItems(); i++) { int32 count = CountItems();
for (int32 i = after; i < count; i++) {
if (ItemAt(i)->IsSelected()) if (ItemAt(i)->IsSelected())
return i; return i;
} }
@@ -1406,8 +1404,9 @@ BListView::_CalcLastSelected(int32 before)
if (before < 0) if (before < 0)
return -1; return -1;
for (int32 i = before; i >= 0; i--) before = min_c(CountItems() - 1, before);
{
for (int32 i = before; i >= 0; i--) {
if (ItemAt(i)->IsSelected()) if (ItemAt(i)->IsSelected())
return i; return i;
} }
@@ -1424,111 +1423,168 @@ BListView::DrawItem(BListItem *item, BRect itemRect, bool complete)
bool bool
BListView::DoSwapItems(int32 a, int32 b) 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)) if (!fList.SwapItems(a, b))
return false; return false;
Invalidate(ItemFrame(a)); if (a == b) {
Invalidate(ItemFrame(b)); // nothing to do, but success nevertheless
return true;
}
// track anchor item
if (fAnchorIndex == a) if (fAnchorIndex == a)
fAnchorIndex = b; fAnchorIndex = b;
else if (fAnchorIndex == b) else if (fAnchorIndex == b)
fAnchorIndex = a; fAnchorIndex = a;
RescanSelection(a, b); // track selection
// NOTE: this is only important if the selection status
// of both items is not the same
if (ItemAt(a)->IsSelected() != ItemAt(b)->IsSelected()) {
int32 first = min_c(a, b);
int32 last = max_c(a, b);
if (first < fFirstSelected || last > fLastSelected) {
first = min_c(first, fFirstSelected);
last = max_c(last, fLastSelected);
_RescanSelection(first, last);
}
// though the actually selected items stayed the
// same, the selection has still changed
SelectionChanged();
}
// take care of invalidation
if (Window()) {
// NOTE: window looper is assumed to be locked!
if (aFrame.Height() != bFrame.Height()) {
// items in between shifted visually
Invalidate(aFrame | bFrame);
} else {
Invalidate(aFrame);
Invalidate(bFrame);
}
}
return true; return true;
} }
bool bool
BListView::DoMoveItem(int32 from, int32 to) BListView::_MoveItem(int32 from, int32 to)
{ {
// remember item frames before doing anything
BRect frameFrom = ItemFrame(from); BRect frameFrom = ItemFrame(from);
BRect frameTo = ItemFrame(to); BRect frameTo = ItemFrame(to);
if (!fList.MoveItem(from, to)) if (!fList.MoveItem(from, to))
return false; return false;
RescanSelection(from, to); // track anchor item
if (fAnchorIndex == from)
fAnchorIndex = to;
BRect frame = frameFrom | frameTo; // track selection
if (ItemAt(to)->IsSelected()) {
_RescanSelection(from, to);
// though the actually selected items stayed the
// same, the selection has still changed
SelectionChanged();
}
if (Bounds().Intersects(frame)) // take care of invalidation
Invalidate(Bounds() & frame); if (Window()) {
// NOTE: window looper is assumed to be locked!
Invalidate(frameFrom | frameTo);
}
return true; return true;
} }
bool bool
BListView::DoReplaceItem(int32 index, BListItem *item) BListView::_ReplaceItem(int32 index, BListItem *item)
{ {
if (!item)
return false;
BListItem* old = ItemAt(index);
if (!old)
return false;
BRect frame = ItemFrame(index); BRect frame = ItemFrame(index);
bool selectionChanged = old->IsSelected() != item->IsSelected();
// replace item
if (!fList.ReplaceItem(index, item)) if (!fList.ReplaceItem(index, item))
return false; return false;
if (frame != ItemFrame(index)) // tack selection
_InvalidateFrom(index); if (selectionChanged) {
else int32 start = min_c(fFirstSelected, index);
Invalidate(frame); int32 end = max_c(fLastSelected, index);
_RescanSelection(start, end);
SelectionChanged();
}
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; return true;
} }
void void
BListView::RescanSelection(int32 from, int32 to) BListView::_RescanSelection(int32 from, int32 to)
{ {
if (from > to) if (from > to) {
{
int32 tmp = from; int32 tmp = from;
from = to; from = to;
to = tmp; to = tmp;
} }
if (fAnchorIndex != -1) from = max_c(0, from);
{ to = min_c(to, CountItems() - 1);
if (fAnchorIndex != -1) {
if (fAnchorIndex == from) if (fAnchorIndex == from)
fAnchorIndex = to; fAnchorIndex = to;
else if (fAnchorIndex == to) else if (fAnchorIndex == to)
fAnchorIndex = from; fAnchorIndex = from;
} }
/* if (from < fFirstSelected && from < fLastSelected) for (int32 i = from; i <= to; i++) {
return; if (ItemAt(i)->IsSelected()) {
if (to > fFirstSelected && to > fLastSelected)
return;*/
int32 i;
for (i = from; i <= to; i++)
{
if (ItemAt(i)->IsSelected())
{
fFirstSelected = i; fFirstSelected = i;
break; break;
} }
} }
for (i = from; i <= to; i++) if (fFirstSelected > from)
from = fFirstSelected;
for (int32 i = from; i <= to; i++) {
if (ItemAt(i)->IsSelected()) if (ItemAt(i)->IsSelected())
fLastSelected = i; fLastSelected = i;
}
} }
void
BListView::DoMouseUp(BPoint where)
{
}
void
BListView::DoMouseMoved(BPoint where)
{
}