]> git.saurik.com Git - wxWidgets.git/blob - src/generic/vlbox.cpp
refresh cache on size/margins change; expanded cache to contain N elements, not just one
[wxWidgets.git] / src / generic / vlbox.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: generic/vlbox.cpp
3 // Purpose: implementation of wxVListBox
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 31.05.03
7 // RCS-ID: $Id$
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // License: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/settings.h"
29 #include "wx/dcclient.h"
30 #endif //WX_PRECOMP
31
32 #include "wx/vlbox.h"
33
34 // ----------------------------------------------------------------------------
35 // event tables
36 // ----------------------------------------------------------------------------
37
38 BEGIN_EVENT_TABLE(wxVListBox, wxVScrolledWindow)
39 EVT_PAINT(wxVListBox::OnPaint)
40
41 EVT_KEY_DOWN(wxVListBox::OnKeyDown)
42 EVT_LEFT_DOWN(wxVListBox::OnLeftDown)
43 EVT_LEFT_DCLICK(wxVListBox::OnLeftDClick)
44 END_EVENT_TABLE()
45
46 // ============================================================================
47 // implementation
48 // ============================================================================
49
50 // ----------------------------------------------------------------------------
51 // wxVListBox creation
52 // ----------------------------------------------------------------------------
53
54 void wxVListBox::Init()
55 {
56 m_selection = -1;
57 }
58
59 bool wxVListBox::Create(wxWindow *parent,
60 wxWindowID id,
61 const wxPoint& pos,
62 const wxSize& size,
63 size_t countItems,
64 long style,
65 const wxString& name)
66 {
67 if ( !wxVScrolledWindow::Create(parent, id, pos, size, style, name) )
68 return false;
69
70 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX));
71
72 SetItemCount(countItems);
73
74 return true;
75 }
76
77 // ----------------------------------------------------------------------------
78 // selection handling
79 // ----------------------------------------------------------------------------
80
81 void wxVListBox::DoSetSelection(int selection, bool sendEvent)
82 {
83 if ( selection == m_selection )
84 {
85 // nothing to do
86 return;
87 }
88
89 if ( m_selection != -1 )
90 RefreshLine(m_selection);
91
92 m_selection = selection;
93
94 if ( m_selection != -1 )
95 {
96 // if the line is not visible at all, we scroll it into view but we
97 // don't need to refresh it -- it will be redrawn anyhow
98 if ( !IsVisible(m_selection) )
99 {
100 ScrollToLine(m_selection);
101 }
102 else // line is at least partly visible
103 {
104 // it is, indeed, only partly visible, so scroll it into view to
105 // make it entirely visible
106 if ( (size_t)m_selection == GetLastVisibleLine() )
107 {
108 ScrollToLine(m_selection);
109 }
110
111 // but in any case refresh it as even if it was only partly visible
112 // before we need to redraw it entirely as its background changed
113 RefreshLine(m_selection);
114 }
115
116 // send a notification event if we were not called directly by user
117 if ( sendEvent )
118 {
119 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, GetId());
120 event.SetEventObject(this);
121 event.m_commandInt = selection;
122
123 (void)GetEventHandler()->ProcessEvent(event);
124 }
125 }
126 }
127
128 // ----------------------------------------------------------------------------
129 // wxVListBox painting
130 // ----------------------------------------------------------------------------
131
132 void wxVListBox::SetMargins(const wxPoint& pt)
133 {
134 if ( pt != m_ptMargins )
135 {
136 m_ptMargins = pt;
137
138 Refresh();
139 }
140 }
141
142 wxCoord wxVListBox::OnGetLineHeight(size_t line) const
143 {
144 return OnMeasureItem(line) + 2*m_ptMargins.y;
145 }
146
147 void wxVListBox::OnDrawSeparator(wxDC& WXUNUSED(dc),
148 wxRect& WXUNUSED(rect),
149 size_t WXUNUSED(n)) const
150 {
151 }
152
153 void wxVListBox::OnPaint(wxPaintEvent& event)
154 {
155 wxPaintDC dc(this);
156
157 // the update rectangle
158 wxRect rectUpdate = GetUpdateClientRect();
159
160 // the bounding rectangle of the current line
161 wxRect rectLine;
162 rectLine.width = GetClientSize().x;
163
164 // iterate over all visible lines
165 const size_t lineMax = GetLastVisibleLine();
166 for ( size_t line = GetFirstVisibleLine(); line <= lineMax; line++ )
167 {
168 const wxCoord hLine = OnGetLineHeight(line);
169
170 rectLine.height = hLine;
171
172 // and draw the ones which intersect the update rect
173 if ( rectLine.Intersects(rectUpdate) )
174 {
175 // don't allow drawing outside of the lines rectangle
176 wxDCClipper clip(dc, rectLine);
177
178 if ( IsSelected(line) )
179 {
180 wxBrush brush(wxSystemSettings::
181 GetColour(wxSYS_COLOUR_HIGHLIGHT),
182 wxSOLID);
183 dc.SetBrush(brush);
184 dc.SetPen(*wxTRANSPARENT_PEN);
185 dc.DrawRectangle(rectLine);
186 }
187
188 wxRect rect = rectLine;
189 OnDrawSeparator(dc, rect, line);
190
191 rect.Deflate(m_ptMargins.x, m_ptMargins.y);
192 OnDrawItem(dc, rect, line);
193 }
194 else // no intersection
195 {
196 if ( rectLine.GetTop() > rectUpdate.GetBottom() )
197 {
198 // we are already below the update rect, no need to continue
199 // further
200 break;
201 }
202 //else: the next line may intersect the update rect
203 }
204
205 rectLine.y += hLine;
206 }
207 }
208
209 // ----------------------------------------------------------------------------
210 // wxVListBox keyboard handling
211 // ----------------------------------------------------------------------------
212
213 void wxVListBox::OnKeyDown(wxKeyEvent& event)
214 {
215 int selection = 0; // just to silent the stupid compiler warnings
216 switch ( event.GetKeyCode() )
217 {
218 case WXK_HOME:
219 selection = 0;
220 break;
221
222 case WXK_END:
223 selection = GetLineCount() - 1;
224 break;
225
226 case WXK_DOWN:
227 if ( m_selection == (int)GetLineCount() - 1 )
228 return;
229
230 selection = m_selection + 1;
231 break;
232
233 case WXK_UP:
234 if ( m_selection == -1 )
235 selection = GetLineCount() - 1;
236 else if ( m_selection != 0 )
237 selection = m_selection - 1;
238 else // m_selection == 0
239 return;
240 break;
241
242 case WXK_PAGEDOWN:
243 case WXK_NEXT:
244 PageDown();
245 selection = GetFirstVisibleLine();
246 break;
247
248 case WXK_PAGEUP:
249 case WXK_PRIOR:
250 if ( m_selection == (int)GetFirstVisibleLine() )
251 {
252 PageUp();
253 }
254
255 selection = GetFirstVisibleLine();
256 break;
257
258 default:
259 event.Skip();
260 return;
261 }
262
263 DoSetSelection(selection);
264 }
265
266 // ----------------------------------------------------------------------------
267 // wxVListBox mouse handling
268 // ----------------------------------------------------------------------------
269
270 void wxVListBox::OnLeftDown(wxMouseEvent& event)
271 {
272 int item = HitTest(event.GetPosition());
273
274 DoSetSelection(item);
275 }
276
277 void wxVListBox::OnLeftDClick(wxMouseEvent& event)
278 {
279 int item = HitTest(event.GetPosition());
280 if ( item != -1 )
281 {
282 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, GetId());
283 event.SetEventObject(this);
284 event.m_commandInt = item;
285
286 (void)GetEventHandler()->ProcessEvent(event);
287 }
288 }
289