]>
git.saurik.com Git - wxWidgets.git/blob - src/common/bookctrl.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/bookctrl.cpp
3 // Purpose: wxBookCtrlBase implementation
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
28 #include "wx/imaglist.h"
30 #include "wx/bookctrl.h"
32 // ============================================================================
34 // ============================================================================
36 // ----------------------------------------------------------------------------
38 // ----------------------------------------------------------------------------
40 IMPLEMENT_ABSTRACT_CLASS(wxBookCtrlBase
, wxControl
)
42 BEGIN_EVENT_TABLE(wxBookCtrlBase
, wxControl
)
43 EVT_SIZE(wxBookCtrlBase::OnSize
)
45 EVT_HELP(wxID_ANY
, wxBookCtrlBase::OnHelp
)
49 // ----------------------------------------------------------------------------
50 // constructors and destructors
51 // ----------------------------------------------------------------------------
53 void wxBookCtrlBase::Init()
55 m_selection
= wxNOT_FOUND
;
57 m_fitToCurrentPage
= false;
59 #if defined(__WXWINCE__)
66 m_controlSizer
= NULL
;
70 wxBookCtrlBase::Create(wxWindow
*parent
,
77 return wxControl::Create
89 // ----------------------------------------------------------------------------
91 // ----------------------------------------------------------------------------
93 void wxBookCtrlBase::DoInvalidateBestSize()
95 // notice that it is not necessary to invalidate our own best size
96 // explicitly if we have m_bookctrl as it will already invalidate the best
97 // size of its parent when its own size is invalidated and its parent is
100 m_bookctrl
->InvalidateBestSize();
102 wxControl::InvalidateBestSize();
105 wxSize
wxBookCtrlBase::CalcSizeFromPage(const wxSize
& sizePage
) const
107 // Add the size of the controller and the border between if it's shown.
108 if ( !m_bookctrl
|| !m_bookctrl
->IsShown() )
111 // Notice that the controller size is its current size while we really want
112 // to have its best size. So we only take into account its size in the
113 // direction in which we should add it but not in the other one, where the
114 // controller size is determined by the size of wxBookCtrl itself.
115 const wxSize sizeController
= GetControllerSize();
117 wxSize size
= sizePage
;
119 size
.y
+= sizeController
.y
+ GetInternalBorder();
120 else // left/right aligned
121 size
.x
+= sizeController
.x
+ GetInternalBorder();
126 void wxBookCtrlBase::SetPageSize(const wxSize
& size
)
128 SetClientSize(CalcSizeFromPage(size
));
131 wxSize
wxBookCtrlBase::DoGetBestSize() const
135 if (m_fitToCurrentPage
&& GetCurrentPage())
137 bestSize
= GetCurrentPage()->GetBestSize();
141 // iterate over all pages, get the largest width and height
142 const size_t nCount
= m_pages
.size();
143 for ( size_t nPage
= 0; nPage
< nCount
; nPage
++ )
145 const wxWindow
* const pPage
= m_pages
[nPage
];
147 bestSize
.IncTo(pPage
->GetBestSize());
151 // convert display area to window area, adding the size necessary for the
153 wxSize best
= CalcSizeFromPage(bestSize
);
158 wxRect
wxBookCtrlBase::GetPageRect() const
160 const wxSize size
= GetControllerSize();
163 wxRect
rectPage(pt
, GetClientSize());
165 switch ( GetWindowStyle() & wxBK_ALIGN_MASK
)
168 wxFAIL_MSG( wxT("unexpected alignment") );
172 rectPage
.y
= size
.y
+ GetInternalBorder();
176 rectPage
.height
-= size
.y
+ GetInternalBorder();
177 if (rectPage
.height
< 0)
182 rectPage
.x
= size
.x
+ GetInternalBorder();
186 rectPage
.width
-= size
.x
+ GetInternalBorder();
187 if (rectPage
.width
< 0)
196 void wxBookCtrlBase::DoSize()
200 // we're not fully created yet or OnSize() should be hidden by derived class
208 // resize controller and the page area to fit inside our new size
209 const wxSize
sizeClient( GetClientSize() ),
210 sizeBorder( m_bookctrl
->GetSize() - m_bookctrl
->GetClientSize() ),
211 sizeCtrl( GetControllerSize() );
213 m_bookctrl
->SetClientSize( sizeCtrl
.x
- sizeBorder
.x
, sizeCtrl
.y
- sizeBorder
.y
);
214 // if this changes the visibility of the scrollbars the best size changes, relayout in this case
215 wxSize sizeCtrl2
= GetControllerSize();
216 if ( sizeCtrl
!= sizeCtrl2
)
218 wxSize sizeBorder2
= m_bookctrl
->GetSize() - m_bookctrl
->GetClientSize();
219 m_bookctrl
->SetClientSize( sizeCtrl2
.x
- sizeBorder2
.x
, sizeCtrl2
.y
- sizeBorder2
.y
);
222 const wxSize sizeNew
= m_bookctrl
->GetSize();
224 switch ( GetWindowStyle() & wxBK_ALIGN_MASK
)
227 wxFAIL_MSG( wxT("unexpected alignment") );
232 // posCtrl is already ok
236 posCtrl
.y
= sizeClient
.y
- sizeNew
.y
;
240 posCtrl
.x
= sizeClient
.x
- sizeNew
.x
;
244 if ( m_bookctrl
->GetPosition() != posCtrl
)
245 m_bookctrl
->Move(posCtrl
);
248 // resize all pages to fit the new control size
249 const wxRect pageRect
= GetPageRect();
250 const unsigned pagesCount
= m_pages
.GetCount();
251 for ( unsigned int i
= 0; i
< pagesCount
; ++i
)
253 wxWindow
* const page
= m_pages
[i
];
256 wxASSERT_MSG( AllowNullPage(),
257 wxT("Null page in a control that does not allow null pages?") );
261 page
->SetSize(pageRect
);
265 void wxBookCtrlBase::OnSize(wxSizeEvent
& event
)
272 wxSize
wxBookCtrlBase::GetControllerSize() const
274 // For at least some book controls (e.g. wxChoicebook) it may make sense to
275 // (temporarily?) hide the controller and we shouldn't leave extra space
276 // for the hidden control in this case.
277 if ( !m_bookctrl
|| !m_bookctrl
->IsShown() )
280 const wxSize sizeClient
= GetClientSize();
284 // Ask for the best width/height considering the other direction.
287 size
.x
= sizeClient
.x
;
288 size
.y
= m_bookctrl
->GetBestHeight(sizeClient
.x
);
290 else // left/right aligned
292 size
.x
= m_bookctrl
->GetBestWidth(sizeClient
.y
);
293 size
.y
= sizeClient
.y
;
299 // ----------------------------------------------------------------------------
300 // miscellaneous stuff
301 // ----------------------------------------------------------------------------
305 void wxBookCtrlBase::OnHelp(wxHelpEvent
& event
)
307 // determine where does this even originate from to avoid redirecting it
308 // back to the page which generated it (resulting in an infinite loop)
310 // notice that we have to check in the hard(er) way instead of just testing
311 // if the event object == this because the book control can have other
312 // subcontrols inside it (e.g. wxSpinButton in case of a notebook in wxUniv)
313 wxWindow
*source
= wxStaticCast(event
.GetEventObject(), wxWindow
);
314 while ( source
&& source
!= this && source
->GetParent() != this )
316 source
= source
->GetParent();
319 if ( source
&& m_pages
.Index(source
) == wxNOT_FOUND
)
321 // this event is for the book control itself, redirect it to the
322 // corresponding page
323 wxWindow
*page
= NULL
;
325 if ( event
.GetOrigin() == wxHelpEvent::Origin_HelpButton
)
327 // show help for the page under the mouse
328 const int pagePos
= HitTest(ScreenToClient(event
.GetPosition()));
330 if ( pagePos
!= wxNOT_FOUND
)
332 page
= GetPage((size_t)pagePos
);
335 else // event from keyboard or unknown source
337 // otherwise show the current page help
338 page
= GetCurrentPage();
343 // change event object to the page to avoid infinite recursion if
344 // we get this event ourselves if the page doesn't handle it
345 event
.SetEventObject(page
);
347 if ( page
->GetEventHandler()->ProcessEvent(event
) )
349 // don't call event.Skip()
354 //else: event coming from one of our pages already
361 // ----------------------------------------------------------------------------
363 // ----------------------------------------------------------------------------
366 wxBookCtrlBase::InsertPage(size_t nPage
,
368 const wxString
& WXUNUSED(text
),
369 bool WXUNUSED(bSelect
),
370 int WXUNUSED(imageId
))
372 wxCHECK_MSG( page
|| AllowNullPage(), false,
373 wxT("NULL page in wxBookCtrlBase::InsertPage()") );
374 wxCHECK_MSG( nPage
<= m_pages
.size(), false,
375 wxT("invalid page index in wxBookCtrlBase::InsertPage()") );
377 m_pages
.Insert(page
, nPage
);
379 page
->SetSize(GetPageRect());
381 DoInvalidateBestSize();
386 bool wxBookCtrlBase::DeletePage(size_t nPage
)
388 wxWindow
*page
= DoRemovePage(nPage
);
389 if ( !(page
|| AllowNullPage()) )
392 // delete NULL is harmless
398 wxWindow
*wxBookCtrlBase::DoRemovePage(size_t nPage
)
400 wxCHECK_MSG( nPage
< m_pages
.size(), NULL
,
401 wxT("invalid page index in wxBookCtrlBase::DoRemovePage()") );
403 wxWindow
*pageRemoved
= m_pages
[nPage
];
404 m_pages
.RemoveAt(nPage
);
405 DoInvalidateBestSize();
410 int wxBookCtrlBase::GetNextPage(bool forward
) const
414 int nMax
= GetPageCount();
415 if ( nMax
-- ) // decrement it to get the last valid index
417 int nSel
= GetSelection();
419 // change selection wrapping if it becomes invalid
420 nPage
= forward
? nSel
== nMax
? 0
425 else // notebook is empty, no next page
433 int wxBookCtrlBase::FindPage(const wxWindow
* page
) const
435 const size_t nCount
= m_pages
.size();
436 for ( size_t nPage
= 0; nPage
< nCount
; nPage
++ )
438 if ( m_pages
[nPage
] == page
)
445 bool wxBookCtrlBase::DoSetSelectionAfterInsertion(size_t n
, bool bSelect
)
449 else if ( m_selection
== wxNOT_FOUND
)
451 else // We're not going to select this page.
454 // Return true to indicate that we selected this page.
458 void wxBookCtrlBase::DoSetSelectionAfterRemoval(size_t n
)
460 if ( m_selection
>= (int)n
)
462 // ensure that the selection is valid
464 if ( GetPageCount() == 0 )
467 sel
= m_selection
? m_selection
- 1 : 0;
469 // if deleting current page we shouldn't try to hide it
470 m_selection
= m_selection
== (int)n
? wxNOT_FOUND
473 if ( sel
!= wxNOT_FOUND
&& sel
!= m_selection
)
478 int wxBookCtrlBase::DoSetSelection(size_t n
, int flags
)
480 wxCHECK_MSG( n
< GetPageCount(), wxNOT_FOUND
,
481 wxT("invalid page index in wxBookCtrlBase::DoSetSelection()") );
483 const int oldSel
= GetSelection();
485 if ( n
!= (size_t)oldSel
)
487 wxBookCtrlEvent
*event
= CreatePageChangingEvent();
488 bool allowed
= false;
490 if ( flags
& SetSelection_SendEvent
)
492 event
->SetSelection(n
);
493 event
->SetOldSelection(oldSel
);
494 event
->SetEventObject(this);
496 allowed
= !GetEventHandler()->ProcessEvent(*event
) || event
->IsAllowed();
499 if ( !(flags
& SetSelection_SendEvent
) || allowed
)
501 if ( oldSel
!= wxNOT_FOUND
)
502 DoShowPage(m_pages
[oldSel
], false);
504 wxWindow
*page
= m_pages
[n
];
505 page
->SetSize(GetPageRect());
506 DoShowPage(page
, true);
508 // change selection now to ignore the selection change event
509 UpdateSelectedPage(n
);
511 if ( flags
& SetSelection_SendEvent
)
513 // program allows the page change
514 MakeChangedEvent(*event
);
515 (void)GetEventHandler()->ProcessEvent(*event
);
525 IMPLEMENT_DYNAMIC_CLASS(wxBookCtrlEvent
, wxNotifyEvent
)
527 #endif // wxUSE_BOOKCTRL