(blind) fix for MSW crash
[wxWidgets.git] / src / generic / listbkg.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: generic/listbkg.cpp
3 // Purpose: generic implementation of wxListbook
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 19.08.03
7 // RCS-ID: $Id$
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "listbook.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_LISTBOOK
32
33 #include "wx/listctrl.h"
34 #include "wx/statline.h"
35 #include "wx/listbook.h"
36 #include "wx/imaglist.h"
37
38 // ----------------------------------------------------------------------------
39 // constants
40 // ----------------------------------------------------------------------------
41
42 // margin between the list and the page, should be bigger than wxStaticLine
43 // size
44 const wxCoord MARGIN = 5;
45
46 // ----------------------------------------------------------------------------
47 // various wxWindows macros
48 // ----------------------------------------------------------------------------
49
50 IMPLEMENT_DYNAMIC_CLASS(wxListbook, wxControl)
51 IMPLEMENT_DYNAMIC_CLASS(wxListbookEvent, wxNotifyEvent)
52
53 const wxEventType wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING = wxNewEventType();
54 const wxEventType wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED = wxNewEventType();
55
56 BEGIN_EVENT_TABLE(wxListbook, wxBookCtrl)
57 EVT_SIZE(wxListbook::OnSize)
58
59 EVT_LIST_ITEM_SELECTED(wxID_ANY, wxListbook::OnListSelected)
60 END_EVENT_TABLE()
61
62 // ============================================================================
63 // wxListbook implementation
64 // ============================================================================
65
66 // ----------------------------------------------------------------------------
67 // wxListbook creation
68 // ----------------------------------------------------------------------------
69
70 void wxListbook::Init()
71 {
72 m_list = NULL;
73 m_line = NULL;
74 m_selection = wxNOT_FOUND;
75 }
76
77 bool
78 wxListbook::Create(wxWindow *parent,
79 wxWindowID id,
80 const wxPoint& pos,
81 const wxSize& size,
82 long style,
83 const wxString& name)
84 {
85 if ( (style & wxLB_ALIGN_MASK) == wxLB_DEFAULT )
86 {
87 #ifdef __WXMAC__
88 style |= wxLB_TOP;
89 #else // !__WXMAC__
90 style |= wxLB_LEFT;
91 #endif // __WXMAC__/!__WXMAC__
92 }
93
94 if ( !wxControl::Create(parent, id, pos, size, style,
95 wxDefaultValidator, name) )
96 return false;
97
98 m_list = new wxListView
99 (
100 this,
101 -1,
102 wxDefaultPosition,
103 wxDefaultSize,
104 wxLC_ICON | wxLC_SINGLE_SEL
105 );
106
107 m_line = new wxStaticLine
108 (
109 this,
110 -1,
111 wxDefaultPosition,
112 wxDefaultSize,
113 IsVertical() ? wxLI_HORIZONTAL : wxLI_VERTICAL
114 );
115
116 return true;
117 }
118
119 // ----------------------------------------------------------------------------
120 // wxListbook geometry management
121 // ----------------------------------------------------------------------------
122
123 wxSize wxListbook::GetListSize() const
124 {
125 const wxSize sizeClient = GetClientSize();
126
127 // we need to find the longest/tallest label
128 wxCoord widthMax = 0,
129 heightMax = 0;
130 const int count = m_list->GetItemCount();
131 if ( count )
132 {
133 for ( int i = 0; i < count; i++ )
134 {
135 wxRect r;
136 m_list->GetItemRect(i, r);
137
138 wxCoord w = r.x + r.width,
139 h = r.y + r.height;
140
141 if ( w > widthMax )
142 widthMax = w;
143 if ( h > heightMax )
144 heightMax = h;
145 }
146 }
147
148 wxSize size;
149 if ( IsVertical() )
150 {
151 size.x = sizeClient.x;
152 size.y = heightMax;
153 }
154 else // left/right aligned
155 {
156 size.x = widthMax + 10;
157 size.y = sizeClient.y;
158 }
159
160 return size;
161 }
162
163 wxRect wxListbook::GetPageRect() const
164 {
165 const wxSize sizeList = GetListSize();
166
167 wxRect rectPage(wxPoint(0, 0), GetClientSize());
168 switch ( GetWindowStyle() & wxLB_ALIGN_MASK )
169 {
170 default:
171 wxFAIL_MSG( _T("unexpected wxListbook alignment") );
172 // fall through
173
174 case wxLB_TOP:
175 rectPage.y = sizeList.y + MARGIN;
176 // fall through
177
178 case wxLB_BOTTOM:
179 rectPage.height -= sizeList.y + MARGIN;
180 break;
181
182 case wxLB_LEFT:
183 rectPage.x = sizeList.x + MARGIN;
184 // fall through
185
186 case wxLB_RIGHT:
187 rectPage.width -= sizeList.x + MARGIN;
188 break;
189 }
190
191 return rectPage;
192 }
193
194 void wxListbook::OnSize(wxSizeEvent& event)
195 {
196 event.Skip();
197
198 if ( !m_list )
199 {
200 // we're not fully created yet
201 return;
202 }
203
204 // resize the list control and the page area to fit inside our new size
205 const wxSize sizeClient = GetClientSize(),
206 sizeList = GetListSize();
207
208 wxPoint posList;
209 switch ( GetWindowStyle() & wxLB_ALIGN_MASK )
210 {
211 default:
212 wxFAIL_MSG( _T("unexpected wxListbook alignment") );
213 // fall through
214
215 case wxLB_TOP:
216 case wxLB_LEFT:
217 // posList is already ok
218 break;
219
220 case wxLB_BOTTOM:
221 posList.y = sizeClient.y - sizeList.y;
222 break;
223
224 case wxLB_RIGHT:
225 posList.x = sizeClient.x - sizeList.x;
226 break;
227 }
228
229 m_list->SetSize(posList.x, posList.y, sizeList.x, sizeList.y);
230
231 if ( m_line )
232 {
233 wxRect rectLine(wxPoint(0, 0), sizeClient);
234
235 switch ( GetWindowStyle() & wxLB_ALIGN_MASK )
236 {
237 case wxLB_TOP:
238 rectLine.y = sizeList.y + 1;
239 rectLine.height = MARGIN - 2;
240 break;
241
242 case wxLB_BOTTOM:
243 rectLine.height = MARGIN - 2;
244 rectLine.y = sizeClient.y - sizeList.y - rectLine.height;
245 break;
246
247 case wxLB_LEFT:
248 rectLine.x = sizeList.x + 1;
249 rectLine.width = MARGIN - 2;
250 break;
251
252 case wxLB_RIGHT:
253 rectLine.width = MARGIN - 2;
254 rectLine.x = sizeClient.x - sizeList.x - rectLine.width;
255 break;
256 }
257
258 m_line->SetSize(rectLine);
259 }
260
261 // we should always have some selection if possible
262 if ( m_selection == wxNOT_FOUND && GetPageCount() )
263 {
264 SetSelection(0);
265 }
266
267 if ( m_selection != wxNOT_FOUND )
268 {
269 wxWindow *page = m_pages[m_selection];
270 wxCHECK_RET( page, _T("NULL page in wxListbook?") );
271
272 page->SetSize(GetPageRect());
273 if ( !page->IsShown() )
274 {
275 page->Show();
276 }
277 }
278 }
279
280 wxSize wxListbook::CalcSizeFromPage(const wxSize& sizePage) const
281 {
282 // we need to add the size of the list control and the margin
283 const wxSize sizeList = GetListSize();
284
285 wxSize size = sizePage;
286 if ( IsVertical() )
287 {
288 size.y += sizeList.y + MARGIN;
289 }
290 else // left/right aligned
291 {
292 size.x += sizeList.x + MARGIN;
293 }
294
295 return size;
296 }
297
298
299 // ----------------------------------------------------------------------------
300 // accessing the pages
301 // ----------------------------------------------------------------------------
302
303 bool wxListbook::SetPageText(size_t n, const wxString& strText)
304 {
305 m_list->SetItemText(n, strText);
306
307 return true;
308 }
309
310 wxString wxListbook::GetPageText(size_t n) const
311 {
312 return m_list->GetItemText(n);
313 }
314
315 int wxListbook::GetPageImage(size_t WXUNUSED(n)) const
316 {
317 wxFAIL_MSG( _T("wxListbook::GetPageImage() not implemented") );
318
319 return -1;
320 }
321
322 bool wxListbook::SetPageImage(size_t n, int imageId)
323 {
324 return m_list->SetItemImage(n, imageId, imageId);
325 }
326
327 // ----------------------------------------------------------------------------
328 // image list stuff
329 // ----------------------------------------------------------------------------
330
331 void wxListbook::SetImageList(wxImageList *imageList)
332 {
333 m_list->SetImageList(imageList, wxIMAGE_LIST_NORMAL);
334
335 wxBookCtrl::SetImageList(imageList);
336 }
337
338 // ----------------------------------------------------------------------------
339 // selection
340 // ----------------------------------------------------------------------------
341
342 int wxListbook::GetSelection() const
343 {
344 return m_selection;
345 }
346
347 int wxListbook::SetSelection(size_t n)
348 {
349 wxCHECK_MSG( n < GetPageCount(), wxNOT_FOUND,
350 _T("invalid page index in wxListbook::SetSelection()") );
351
352 int selOld = m_selection;
353
354 if ( (int)n != m_selection )
355 {
356 m_selection = n;
357
358 m_list->Select(m_selection);
359 m_list->Focus(m_selection);
360 }
361
362 return selOld;
363 }
364
365
366 // ----------------------------------------------------------------------------
367 // adding/removing the pages
368 // ----------------------------------------------------------------------------
369
370 bool
371 wxListbook::InsertPage(size_t n,
372 wxWindow *page,
373 const wxString& text,
374 bool bSelect,
375 int imageId)
376 {
377 if ( !wxBookCtrl::InsertPage(n, page, text, bSelect, imageId) )
378 return false;
379
380 m_list->InsertItem(n, text, imageId);
381
382 if ( bSelect )
383 {
384 m_list->Select(n);
385 m_list->Focus(n);
386 }
387 else // don't select this page
388 {
389 // it will be shown only when selected
390 page->Hide();
391 }
392
393 return true;
394 }
395
396 wxWindow *wxListbook::DoRemovePage(size_t page)
397 {
398 wxWindow *win = wxBookCtrl::DoRemovePage(page);
399 if ( win )
400 {
401 m_list->DeleteItem(page);
402 }
403
404 return win;
405 }
406
407 // ----------------------------------------------------------------------------
408 // wxListbook events
409 // ----------------------------------------------------------------------------
410
411 void wxListbook::OnListSelected(wxListEvent& eventList)
412 {
413 const int selNew = eventList.GetIndex();
414
415 if ( selNew == m_selection )
416 {
417 // this event can only come from our own Select(m_selection) below
418 // which we call when the page change is vetoed, so we should simply
419 // ignore it
420 return;
421 }
422
423 // first send "change in progress" event which may be vetoed by user
424 wxListbookEvent eventIng(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING, GetId());
425
426 eventIng.SetEventObject(this);
427 eventIng.SetSelection(selNew);
428 eventIng.SetOldSelection(m_selection);
429 if ( GetEventHandler()->ProcessEvent(eventIng) && !eventIng.IsAllowed() )
430 {
431 m_list->Select(m_selection);
432 return;
433 }
434
435 // change allowed: do change the page and notify the user about it
436 if ( m_selection != wxNOT_FOUND )
437 m_pages[m_selection]->Hide();
438 wxWindow *page = m_pages[m_selection = selNew];
439 page->SetSize(GetPageRect());
440 page->Show();
441
442 wxListbookEvent eventEd(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED, GetId());
443
444 eventEd.SetEventObject(this);
445 eventEd.SetSelection(selNew);
446 eventEd.SetOldSelection(m_selection);
447
448 (void)GetEventHandler()->ProcessEvent(eventEd);
449 }
450
451 #endif // wxUSE_LISTBOOK
452