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