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