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