1 /////////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     implementation of wxNotebook 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  19 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  20 #pragma implementation "notebook.h" 
  24 #pragma message disable unscomzer 
  27 // For compilers that support precompilation, includes "wx.h". 
  28 #include "wx/wxprec.h" 
  34 #include  "wx/string.h" 
  36 #include  "wx/settings.h" 
  37 #include  "wx/generic/imaglist.h" 
  38 #include  "wx/notebook.h" 
  39 #include  "wx/dcclient.h" 
  40 #include  "wx/generic/tabg.h" 
  42 // ---------------------------------------------------------------------------- 
  44 // ---------------------------------------------------------------------------- 
  46 // check that the page index is valid 
  47 #define IS_VALID_PAGE(nPage) (((nPage) >= 0) && ((nPage) < GetPageCount())) 
  49 // ---------------------------------------------------------------------------- 
  51 // ---------------------------------------------------------------------------- 
  53 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
) 
  54 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
) 
  56 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
) 
  57     EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange
) 
  58     EVT_SIZE(wxNotebook::OnSize
) 
  59     EVT_PAINT(wxNotebook::OnPaint
) 
  60     EVT_MOUSE_EVENTS(wxNotebook::OnMouseEvent
) 
  61     EVT_SET_FOCUS(wxNotebook::OnSetFocus
) 
  62     EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
) 
  65 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
) 
  66 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxCommandEvent
) 
  68 // ============================================================================ 
  70 // ============================================================================ 
  72 // ============================================================================ 
  74 // ============================================================================ 
  76 // This reuses wxTabView to draw the tabs. 
  77 class WXDLLEXPORT wxNotebookTabView
: public wxTabView
 
  79 DECLARE_DYNAMIC_CLASS(wxNotebookTabView
) 
  81   wxNotebookTabView(wxNotebook
* notebook
, long style 
= wxTAB_STYLE_DRAW_BOX 
| wxTAB_STYLE_COLOUR_INTERIOR
); 
  82   ~wxNotebookTabView(void); 
  84   // Called when a tab is activated 
  85   virtual void OnTabActivate(int activateId
, int deactivateId
); 
  87   virtual bool OnTabPreActivate(int activateId
, int deactivateId
); 
  90    wxNotebook
*      m_notebook
; 
  93 // ---------------------------------------------------------------------------- 
  94 // wxNotebook construction 
  95 // ---------------------------------------------------------------------------- 
  97 // common part of all ctors 
  98 void wxNotebook::Init() 
 100     m_tabView 
= (wxNotebookTabView
*) NULL
; 
 104 // default for dynamic class 
 105 wxNotebook::wxNotebook() 
 110 // the same arguments as for wxControl 
 111 wxNotebook::wxNotebook(wxWindow 
*parent
, 
 116                        const wxString
& name
) 
 120     Create(parent
, id
, pos
, size
, style
, name
); 
 124 bool wxNotebook::Create(wxWindow 
*parent
, 
 129                         const wxString
& name
) 
 134     m_windowId 
= id 
== -1 ? NewControlId() : id
; 
 136     // It's like a normal window... 
 137     if (!wxWindow::Create(parent
, id
, pos
, size
, style
|wxNO_BORDER
, name
)) 
 140     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
)); 
 142     SetTabView(new wxNotebookTabView(this)); 
 148 wxNotebook::~wxNotebook() 
 153 // ---------------------------------------------------------------------------- 
 154 // wxNotebook accessors 
 155 // ---------------------------------------------------------------------------- 
 156 int wxNotebook::GetRowCount() const 
 162 int wxNotebook::SetSelection(size_t nPage
) 
 164     wxASSERT( IS_VALID_PAGE(nPage
) ); 
 166 #if defined (__WIN16__) 
 167     m_tabView
->SetTabSelection(nPage
); 
 169     wxNotebookPage
* pPage 
= GetPage(nPage
); 
 171     m_tabView
