1 /////////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     implementation of wxNotebook 
   4 // Author:      Stefan Csomor 
   8 // Copyright:   (c) Stefan Csomor 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  13 #pragma implementation "notebook.h" 
  16 // ============================================================================ 
  18 // ============================================================================ 
  20 // ---------------------------------------------------------------------------- 
  22 // ---------------------------------------------------------------------------- 
  23 #include "wx/wxprec.h" 
  28 #include "wx/string.h" 
  30 #include "wx/imaglist.h" 
  32 #include "wx/notebook.h" 
  33 #include "wx/mac/uma.h" 
  34 // ---------------------------------------------------------------------------- 
  36 // ---------------------------------------------------------------------------- 
  38 // check that the page index is valid 
  39 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) 
  42 // ---------------------------------------------------------------------------- 
  44 // ---------------------------------------------------------------------------- 
  46 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
) 
  47 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
) 
  49 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
) 
  50     EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange
) 
  52     EVT_SIZE(wxNotebook::OnSize
) 
  53     EVT_SET_FOCUS(wxNotebook::OnSetFocus
) 
  54     EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
) 
  57 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
) 
  58 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxCommandEvent
) 
  60 // ============================================================================ 
  62 // ============================================================================ 
  64 // ---------------------------------------------------------------------------- 
  65 // wxNotebook construction 
  66 // ---------------------------------------------------------------------------- 
  68 // common part of all ctors 
  69 void wxNotebook::Init() 
  74 // default for dynamic class 
  75 wxNotebook::wxNotebook() 
  80 // the same arguments as for wxControl 
  81 wxNotebook::wxNotebook(wxWindow 
*parent
, 
  90     Create(parent
, id
, pos
, size
, style
, name
); 
  94 bool wxNotebook::Create(wxWindow 
*parent
, 
 101     m_macIsUserPane 
= FALSE 
; 
 103     if ( !wxNotebookBase::Create(parent
, id
, pos
, size
, style
, name
) ) 
 106     Rect bounds 
= wxMacGetBoundsForControl( this , pos 
, size 
) ; 
 108     if( bounds
.right 
<= bounds
.left 
) 
 109         bounds
.right 
= bounds
.left 
+ 100 ; 
 110     if ( bounds
.bottom 
<= bounds
.top 
) 
 111         bounds
.bottom 
= bounds
.top 
+ 100 ; 
 113     UInt16 tabstyle 
= kControlTabDirectionNorth 
; 
 114     if ( HasFlag(wxNB_LEFT
) ) 
 115         tabstyle 
= kControlTabDirectionWest 
; 
 116     else if ( HasFlag( wxNB_RIGHT 
) ) 
 117         tabstyle 
= kControlTabDirectionEast 
; 
 118     else if ( HasFlag( wxNB_BOTTOM 
) ) 
 119         tabstyle 
= kControlTabDirectionSouth 
; 
 121     ControlTabSize tabsize 
= kControlTabSizeLarge 
; 
 122     if ( GetWindowVariant() == wxWINDOW_VARIANT_SMALL 
) 
 123         tabsize 
= kControlTabSizeSmall 
; 
 124     else if ( GetWindowVariant() == wxWINDOW_VARIANT_MINI 
) 
 126         if (UMAGetSystemVersion() >= 0x1030 ) 
 129             tabsize 
= kControlSizeSmall
;  
 132     m_peer 
= new wxMacControl(this) ; 
 133     verify_noerr ( CreateTabsControl( MAC_WXHWND(parent
->MacGetTopLevelWindowRef()) , &bounds 
, 
 134      tabsize 
, tabstyle
, 0, NULL
,  m_peer
->GetControlRefAddr() ) ); 
 137     MacPostControlCreate(pos
,size
) ; 
 142 wxNotebook::~wxNotebook() 
 146 // ---------------------------------------------------------------------------- 
 147 // wxNotebook accessors 
 148 // ---------------------------------------------------------------------------- 
 150 void wxNotebook::SetPadding(const wxSize
& padding
) 
 155 void wxNotebook::SetTabSize(const wxSize
& sz
) 
 160 void wxNotebook::SetPageSize(const wxSize
& size
) 
 162     SetSize( CalcSizeFromPage( size 
) ); 
 165 wxSize 
wxNotebook::CalcSizeFromPage(const wxSize
& sizePage
) const 
 167     return DoGetSizeFromClientSize( sizePage 
) ; 
 170 int wxNotebook::SetSelection(size_t nPage
) 
 172     wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") ); 
 174     if ( int(nPage
) != m_nSelection 
) 
 176         wxNotebookEvent 
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, m_windowId
); 
 177         event
.SetSelection(nPage
); 
 178         event
.SetOldSelection(m_nSelection
); 
 179         event
.SetEventObject(this); 
 180         if ( !GetEventHandler()->ProcessEvent(event
) || event
.IsAllowed() ) 
 182             // program allows the page change 
 183             event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
); 
 184             (void)GetEventHandler()->ProcessEvent(event
); 
 186             ChangePage(m_nSelection
, nPage
); 
 193 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
) 
 195     wxASSERT( IS_VALID_PAGE(nPage
) ); 
 197     wxNotebookPage 
