From 6c214d944129e149a0a4b5efef65585738ac6cdf Mon Sep 17 00:00:00 2001
From: "Alexander G. M. Smith" <agmsmith@ncf.ca>
Date: Mon, 6 Nov 2017 20:35:36 -0500
Subject: [PATCH] Recalculate BListView cached selection boxes in Invalidate().
The coordinates of BListItems are cached and used for drawing selection
highlights and detecting mouse clicks. If you change the size of a
BListItem with BListItem::SetHeight(), it could make the following
BListItems highlight incorrectly. Calling this modified Invalidate()
will recalculate the selection coordinates for all BListItems and then
do a BView::Invalidate().
Unfortunately BView::Invalidate() isn't a virtual function, so I
couldn't cleanly add it, and this fix won't work if you call
Invalidate() through a pointer to BView. Suggestions welcome. An
alternative may be to have a special update function to make the
caching visible to the user-programmer. Currently the work-around is
to add a BListItem at the top of the list and then delete it.
Fixes #13757
---
docs/user/interface/ListView.dox | 25 +++++++++++++++++++++++++
headers/os/interface/ListView.h | 8 ++++++++
src/kits/interface/ListView.cpp | 22 ++++++++++++++++++++++
3 files changed, 55 insertions(+)
diff --git a/docs/user/interface/ListView.dox b/docs/user/interface/ListView.dox
index 6d9090a..dc86206 100644
a
|
b
|
|
827 | 827 | |
828 | 828 | |
829 | 829 | /*! |
| 830 | \fn void BListView::Invalidate() |
| 831 | \brief Updates cached item selection coordinates and sends a message |
| 832 | to App Server to redraw the view. |
| 833 | |
| 834 | The coordinates of BListItems are cached and used for drawing selection |
| 835 | highlights and detecting mouse clicks. If you change the size of a |
| 836 | BListItem with BListItem::SetHeight(), it could make the following |
| 837 | BListItems highlight incorrectly; calling this will recalculate the |
| 838 | selection coordinates for all BListItems and then do a |
| 839 | BView::Invalidate(). |
| 840 | |
| 841 | \remark Adding or removing a BListItem does automatically update the |
| 842 | selection coordinates and redraws following items. No need to |
| 843 | call Invalidate(). |
| 844 | |
| 845 | \note Since BView::Invalidate() is not a virtual function, you can't |
| 846 | access this Invalidate() through a generic BView pointer. Maybe |
| 847 | we should make _RecalcItemTops() a public function rather than |
| 848 | hiding the cache from the user? |
| 849 | |
| 850 | \since Haiku R1 |
| 851 | */ |
| 852 | |
| 853 | |
| 854 | /*! |
830 | 855 | \fn void BListView::InvalidateItem(int32 index) |
831 | 856 | \brief Draws the list item at the specified \a index. |
832 | 857 | |
diff --git a/headers/os/interface/ListView.h b/headers/os/interface/ListView.h
index f705765..ab9cc24 100644
a
|
b
|
public:
|
109 | 109 | void DoForEach(bool (*func)(BListItem* item, |
110 | 110 | void* arg), void* arg); |
111 | 111 | const BListItem** Items() const; |
| 112 | |
| 113 | // Since Invalidate() isn't virtual, the other BView varieties |
| 114 | // would get masked by our redeclaration, so have to redeclare |
| 115 | // all of them here too. |
| 116 | void Invalidate(); |
| 117 | void Invalidate(BRect invalRect); |
| 118 | void Invalidate(const BRegion* invalRegion); |
112 | 119 | void InvalidateItem(int32 index); |
| 120 | |
113 | 121 | void ScrollToSelection(); |
114 | 122 | |
115 | 123 | void Select(int32 index, bool extend = false); |
diff --git a/src/kits/interface/ListView.cpp b/src/kits/interface/ListView.cpp
index fcd8701..3ceb8cd 100644
a
|
b
|
BListView::Items() const
|
1085 | 1085 | |
1086 | 1086 | |
1087 | 1087 | void |
| 1088 | BListView::Invalidate() |
| 1089 | { |
| 1090 | _RecalcItemTops(0); |
| 1091 | BView::Invalidate(); |
| 1092 | } |
| 1093 | |
| 1094 | |
| 1095 | void |
| 1096 | BListView::Invalidate(BRect invalRect) |
| 1097 | { |
| 1098 | BView::Invalidate(invalRect); |
| 1099 | } |
| 1100 | |
| 1101 | |
| 1102 | void |
| 1103 | BListView::Invalidate(const BRegion* invalRegion) |
| 1104 | { |
| 1105 | BView::Invalidate(invalRegion); |
| 1106 | } |
| 1107 | |
| 1108 | |
| 1109 | void |
1088 | 1110 | BListView::InvalidateItem(int32 index) |
1089 | 1111 | { |
1090 | 1112 | Invalidate(ItemFrame(index)); |