->SetTabSelection((int) (long) pPage
); 
 178 void wxNotebook::AdvanceSelection(bool bForward
) 
 180     int nSel 
= GetSelection(); 
 181     int nMax 
= GetPageCount() - 1; 
 183         SetSelection(nSel 
== nMax 
? 0 : nSel 
+ 1); 
 185         SetSelection(nSel 
== 0 ? nMax 
: nSel 
- 1); 
 189 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
) 
 191     wxASSERT( IS_VALID_PAGE(nPage
) ); 
 192 #if defined (__WIN16__) 
 193         m_tabView
->SetTabText(nPage
, strText
); 
 197     wxNotebookPage
* page 
= GetPage(nPage
); 
 200         m_tabView
->SetTabText((int) (long) page
, strText
); 
 208 wxString 
wxNotebook::GetPageText(size_t nPage
) const 
 210     wxASSERT( IS_VALID_PAGE(nPage
) ); 
 212 #if defined (__WIN16__) 
 213     return m_tabView
->GetTabText(nPage
); 
 215     wxNotebookPage
* page 
= ((wxNotebook
*)this)->GetPage(nPage
); 
 217         return m_tabView
->GetTabText((int) (long) page
); 
 219         return wxEmptyString
; 
 223 int wxNotebook::GetPageImage(size_t nPage
) const 
 225     wxASSERT( IS_VALID_PAGE(nPage
) ); 
 231 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
) 
 233     wxASSERT( IS_VALID_PAGE(nPage
) ); 
 239 // set the size (the same for all pages) 
 240 void wxNotebook::SetPageSize(const wxSize
& size
) 
 245 // set the padding between tabs (in pixels) 
 246 void wxNotebook::SetPadding(const wxSize
& padding
) 
 251 // set the size of the tabs for wxNB_FIXEDWIDTH controls 
 252 void wxNotebook::SetTabSize(const wxSize
& sz
) 
 257 // ---------------------------------------------------------------------------- 
 258 // wxNotebook operations 
 259 // ---------------------------------------------------------------------------- 
 261 // remove one page from the notebook and delete it 
 262 bool wxNotebook::DeletePage(size_t nPage
) 
 264     wxCHECK( IS_VALID_PAGE(nPage
), FALSE 
); 
 266     if (m_nSelection 
!= -1) 
 268         m_pages
[m_nSelection
]->Show(FALSE
); 
 269         m_pages
[m_nSelection
]->Lower(); 
 272     wxNotebookPage
* pPage 
= GetPage(nPage
); 
 273 #if defined (__WIN16__) 
 274     m_tabView
->RemoveTab(nPage
); 
 276     m_tabView
->RemoveTab((int) (long) pPage
); 
 279     m_pages
.Remove(pPage
); 
 282     if (m_pages
.GetCount() == 0) 
 285       m_tabView
->SetTabSelection(-1, FALSE
); 
 287     else if (m_nSelection 
> -1) 
 290 #if defined (__WIN16__) 
 291       m_tabView
->SetTabSelection(0, FALSE
); 
 293       m_tabView
->SetTabSelection((int) (long) GetPage(0), FALSE
); 
 295       if (m_nSelection 
!= 0) 
 299     RefreshLayout(FALSE
); 
 304 bool wxNotebook::DeletePage(wxNotebookPage
* page
) 
 306     int pagePos 
= FindPagePosition(page
); 
 308         return DeletePage(pagePos
); 
 313 bool wxNotebook::RemovePage(size_t nPage
) 
 315     return DoRemovePage(nPage
) != NULL
; 
 318 // remove one page from the notebook 
 319 wxWindow
* wxNotebook::DoRemovePage(size_t nPage
) 
 321     wxCHECK( IS_VALID_PAGE(nPage
), FALSE 
); 
 323     m_pages
[nPage
]->Show(FALSE
); 
 324     //    m_pages[nPage]->Lower(); 
 326     wxNotebookPage
* pPage 
= GetPage(nPage
); 
 327 #if defined (__WIN16__) 
 328     m_tabView