*page 
= m_pages
[nPage
]; 
 198     page
->SetLabel(strText
); 
 204 wxString 
wxNotebook::GetPageText(size_t nPage
) const 
 206     wxASSERT( IS_VALID_PAGE(nPage
) ); 
 208     wxNotebookPage 
*page 
= m_pages
[nPage
]; 
 209     return page
->GetLabel(); 
 212 int wxNotebook::GetPageImage(size_t nPage
) const 
 214     wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, _T("invalid notebook page") ); 
 216     return m_images
[nPage
]; 
 219 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
) 
 221     wxCHECK_MSG( IS_VALID_PAGE(nPage
), FALSE
, _T("invalid notebook page") ); 
 223     wxCHECK_MSG( m_imageList 
&& nImage 
< m_imageList
->GetImageCount(), FALSE
, 
 224         _T("invalid image index in SetPageImage()") ); 
 226     if ( nImage 
!= m_images
[nPage
] ) 
 228         // if the item didn't have an icon before or, on the contrary, did have 
 229         // it but has lost it now, its size will change - but if the icon just 
 231         m_images
[nPage
] = nImage
; 
 239 // ---------------------------------------------------------------------------- 
 240 // wxNotebook operations 
 241 // ---------------------------------------------------------------------------- 
 243 // remove one page from the notebook, without deleting the window 
 244 wxNotebookPage
* wxNotebook::DoRemovePage(size_t nPage
) 
 246     wxCHECK( IS_VALID_PAGE(nPage
), NULL 
); 
 247     wxNotebookPage
* page 
= m_pages
[nPage
] ; 
 248     m_pages
