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