->RemoveTab(nPage
); 
 330     m_tabView
->RemoveTab((int) (long) pPage
); 
 333     m_pages
.Remove(pPage
); 
 335     if (m_pages
.GetCount() == 0) 
 338       m_tabView
->SetTabSelection(-1, TRUE
); 
 340     else if (m_nSelection 
> -1) 
 342       // Only change the selection if the page we 
 343       // deleted was the selection. 
 344       if (nPage 
== (size_t)m_nSelection
) 
 347          // Select the first tab. Generates a ChangePage. 
 348          m_tabView
->SetTabSelection(0, TRUE
); 
 352         // We must adjust which tab we think is selected. 
 353         // If greater than the page we deleted, it must be moved down 
 355         if (size_t(m_nSelection
) > nPage
) 
 360     RefreshLayout(FALSE
); 
 365 bool wxNotebook::RemovePage(wxNotebookPage
* page
) 
 367     int pagePos 
= FindPagePosition(page
); 
 369         return RemovePage(pagePos
); 
 374 // Find the position of the wxNotebookPage, -1 if not found. 
 375 int wxNotebook::FindPagePosition(wxNotebookPage
* page
) const 
 377     size_t nPageCount 
= GetPageCount(); 
 379     for ( nPage 
= 0; nPage 
< nPageCount
; nPage
++ ) 
 380         if (m_pages
[nPage
] == page
) 
 386 bool wxNotebook::DeleteAllPages() 
 388     m_tabView
->ClearTabs(TRUE
); 
 390     size_t nPageCount 
= GetPageCount(); 
 392     for ( nPage 
= 0; nPage 
< nPageCount
; nPage
++ ) 
 393         delete m_pages