.RemoveAt(nPage
); 
 252     if(m_nSelection 
>= (int)GetPageCount()) { 
 253         m_nSelection 
= GetPageCount() - 1; 
 255     if(m_nSelection 
>= 0) { 
 256         m_pages
[m_nSelection
]->Show(true); 
 258     InvalidateBestSize(); 
 263 bool wxNotebook::DeleteAllPages() 
 265     WX_CLEAR_ARRAY(m_pages
) ; 
 268     InvalidateBestSize(); 
 273 // same as AddPage() but does it at given position 
 274 bool wxNotebook::InsertPage(size_t nPage
, 
 275                             wxNotebookPage 
*pPage
, 
 276                             const wxString
& strText
, 
 280     if ( !wxNotebookBase::InsertPage(nPage
, pPage
, strText
, bSelect
, imageId
) ) 
 283     wxASSERT_MSG( pPage
->GetParent() == this, 
 284                     _T("notebook pages must have notebook as parent") ); 
 286     // don't show pages by default (we'll need to adjust their size first) 
 287     pPage
->Show( false ) ; 
 289     pPage
->SetLabel(strText
); 
 291     m_images
.Insert(imageId
, nPage
); 
 295     wxRect rect 
= GetPageRect() ; 
 296     pPage
->SetSize(rect
); 
 297     if ( pPage
->GetAutoLayout() ) { 
 302     // now deal with the selection 
 303     // --------------------------- 
 305     // if the inserted page is before the selected one, we must update the 
 306     // index of the selected page 
 308     if ( int(nPage
) <= m_nSelection 
)  
 311         // while this still is the same page showing, we need to update the tabs 
 312         m_peer
->SetValue( m_nSelection 
+ 1 ) ; 
 315     // some page should be selected: either this one or the first one if there 
 316     // is still no selection 
 320     else if ( m_nSelection 
== -1 ) 
 324         SetSelection(selNew
); 
 326     InvalidateBestSize(); 
 330 /* Added by Mark Newsam 
 331 * When a page is added or deleted to the notebook this function updates 
 332 * information held in the control so that it matches the order 
 333 * the user would expect. 
 335 void wxNotebook::MacSetupTabs() 
 337     m_peer
->SetMaximum( GetPageCount() ) ; 
 339     wxNotebookPage 
*page
; 
 340     ControlTabInfoRec info
; 
 342     const size_t countPages 
= GetPageCount(); 
 343     for(size_t ii 
= 0; ii 
< countPages
; ii
++) 
 347         info
.iconSuiteID 
= 0; 
 348         wxMacStringToPascal( page
->GetLabel() , info
.name 
) ; 
 349         m_peer
->SetData
<ControlTabInfoRec
>( ii
+1, kControlTabInfoTag
, &info 
) ; 
 350         m_peer
->SetTabEnabled( ii 
+ 1 , true ) ; 
 352         if ( GetImageList() && GetPageImage(ii
) >= 0 && UMAGetSystemVersion() >= 0x1020 ) 
 354             const wxBitmap
* bmap 
= GetImageList()->GetBitmapPtr( GetPageImage(ii 
) ) ; 
 357                 ControlButtonContentInfo info 
; 
 359                 wxMacCreateBitmapButton( &info 
, *bmap 
) ; 
 360                 OSStatus err 
= m_peer
->SetData
<ControlButtonContentInfo
>( ii
+1,kControlTabImageContentTag
, &info 
); 
 361                 wxASSERT_MSG( err 
== noErr 
, wxT("Error when setting icon on tab") ) ; 
 362                 wxMacReleaseBitmapButton( &info 
) ; 
 368     m_peer
->GetRectInWindowCoords( &bounds 
) ; 
 369     InvalWindowRect((WindowRef
)MacGetTopLevelWindowRef(), &bounds
); 
 372 wxRect 
wxNotebook::GetPageRect() const 
 374     wxSize size 
= GetClientSize() ; 
 375     return wxRect( 0 , 0 , size
.x 
, size
.y 
) ; 
 377 // ---------------------------------------------------------------------------- 
 378 // wxNotebook callbacks 
 379 // ---------------------------------------------------------------------------- 
 381 // @@@ OnSize() is used for setting the font when it's called for the first 
 382 //     time because doing it in ::Create() doesn't work (for unknown reasons) 
 383 void wxNotebook::OnSize(wxSizeEvent
& event
) 
 386     unsigned int nCount 
= m_pages
.Count(); 
 387     wxRect rect 
= GetPageRect() ; 
 388     for ( unsigned int nPage 
= 0; nPage 
< nCount
; nPage
++ ) { 
 389         wxNotebookPage 
*pPage 
= m_pages
[nPage
]; 
 390         pPage
->SetSize(rect
); 
 391         if ( pPage
->GetAutoLayout() ) { 
 396     // Processing continues to next OnSize 
 400 void wxNotebook::OnSelChange(wxNotebookEvent
& event
) 
 402     // is it our tab control? 
 403     if ( event
.GetEventObject() == this ) 
 404         ChangePage(event
.GetOldSelection(), event
.GetSelection()); 
 406     // we want to give others a chance to process this message as well 
 410 void wxNotebook::OnSetFocus(wxFocusEvent
& event
) 
 412     // set focus to the currently selected page if any 
 413     if ( m_nSelection 
!= -1 ) 
 414         m_pages
[m_nSelection
]->SetFocus(); 
 419 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
) 
 421     if ( event
.IsWindowChange() ) { 
 423         AdvanceSelection(event
.GetDirection()); 
 426         // we get this event in 2 cases 
 428         // a) one of our pages might have generated it because the user TABbed 
 429         // out from it in which case we should propagate the event upwards and 
 430         // our parent will take care of setting the focus to prev/next sibling 
 434         // b) the parent panel wants to give the focus to us so that we 
 435         // forward it to our selected page. We can't deal with this in 
 436         // OnSetFocus() because we don't know which direction the focus came 
 437         // from in this case and so can't choose between setting the focus to 
 438         // first or last panel child 
 439         wxWindow 
*parent 
= GetParent(); 
 440         // the cast is here to fic a GCC ICE 
 441         if ( ((wxWindow
*)event
.GetEventObject()) == parent 
) 
 443             // no, it doesn't come from child, case (b): forward to a page 
 444             if ( m_nSelection 
!= -1 ) 
 446                 // so that the page knows that the event comes from it's parent 
 447                 // and is being propagated downwards 
 448                 event
.SetEventObject(this); 
 450                 wxWindow 
*page 
= m_pages
[m_nSelection
]; 
 451                 if ( !page
->GetEventHandler()->ProcessEvent(event
) ) 
 455                 //else: page manages focus inside it itself 
 459                 // we have no pages - still have to give focus to _something_ 
 465             // it comes from our child, case (a), pass to the parent 
 467                 event
.SetCurrentFocus(this); 
 468                 parent
->GetEventHandler()->ProcessEvent(event
); 
 474 // ---------------------------------------------------------------------------- 
 475 // wxNotebook base class virtuals 
 476 // ---------------------------------------------------------------------------- 
 478 #if wxUSE_CONSTRAINTS 
 480 // override these 2 functions to do nothing: everything is done in OnSize 
 482 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
)) 
 484   // don't set the sizes of the pages - their correct size is not yet known 
 485   wxControl::SetConstraintSizes(FALSE
); 
 488 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
)) 
 493 #endif // wxUSE_CONSTRAINTS 
 495 void wxNotebook::Command(wxCommandEvent
& event
) 
 497     wxFAIL_MSG(wxT("wxNotebook::Command not implemented")); 
 500 // ---------------------------------------------------------------------------- 
 501 // wxNotebook helper functions 
 502 // ---------------------------------------------------------------------------- 
 504 // hide the currently active panel and show the new one 
 505 void wxNotebook::ChangePage(int nOldSel
, int nSel
) 
 509         m_pages
[nOldSel
]->Show(FALSE
); 
 514         wxNotebookPage 
*pPage 
= m_pages
[nSel
]; 
 520     m_peer
->SetValue( m_nSelection 
+ 1 ) ; 
 523 wxInt32 
wxNotebook::MacControlHit(WXEVENTHANDLERREF 
WXUNUSED(handler
) , WXEVENTREF 
WXUNUSED(event
) )  
 525     OSStatus status 
= eventNotHandledErr 
; 
 527     SInt32 newSel 
= m_peer
->GetValue() - 1 ; 
 528     if ( newSel 
!= m_nSelection 
) 
 530         wxNotebookEvent 
changing(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, m_windowId
, 
 531             newSel 
, m_nSelection
); 
 532         changing
.SetEventObject(this); 
 533         GetEventHandler()->ProcessEvent(changing
); 
 535         if(changing
.IsAllowed()) 
 537             wxNotebookEvent 
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
, m_windowId
, 
 538                 newSel
, m_nSelection
); 
 539             event
.SetEventObject(this); 
 541             GetEventHandler()->ProcessEvent(event
); 
 545             m_peer
->SetValue( m_nSelection 
+ 1 ) ;