1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: generic/listbkg.cpp
3 // Purpose: generic implementation of wxListbook
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "listbook.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
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"
39 // ----------------------------------------------------------------------------
41 // ----------------------------------------------------------------------------
43 // margin between the list and the page, should be bigger than wxStaticLine
45 const wxCoord MARGIN
= 5;
47 // ----------------------------------------------------------------------------
48 // various wxWidgets macros
49 // ----------------------------------------------------------------------------
51 IMPLEMENT_DYNAMIC_CLASS(wxListbook
, wxControl
)
52 IMPLEMENT_DYNAMIC_CLASS(wxListbookEvent
, wxNotifyEvent
)
54 const wxEventType wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING
= wxNewEventType();
55 const wxEventType wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED
= wxNewEventType();
56 const int wxID_LISTBOOKLISTVIEW
= wxNewId();
58 BEGIN_EVENT_TABLE(wxListbook
, wxBookCtrl
)
59 EVT_SIZE(wxListbook::OnSize
)
60 EVT_LIST_ITEM_SELECTED(wxID_LISTBOOKLISTVIEW
, wxListbook::OnListSelected
)
63 // ============================================================================
64 // wxListbook implementation
65 // ============================================================================
67 // ----------------------------------------------------------------------------
68 // wxListbook creation
69 // ----------------------------------------------------------------------------
71 void wxListbook::Init()
74 #if wxUSE_LINE_IN_LISTBOOK
76 #endif // wxUSE_LINE_IN_LISTBOOK
77 m_selection
= wxNOT_FOUND
;
81 wxListbook::Create(wxWindow
*parent
,
88 if ( (style
& wxLB_ALIGN_MASK
) == wxLB_DEFAULT
)
94 #endif // __WXMAC__/!__WXMAC__
97 // no border for this control, it doesn't look nice together with
99 style
&= ~wxBORDER_MASK
;
100 style
|= wxBORDER_NONE
;
102 if ( !wxControl::Create(parent
, id
, pos
, size
, style
,
103 wxDefaultValidator
, name
) )
106 m_list
= new wxListView
109 wxID_LISTBOOKLISTVIEW
,
112 wxLC_ICON
| wxLC_SINGLE_SEL
|
113 (IsVertical() ? wxLC_ALIGN_LEFT
: wxLC_ALIGN_TOP
)
116 #if wxUSE_LINE_IN_LISTBOOK
117 m_line
= new wxStaticLine
123 IsVertical() ? wxLI_HORIZONTAL
: wxLI_VERTICAL
125 #endif // wxUSE_LINE_IN_LISTBOOK
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.
135 GetEventHandler()->AddPendingEvent(evt
);
140 // ----------------------------------------------------------------------------
141 // wxListbook geometry management
142 // ----------------------------------------------------------------------------
144 wxSize
wxListbook::GetListSize() const
146 const wxSize sizeClient
= GetClientSize(),
147 sizeList
= m_list
->GetViewRect().GetSize();
152 size
.x
= sizeClient
.x
;
155 else // left/right aligned
158 size
.y
= sizeClient
.y
;
164 wxRect
wxListbook::GetPageRect() const
166 const wxSize sizeList
= m_list
->GetSize();
168 wxRect
rectPage(wxPoint(0, 0), GetClientSize());
169 switch ( GetWindowStyle() & wxLB_ALIGN_MASK
)
172 wxFAIL_MSG( _T("unexpected wxListbook alignment") );
176 rectPage
.y
= sizeList
.y
+ MARGIN
;
180 rectPage
.height
-= sizeList
.y
+ MARGIN
;
184 rectPage
.x
= sizeList
.x
+ MARGIN
;
188 rectPage
.width
-= sizeList
.x
+ MARGIN
;
195 void wxListbook::OnSize(wxSizeEvent
& event
)
201 // we're not fully created yet
205 // resize the list control and the page area to fit inside our new size
206 const wxSize sizeClient
= GetClientSize(),
207 sizeList
= GetListSize();
210 switch ( GetWindowStyle() & wxLB_ALIGN_MASK
)
213 wxFAIL_MSG( _T("unexpected wxListbook alignment") );
218 // posList is already ok
222 posList
.y
= sizeClient
.y
- sizeList
.y
;
226 posList
.x
= sizeClient
.x
- sizeList
.x
;
230 m_list
->Move(posList
.x
, posList
.y
);
231 m_list
->SetClientSize(sizeList
.x
, sizeList
.y
);
233 #if wxUSE_LINE_IN_LISTBOOK
236 wxRect
rectLine(wxPoint(0, 0), sizeClient
);
238 switch ( GetWindowStyle() & wxLB_ALIGN_MASK
)
241 rectLine
.y
= sizeList
.y
+ 1;
242 rectLine
.height
= MARGIN
- 2;
246 rectLine
.height
= MARGIN
- 2;
247 rectLine
.y
= sizeClient
.y
- sizeList
.y
- rectLine
.height
;
251 rectLine
.x
= sizeList
.x
+ 1;
252 rectLine
.width
= MARGIN
- 2;
256 rectLine
.width
= MARGIN
- 2;
257 rectLine
.x
= sizeClient
.x
- sizeList
.x
- rectLine
.width
;
261 m_line
->SetSize(rectLine
);
263 #endif // wxUSE_LINE_IN_LISTBOOK
265 // resize the currently shown page
266 if (m_selection
!= wxNOT_FOUND
)
268 wxWindow
*page
= m_pages
[m_selection
];
269 wxCHECK_RET( page
, _T("NULL page in wxListbook?") );
270 page
->SetSize(GetPageRect());
274 wxSize
wxListbook::CalcSizeFromPage(const wxSize
& sizePage
) const
276 // we need to add the size of the list control and the margin
277 const wxSize sizeList
= GetListSize();
279 wxSize size
= sizePage
;
282 size
.y
+= sizeList
.y
+ MARGIN
;
284 else // left/right aligned
286 size
.x
+= sizeList
.x
+ MARGIN
;
293 // ----------------------------------------------------------------------------
294 // accessing the pages
295 // ----------------------------------------------------------------------------
297 bool wxListbook::SetPageText(size_t n
, const wxString
& strText
)
299 m_list
->SetItemText(n
, strText
);
304 wxString
wxListbook::GetPageText(size_t n
) const
306 return m_list
->GetItemText(n
);
309 int wxListbook::GetPageImage(size_t WXUNUSED(n
)) const
311 wxFAIL_MSG( _T("wxListbook::GetPageImage() not implemented") );
316 bool wxListbook::SetPageImage(size_t n
, int imageId
)
318 return m_list
->SetItemImage(n
, imageId
, imageId
);
321 // ----------------------------------------------------------------------------
323 // ----------------------------------------------------------------------------
325 void wxListbook::SetImageList(wxImageList
*imageList
)
327 m_list
->SetImageList(imageList
, wxIMAGE_LIST_NORMAL
);
329 wxBookCtrl::SetImageList(imageList
);
332 // ----------------------------------------------------------------------------
334 // ----------------------------------------------------------------------------
336 int wxListbook::GetSelection() const
341 int wxListbook::SetSelection(size_t n
)
343 wxCHECK_MSG( n
< GetPageCount(), wxNOT_FOUND
,
344 _T("invalid page index in wxListbook::SetSelection()") );
346 const int selOld
= m_selection
;
348 if ( (int)n
!= m_selection
)
350 if ( m_selection
!= wxNOT_FOUND
)
351 m_pages
[m_selection
]->Hide();
352 wxWindow
*page
= m_pages
[n
];
353 page
->SetSize(GetPageRect());
356 // change m_selection only now to ignore the selection change event
366 // ----------------------------------------------------------------------------
367 // adding/removing the pages
368 // ----------------------------------------------------------------------------
371 wxListbook::InsertPage(size_t n
,
373 const wxString
& text
,
377 if ( !wxBookCtrl::InsertPage(n
, page
, text
, bSelect
, imageId
) )
380 m_list
->InsertItem(n
, text
, imageId
);
382 // we should always have some selection if possible
383 if ( bSelect
|| (m_selection
== wxNOT_FOUND
) )
387 else // don't select this page
389 // it will be shown only when selected
393 InvalidateBestSize();
397 wxWindow
*wxListbook::DoRemovePage(size_t page
)
399 const int page_count
= GetPageCount();
400 wxWindow
*win
= wxBookCtrl::DoRemovePage(page
);
404 m_list
->DeleteItem(page
);
406 if (m_selection
>= (int)page
)
408 // force new sel valid if possible
409 int sel
= m_selection
- 1;
412 else if ((page_count
== 2) || (sel
== -1))
415 // force sel invalid if deleting current page - don't try to hide it
416 m_selection
= (m_selection
== (int)page
) ? wxNOT_FOUND
: m_selection
- 1;
418 if ((sel
!= wxNOT_FOUND
) && (sel
!= m_selection
))
427 bool wxListbook::DeleteAllPages()
429 m_list
->DeleteAllItems();
430 return wxBookCtrl::DeleteAllPages();
433 // ----------------------------------------------------------------------------
435 // ----------------------------------------------------------------------------
437 void wxListbook::OnListSelected(wxListEvent
& eventList
)
439 const int selNew
= eventList
.GetIndex();
440 const int selOld
= m_selection
;
442 if ( selNew
== m_selection
)
444 // this event can only come from our own Select(m_selection) below
445 // which we call when the page change is vetoed, so we should simply
450 // first send "change in progress" event which may be vetoed by user
451 wxListbookEvent
eventIng(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING
, GetId());
453 eventIng
.SetEventObject(this);
454 eventIng
.SetSelection(selNew
);
455 eventIng
.SetOldSelection(selOld
);
456 if ( GetEventHandler()->ProcessEvent(eventIng
) && !eventIng
.IsAllowed() )
458 m_list
->Select(m_selection
);
462 // change allowed: do change the page and notify the user about it
463 SetSelection(selNew
);
465 wxListbookEvent
eventEd(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED
, GetId());
467 eventEd
.SetEventObject(this);
468 eventEd
.SetSelection(selNew
);
469 eventEd
.SetOldSelection(selOld
);
471 (void)GetEventHandler()->ProcessEvent(eventEd
);
474 #endif // wxUSE_LISTBOOK