Include imaglist.h
[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 // resize the list control and the page area to fit inside our new size
197 const wxSize sizeClient = GetClientSize(),
198 sizeList = GetListSize();
199
200 wxPoint posList;
201 switch ( GetWindowStyle() & wxLB_ALIGN_MASK )
202 {
203 default:
204 wxFAIL_MSG( _T("unexpected wxListbook alignment") );
205 // fall through
206
207 case wxLB_TOP:
208 case wxLB_LEFT:
209 // posList is already ok
210 break;
211
212 case wxLB_BOTTOM:
213 posList.y = sizeClient.y - sizeList.y;
214 break;
215
216 case wxLB_RIGHT:
217 posList.x = sizeClient.x - sizeList.x;
218 break;
219 }
220
221 m_list->SetSize(posList.x, posList.y, sizeList.x, sizeList.y);
222
223 if ( m_line )
224 {
225 wxRect rectLine(wxPoint(0, 0), sizeClient);
226
227 switch ( GetWindowStyle() & wxLB_ALIGN_MASK )
228 {
229 case wxLB_TOP:
230 rectLine.y = sizeList.y + 1;
231 rectLine.height = MARGIN - 2;
232 break;
233
234 case wxLB_BOTTOM:
235 rectLine.height = MARGIN - 2;
236 rectLine.y = sizeClient.y - sizeList.y - rectLine.height;
237 break;
238
239 case wxLB_LEFT:
240 rectLine.x = sizeList.x + 1;
241 rectLine.width = MARGIN - 2;
242 break;
243
244 case wxLB_RIGHT:
245 rectLine.width = MARGIN - 2;
246 rectLine.x = sizeClient.x - sizeList.x - rectLine.width;
247 break;
248 }
249
250 m_line->SetSize(rectLine);
251 }
252
253 // we should always have some selection if possible
254 if ( m_selection == wxNOT_FOUND && GetPageCount() )
255 {
256 SetSelection(0);
257 }
258
259 if ( m_selection != wxNOT_FOUND )
260 {
261 wxWindow *page = m_pages[m_selection];
262 wxCHECK_RET( page, _T("NULL page in wxListbook?") );
263
264 page->SetSize(GetPageRect());
265 if ( !page->IsShown() )
266 {
267 page->Show();
268 }
269 }
270
271 event.Skip();
272 }
273
274 wxSize wxListbook::CalcSizeFromPage(const wxSize& sizePage) const
275 {
276 // we need to add the size of the list control and the margin
277 const wxSize sizeList = GetListSize();
278
279 wxSize size = sizePage;
280 if ( IsVertical() )
281 {
282 size.y += sizeList.y + MARGIN;
283 }
284 else // left/right aligned
285 {
286 size.x += sizeList.x + MARGIN;
287 }
288
289 return size;
290 }
291
292
293 // ----------------------------------------------------------------------------
294 // accessing the pages
295 // ----------------------------------------------------------------------------
296
297 bool wxListbook::SetPageText(size_t n, const wxString& strText)
298 {
299 m_list->SetItemText(n, strText);
300
301 return true;
302 }
303
304 wxString wxListbook::GetPageText(size_t n) const
305 {
306 return m_list->GetItemText(n);
307 }
308
309 int wxListbook::GetPageImage(size_t WXUNUSED(n)) const
310 {
311 wxFAIL_MSG( _T("wxListbook::GetPageImage() not implemented") );
312
313 return -1;
314 }
315
316 bool wxListbook::SetPageImage(size_t n, int imageId)
317 {
318 return m_list->SetItemImage(n, imageId, imageId);
319 }
320
321 // ----------------------------------------------------------------------------
322 // image list stuff
323 // ----------------------------------------------------------------------------
324
325 void wxListbook::SetImageList(wxImageList *imageList)
326 {
327 m_list->SetImageList(imageList, wxIMAGE_LIST_NORMAL);
328
329 wxBookCtrl::SetImageList(imageList);
330 }
331
332 // ----------------------------------------------------------------------------
333 // selection
334 // ----------------------------------------------------------------------------
335
336 int wxListbook::GetSelection() const
337 {
338 return m_selection;
339 }
340
341 int wxListbook::SetSelection(size_t n)
342 {
343 wxCHECK_MSG( n < GetPageCount(), wxNOT_FOUND,
344 _T("invalid page index in wxListbook::SetSelection()") );
345
346 int selOld = m_selection;
347
348 if ( (int)n != m_selection )
349 {
350 m_selection = n;
351
352 m_list->Select(m_selection);
353 m_list->Focus(m_selection);
354 }
355
356 return selOld;
357 }
358
359
360 // ----------------------------------------------------------------------------
361 // adding/removing the pages
362 // ----------------------------------------------------------------------------
363
364 bool
365 wxListbook::InsertPage(size_t n,
366 wxWindow *page,
367 const wxString& text,
368 bool bSelect,
369 int imageId)
370 {
371 if ( !wxBookCtrl::InsertPage(n, page, text, bSelect, imageId) )
372 return false;
373
374 m_list->InsertItem(n, text, imageId);
375
376 if ( bSelect )
377 {
378 m_list->Select(n);
379 m_list->Focus(n);
380 }
381 else // don't select this page
382 {
383 // it will be shown only when selected
384 page->Hide();
385 }
386
387 return true;
388 }
389
390 wxWindow *wxListbook::DoRemovePage(size_t page)
391 {
392 wxWindow *win = wxBookCtrl::DoRemovePage(page);
393 if ( win )
394 {
395 m_list->DeleteItem(page);
396 }
397
398 return win;
399 }
400
401 // ----------------------------------------------------------------------------
402 // wxListbook events
403 // ----------------------------------------------------------------------------
404
405 void wxListbook::OnListSelected(wxListEvent& eventList)
406 {
407 const int selNew = eventList.GetIndex();
408
409 if ( selNew == m_selection )
410 {
411 // this event can only come from our own Select(m_selection) below
412 // which we call when the page change is vetoed, so we should simply
413 // ignore it
414 return;
415 }
416
417 // first send "change in progress" event which may be vetoed by user
418 wxListbookEvent eventIng(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING, GetId());
419
420 eventIng.SetEventObject(this);
421 eventIng.SetSelection(selNew);
422 eventIng.SetOldSelection(m_selection);
423 if ( GetEventHandler()->ProcessEvent(eventIng) && !eventIng.IsAllowed() )
424 {
425 m_list->Select(m_selection);
426 return;
427 }
428
429 // change allowed: do change the page and notify the user about it
430 if ( m_selection != wxNOT_FOUND )
431 m_pages[m_selection]->Hide();
432 wxWindow *page = m_pages[m_selection = selNew];
433 page->SetSize(GetPageRect());
434 page->Show();
435
436 wxListbookEvent eventEd(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED, GetId());
437
438 eventEd.SetEventObject(this);
439 eventEd.SetSelection(selNew);
440 eventEd.SetOldSelection(m_selection);
441
442 (void)GetEventHandler()->ProcessEvent(eventEd);
443 }
444
445 #endif // wxUSE_LISTBOOK
446