Introduced the ability to size a book control based on the currently selected page
[wxWidgets.git] / src / common / bookctrl.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/bookctrl.cpp
3 // Purpose: wxBookCtrlBase implementation
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 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_BOOKCTRL
28
29 #include "wx/imaglist.h"
30
31 #include "wx/bookctrl.h"
32
33 // ============================================================================
34 // implementation
35 // ============================================================================
36
37 // ----------------------------------------------------------------------------
38 // event table
39 // ----------------------------------------------------------------------------
40
41 IMPLEMENT_ABSTRACT_CLASS(wxBookCtrlBase, wxControl)
42
43 BEGIN_EVENT_TABLE(wxBookCtrlBase, wxControl)
44 EVT_SIZE(wxBookCtrlBase::OnSize)
45 END_EVENT_TABLE()
46
47 // ----------------------------------------------------------------------------
48 // constructors and destructors
49 // ----------------------------------------------------------------------------
50
51 void wxBookCtrlBase::Init()
52 {
53 m_bookctrl = NULL;
54 m_imageList = NULL;
55 m_ownsImageList = false;
56 m_shrinkToFit = false;
57
58 #if defined(__WXWINCE__)
59 m_internalBorder = 1;
60 #else
61 m_internalBorder = 5;
62 #endif
63 }
64
65 bool
66 wxBookCtrlBase::Create(wxWindow *parent,
67 wxWindowID id,
68 const wxPoint& pos,
69 const wxSize& size,
70 long style,
71 const wxString& name)
72 {
73 return wxControl::Create
74 (
75 parent,
76 id,
77 pos,
78 size,
79 style,
80 wxDefaultValidator,
81 name
82 );
83 }
84
85 wxBookCtrlBase::~wxBookCtrlBase()
86 {
87 if ( m_ownsImageList )
88 {
89 // may be NULL, ok
90 delete m_imageList;
91 }
92 }
93
94 // ----------------------------------------------------------------------------
95 // image list
96 // ----------------------------------------------------------------------------
97
98 void wxBookCtrlBase::SetImageList(wxImageList *imageList)
99 {
100 if ( m_ownsImageList )
101 {
102 // may be NULL, ok
103 delete m_imageList;
104
105 m_ownsImageList = false;
106 }
107
108 m_imageList = imageList;
109 }
110
111 void wxBookCtrlBase::AssignImageList(wxImageList* imageList)
112 {
113 SetImageList(imageList);
114
115 m_ownsImageList = true;
116 }
117
118 // ----------------------------------------------------------------------------
119 // geometry
120 // ----------------------------------------------------------------------------
121
122 void wxBookCtrlBase::SetPageSize(const wxSize& size)
123 {
124 SetClientSize(CalcSizeFromPage(size));
125 }
126
127 wxSize wxBookCtrlBase::DoGetBestSize() const
128 {
129 wxSize bestSize;
130
131 // iterate over all pages, get the largest width and height
132 const size_t nCount = m_pages.size();
133 for ( size_t nPage = 0; nPage < nCount; nPage++ )
134 {
135 const wxWindow * const pPage = m_pages[nPage];
136 if( pPage )
137 {
138 wxSize childBestSize(pPage->GetBestSize());
139
140 if ( childBestSize.x > bestSize.x )
141 bestSize.x = childBestSize.x;
142
143 if ( childBestSize.y > bestSize.y )
144 bestSize.y = childBestSize.y;
145 }
146 }
147
148 if (m_shrinkToFit && GetCurrentPage())
149 bestSize = GetCurrentPage()->GetBestSize();
150
151 // convert display area to window area, adding the size necessary for the
152 // tabs
153 wxSize best = CalcSizeFromPage(bestSize);
154 CacheBestSize(best);
155 return best;
156 }
157
158 // ----------------------------------------------------------------------------
159 // pages management
160 // ----------------------------------------------------------------------------
161
162 bool
163 wxBookCtrlBase::InsertPage(size_t nPage,
164 wxWindow *page,
165 const wxString& WXUNUSED(text),
166 bool WXUNUSED(bSelect),
167 int WXUNUSED(imageId))
168 {
169 wxCHECK_MSG( page || AllowNullPage(), false,
170 _T("NULL page in wxBookCtrlBase::InsertPage()") );
171 wxCHECK_MSG( nPage <= m_pages.size(), false,
172 _T("invalid page index in wxBookCtrlBase::InsertPage()") );
173
174 m_pages.Insert(page, nPage);
175 InvalidateBestSize();
176
177 return true;
178 }
179
180 bool wxBookCtrlBase::DeletePage(size_t nPage)
181 {
182 wxWindow *page = DoRemovePage(nPage);
183 if ( !(page || AllowNullPage()) )
184 return false;
185
186 // delete NULL is harmless
187 delete page;
188
189 return true;
190 }
191
192 wxWindow *wxBookCtrlBase::DoRemovePage(size_t nPage)
193 {
194 wxCHECK_MSG( nPage < m_pages.size(), NULL,
195 _T("invalid page index in wxBookCtrlBase::DoRemovePage()") );
196
197 wxWindow *pageRemoved = m_pages[nPage];
198 m_pages.RemoveAt(nPage);
199 InvalidateBestSize();
200
201 return pageRemoved;
202 }
203
204 int wxBookCtrlBase::GetNextPage(bool forward) const
205 {
206 int nPage;
207
208 int nMax = GetPageCount();
209 if ( nMax-- ) // decrement it to get the last valid index
210 {
211 int nSel = GetSelection();
212
213 // change selection wrapping if it becomes invalid
214 nPage = forward ? nSel == nMax ? 0
215 : nSel + 1
216 : nSel == 0 ? nMax
217 : nSel - 1;
218 }
219 else // notebook is empty, no next page
220 {
221 nPage = wxNOT_FOUND;
222 }
223
224 return nPage;
225 }
226
227 wxRect wxBookCtrlBase::GetPageRect() const
228 {
229 const wxSize size = GetControllerSize();
230
231 wxPoint pt;
232 wxRect rectPage(pt, GetClientSize());
233 switch ( GetWindowStyle() & wxBK_ALIGN_MASK )
234 {
235 default:
236 wxFAIL_MSG( _T("unexpected alignment") );
237 // fall through
238
239 case wxBK_TOP:
240 rectPage.y = size.y + GetInternalBorder();
241 // fall through
242
243 case wxBK_BOTTOM:
244 rectPage.height -= size.y + GetInternalBorder();
245 break;
246
247 case wxBK_LEFT:
248 rectPage.x = size.x + GetInternalBorder();
249 // fall through
250
251 case wxBK_RIGHT:
252 rectPage.width -= size.x + GetInternalBorder();
253 break;
254 }
255
256 return rectPage;
257 }
258
259 // Lay out controls
260 void wxBookCtrlBase::DoSize()
261 {
262 if ( !m_bookctrl )
263 {
264 // we're not fully created yet or OnSize() should be hidden by derived class
265 return;
266 }
267
268 // resize controller and the page area to fit inside our new size
269 const wxSize sizeClient( GetClientSize() ),
270 sizeBorder( m_bookctrl->GetSize() - m_bookctrl->GetClientSize() ),
271 sizeCtrl( GetControllerSize() );
272
273 m_bookctrl->SetClientSize( sizeCtrl.x - sizeBorder.x, sizeCtrl.y - sizeBorder.y );
274
275 const wxSize sizeNew = m_bookctrl->GetSize();
276 wxPoint posCtrl;
277 switch ( GetWindowStyle() & wxBK_ALIGN_MASK )
278 {
279 default:
280 wxFAIL_MSG( _T("unexpected alignment") );
281 // fall through
282
283 case wxBK_TOP:
284 case wxBK_LEFT:
285 // posCtrl is already ok
286 break;
287
288 case wxBK_BOTTOM:
289 posCtrl.y = sizeClient.y - sizeNew.y;
290 break;
291
292 case wxBK_RIGHT:
293 posCtrl.x = sizeClient.x - sizeNew.x;
294 break;
295 }
296
297 if ( m_bookctrl->GetPosition() != posCtrl )
298 m_bookctrl->Move(posCtrl);
299
300 // resize the currently shown page
301 if (GetSelection() != wxNOT_FOUND )
302 {
303 wxWindow *page = m_pages[GetSelection()];
304 wxCHECK_RET( page, _T("NULL page?") );
305 page->SetSize(GetPageRect());
306 }
307 }
308
309 void wxBookCtrlBase::OnSize(wxSizeEvent& event)
310 {
311 event.Skip();
312
313 DoSize();
314 }
315
316 wxSize wxBookCtrlBase::GetControllerSize() const
317 {
318 if(!m_bookctrl)
319 return wxSize(0,0);
320
321 const wxSize sizeClient = GetClientSize(),
322 sizeBorder = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(),
323 sizeCtrl = m_bookctrl->GetBestSize() + sizeBorder;
324
325 wxSize size;
326
327 if ( IsVertical() )
328 {
329 size.x = sizeClient.x;
330 size.y = sizeCtrl.y;
331 }
332 else // left/right aligned
333 {
334 size.x = sizeCtrl.x;
335 size.y = sizeClient.y;
336 }
337
338 return size;
339 }
340
341 #endif // wxUSE_BOOKCTRL