[nPage
]; 
 400 // same as AddPage() but does it at given position 
 401 bool wxNotebook::InsertPage(size_t nPage
, 
 402                             wxNotebookPage 
*pPage
, 
 403                             const wxString
& strText
, 
 407     wxASSERT( pPage 
!= NULL 
); 
 408     wxCHECK( IS_VALID_PAGE(nPage
) || nPage 
== GetPageCount(), FALSE 
); 
 410 // For 16 bit integers (tabs limited to 32768) 
 411 #if defined (__WIN16__) 
 412     m_tabView
->AddTab(nPage
, strText
); 
 414     m_tabView
->AddTab((int) (long) pPage
, strText
); 
 419     // save the pointer to the page 
 420     m_pages
.Insert(pPage
, nPage
); 
 424         // This will cause ChangePage to be called, via OnSelPage 
 425 #if defined (__WIN16__) 
 426         m_tabView
->SetTabSelection(nPage
, TRUE
); 
 428         m_tabView
->SetTabSelection((int) (long) pPage
, TRUE
); 
 432     // some page must be selected: either this one or the first one if there is 
 433     // still no selection 
 434     if ( m_nSelection 
== -1 ) 
 437     RefreshLayout(FALSE
); 
 442 // ---------------------------------------------------------------------------- 
 443 // wxNotebook callbacks 
 444 // ---------------------------------------------------------------------------- 
 446 // @@@ OnSize() is used for setting the font when it's called for the first 
 447 //     time because doing it in ::Create() doesn't work (for unknown reasons) 
 448 void wxNotebook::OnSize(wxSizeEvent
& event
) 
 450     static bool s_bFirstTime 
= TRUE
; 
 451     if ( s_bFirstTime 
) { 
 452         // TODO: any first-time-size processing. 
 453         s_bFirstTime 
= FALSE
; 
 458     // Processing continues to next OnSize 
 462 // This was supposed to cure the non-display of the notebook 
 463 // until the user resizes the window. 
 465 void wxNotebook::OnInternalIdle() 
 467     wxWindow::OnInternalIdle(); 
 470     static bool s_bFirstTime 
= TRUE
; 
 471     if ( s_bFirstTime 
) { 
 473       wxSize sz(GetSize()); 
 481       wxSize sz(GetSize()); 
 482       wxSizeEvent sizeEvent(sz, GetId()); 
 483       sizeEvent.SetEventObject(this); 
 484       GetEventHandler()->ProcessEvent(sizeEvent); 
 487       s_bFirstTime 
= FALSE
; 
 492 // Implementation: calculate the layout of the view rect 
 493 // and resize the children if required 
 494 bool wxNotebook::RefreshLayout(bool force
) 
 498         wxRect oldRect 
= m_tabView
->GetViewRect(); 
 501         GetClientSize(& cw
, & ch
); 
 503         int tabHeight 
= m_tabView
->GetTotalTabHeight(); 
 506         rect
.y 
= tabHeight 
+ 4; 
 508         rect
.height 
= ch 
- 4 - rect
.y 
; 
 510         m_tabView
->SetViewRect(rect
); 
 512         m_tabView
->LayoutTabs(); 
 514         // Need to do it a 2nd time to get the tab height with 
 515         // the new view width, since changing the view width changes the 
 517         tabHeight 
= m_tabView
->GetTotalTabHeight(); 
 519         rect
.y 
= tabHeight 
+ 4; 
 521         rect
.height 
= ch 
- 4 - rect
.y 
; 
 523         m_tabView
->SetViewRect(rect
); 
 525         m_tabView
->LayoutTabs(); 
 527         if (!force 
&& (rect 
== oldRect
)) 
 530         // fit the notebook page to the tab control's display area 
 532         size_t nCount 
= m_pages
.Count(); 
 533         for ( size_t nPage 
= 0; nPage 
< nCount
; nPage
++ ) { 
 534             wxNotebookPage 
*pPage 
= m_pages
[nPage
]; 
 535             wxRect clientRect 
= GetAvailableClientSize(); 
 536             if (pPage
->IsShown()) 
 538                 pPage
->SetSize(clientRect
.x
, clientRect
.y
, clientRect
.width
, clientRect
.height
); 
 539                 if ( pPage
->GetAutoLayout() ) 
 548 void wxNotebook::OnSelChange(wxNotebookEvent
& event
) 
 550     // is it our tab control? 
 551     if ( event
.GetEventObject() == this ) 
 553         if (event
.GetSelection() != m_nSelection
) 
 554           ChangePage(event
.GetOldSelection(), event
.GetSelection()); 
 557     // we want to give others a chance to process this message as well 
 561 void wxNotebook::OnSetFocus(wxFocusEvent
& event
) 
 563     // set focus to the currently selected page if any 
 564     if ( m_nSelection 
!= -1 ) 
 565         m_pages
[m_nSelection
]->SetFocus(); 
 570 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
) 
 572     if ( event
.IsWindowChange() ) { 
 574         AdvanceSelection(event
.GetDirection()); 
 577         // pass to the parent 
 579             event
.SetCurrentFocus(this); 
 580             GetParent()->ProcessEvent(event
); 
 585 // ---------------------------------------------------------------------------- 
 586 // wxNotebook base class virtuals 
 587 // ---------------------------------------------------------------------------- 
 589 // override these 2 functions to do nothing: everything is done in OnSize 
 591 void wxNotebook::SetConstraintSizes(bool /* recurse */) 
 593     // don't set the sizes of the pages - their correct size is not yet known 
 594     wxControl::SetConstraintSizes(FALSE
); 
 597 bool wxNotebook::DoPhase(int /* nPhase */) 
 602 void wxNotebook::Command(wxCommandEvent
& WXUNUSED(event
)) 
 604     wxFAIL_MSG("wxNotebook::Command not implemented"); 
 607 // ---------------------------------------------------------------------------- 
 608 // wxNotebook helper functions 
 609 // ---------------------------------------------------------------------------- 
 611 // hide the currently active panel and show the new one 
 612 void wxNotebook::ChangePage(int nOldSel
, int nSel
) 
 614   //  cout << "ChangePage: " << nOldSel << ", " << nSel << "\n"; 
 615     wxASSERT( nOldSel 
!= nSel 
); // impossible 
 617     if ( nOldSel 
!= -1 ) { 
 618         m_pages
[nOldSel
]->Show(FALSE
); 
 619         m_pages
[nOldSel
]->Lower(); 
 622     wxNotebookPage 
*pPage 
= m_pages
[nSel
]; 
 624     wxRect clientRect 
= GetAvailableClientSize(); 
 625     pPage
->SetSize(clientRect
.x
, clientRect
.y
, clientRect
.width
, clientRect
.height
); 
 636 void wxNotebook::OnMouseEvent(wxMouseEvent
& event
) 
 639     m_tabView
->OnEvent(event
); 
 642 void wxNotebook::OnPaint(wxPaintEvent
& WXUNUSED(event
) ) 
 649 wxRect 
wxNotebook::GetAvailableClientSize() 
 652     GetClientSize(& cw
, & ch
); 
 654     int tabHeight 
= m_tabView
->GetTotalTabHeight(); 
 656     // TODO: these margins should be configurable. 
 659     rect
.y 
= tabHeight 
+ 6; 
 660     rect
.width 
= cw 
- 12; 
 661     rect
.height 
= ch 
- 4 - rect
.y 
; 
 670 IMPLEMENT_CLASS(wxNotebookTabView
, wxTabView
) 
 672 wxNotebookTabView::wxNotebookTabView(wxNotebook 
*notebook
, long style
): wxTabView(style
) 
 674   m_notebook 
= notebook
; 
 676   m_notebook
->SetTabView(this); 
 678   SetWindow(m_notebook
); 
 681 wxNotebookTabView::~wxNotebookTabView(void) 
 685 // Called when a tab is activated 
 686 void wxNotebookTabView::OnTabActivate(int activateId
, int deactivateId
) 
 691   wxNotebookEvent 
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
, m_notebook
->GetId()); 
 693 #if defined (__WIN16__) 
 694   int activatePos 
= activateId
; 
 695   int deactivatePos 
= deactivateId
; 
 697   // Translate from wxTabView's ids (which aren't position-dependent) 
 698   // to wxNotebook's (which are). 
 699   wxNotebookPage
* pActive 
= (wxNotebookPage
*) activateId
; 
 700   wxNotebookPage
* pDeactive 
= (wxNotebookPage
*) deactivateId
; 
 702   int activatePos 
= m_notebook
->FindPagePosition(pActive
); 
 703   int deactivatePos 
= m_notebook
->FindPagePosition(pDeactive
); 
 706   event
.SetEventObject(m_notebook
); 
 707   event
.SetSelection(activatePos
); 
 708   event
.SetOldSelection(deactivatePos
); 
 709   m_notebook
->GetEventHandler()->ProcessEvent(event
); 
 713 bool wxNotebookTabView::OnTabPreActivate(int activateId
, int deactivateId
) 
 719     wxNotebookEvent 
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, m_notebook
->GetId()); 
 721 #if defined (__WIN16__) 
 722     int activatePos 
= activateId
; 
 723     int deactivatePos 
= deactivateId
; 
 725     // Translate from wxTabView's ids (which aren't position-dependent) 
 726     // to wxNotebook's (which are). 
 727     wxNotebookPage
* pActive 
= (wxNotebookPage
*) activateId
; 
 728     wxNotebookPage
* pDeactive 
= (wxNotebookPage
*) deactivateId
; 
 730     int activatePos 
= m_notebook
->FindPagePosition(pActive
); 
 731     int deactivatePos 
= m_notebook
->FindPagePosition(pDeactive
); 
 734     event
.SetEventObject(m_notebook
); 
 735     event
.SetSelection(activatePos
); 
 736     event
.SetOldSelection(deactivatePos
); 
 737     if (m_notebook
->GetEventHandler()->ProcessEvent(event
)) 
 739       retval 
= event
.IsAllowed();