1 /////////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     implementation of wxNotebook 
   4 // Author:      David Webster 
   8 // Copyright:   (c) David Webster 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  20   #include "wx/dcclient.h" 
  21   #include "wx/string.h" 
  22   #include "wx/settings.h" 
  26 #include  "wx/imaglist.h" 
  28 #include  "wx/control.h" 
  29 #include  "wx/notebook.h" 
  31 #include  "wx/os2/private.h" 
  33 // ---------------------------------------------------------------------------- 
  35 // ---------------------------------------------------------------------------- 
  37 // check that the page index is valid 
  38 #define IS_VALID_PAGE(nPage) (((nPage) >= 0) && ((nPage) < GetPageCount())) 
  41 #define m_hWnd    (HWND)GetHWND() 
  43 // ---------------------------------------------------------------------------- 
  45 // ---------------------------------------------------------------------------- 
  47 // ---------------------------------------------------------------------------- 
  49 // ---------------------------------------------------------------------------- 
  51 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
) 
  52 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
) 
  54 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
) 
  55     EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange
) 
  56     EVT_SIZE(wxNotebook::OnSize
) 
  57     EVT_SET_FOCUS(wxNotebook::OnSetFocus
) 
  58     EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
) 
  61 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
) 
  62 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxNotifyEvent
) 
  64 // ============================================================================ 
  66 // ============================================================================ 
  68 // ---------------------------------------------------------------------------- 
  69 // wxNotebook construction 
  70 // ---------------------------------------------------------------------------- 
  73 // Common part of all ctors 
  75 void wxNotebook::Init() 
  80 } // end of wxNotebook::Init 
  83 // Default for dynamic class 
  85 wxNotebook::wxNotebook() 
  88 } // end of wxNotebook::wxNotebook 
  91 // The same arguments as for wxControl 
  93 wxNotebook::wxNotebook( 
  99 , const wxString
&                   rsName
 
 110 } // end of wxNotebook::wxNotebook 
 115 bool wxNotebook::Create( 
 118 , const wxPoint
&                    rPos
 
 119 , const wxSize
&                     rSize
 
 121 , const wxString
&                   rsName
 
 127     if (!CreateControl( pParent
 
 138     // Notebook, so explicitly specify 0 as last parameter 
 140     if (!OS2CreateControl( "NOTEBOOK" 
 144                           ,lStyle 
| wxTAB_TRAVERSAL
 
 148     SetBackgroundColour(wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))); 
 150 } // end of wxNotebook::Create 
 152 WXDWORD 
wxNotebook::OS2GetStyle ( 
 154 , WXDWORD
*                          pdwExstyle
 
 157     WXDWORD                         dwTabStyle 
= wxControl::OS2GetStyle( lStyle
 
 161     dwTabStyle 
|= WS_TABSTOP 
| BKS_SOLIDBIND 
| BKS_ROUNDEDTABS 
| BKS_TABTEXTCENTER
; 
 163     if (lStyle 
& wxNB_BOTTOM
) 
 164         dwTabStyle 
|= BKS_MAJORTABBOTTOM 
| BKS_BACKPAGESBL
; 
 165     else if (lStyle 
& wxNB_RIGHT
) 
 166         dwTabStyle 
|= BKS_MAJORTABRIGHT 
| BKS_BACKPAGESBR
; 
 167     else if (lStyle 
& wxNB_LEFT
) 
 168         dwTabStyle 
|= BKS_MAJORTABLEFT 
| BKS_BACKPAGESTL
; 
 169     else // default to top 
 170         dwTabStyle 
|= BKS_MAJORTABTOP 
| BKS_BACKPAGESTR
; 
 178         // Note that we never want to have the default WS_EX_CLIENTEDGE style 
 179         // as it looks too ugly for the notebooks 
 184 } // end of wxNotebook::OS2GetStyle 
 186 // ---------------------------------------------------------------------------- 
 187 // wxNotebook accessors 
 188 // ---------------------------------------------------------------------------- 
 190 size_t wxNotebook::GetPageCount() const 
 192     int                             nPageInternal 
= m_pages
.Count(); 
 193     int                             nPageAPI 
= (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT
, (MPARAM
)0, (MPARAM
)BKA_END
); 
 198     wxASSERT((int)m_pages
.Count() == (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT
, (MPARAM
)0, (MPARAM
)BKA_END
)); 
 199     return m_pages
.Count(); 
 200 } // end of wxNotebook::GetPageCount 
 202 int wxNotebook::GetRowCount() const 
 204     return (int)::WinSendMsg( GetHWND() 
 209 } // end of wxNotebook::GetRowCount 
 211 int wxNotebook::SetSelection( 
 215     wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") ); 
 217     if (nPage 
!= m_nSelection
) 
 219         wxNotebookEvent             
vEvent( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
 
 223         vEvent
.SetSelection(nPage
); 
 224         vEvent
.SetOldSelection(m_nSelection
); 
 225         vEvent
.SetEventObject(this); 
 226         if (!GetEventHandler()->ProcessEvent(vEvent
) || vEvent
.IsAllowed()) 
 230             // Program allows the page change 
 232             vEvent
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
); 
 233             GetEventHandler()->ProcessEvent(vEvent
); 
 235             ULONG                   ulPageId 
= (ULONG
)m_alPageId
[nPage
]; 
 237             ::WinSendMsg( GetHWND() 
 239                          ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 244     m_nSelection 
= nPage
; 
 246 } // end of wxNotebook::SetSelection 
 248 bool wxNotebook::SetPageText( 
 250 , const wxString
&                   rsStrText
 
 253     wxCHECK_MSG( IS_VALID_PAGE(nPage
), FALSE
, wxT("notebook page out of range") ); 
 256     ULONG                           ulPageId 
= (ULONG
)m_alPageId
[nPage
]; 
 258     return (bool)::WinSendMsg( m_hWnd
 
 260                               ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 261                               ,MPFROMP((PSZ
)rsStrText
.c_str()) 
 263 } // end of wxNotebook::SetPageText 
 265 wxString 
wxNotebook::GetPageText ( 
 274     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxT(""), wxT("notebook page out of range") ); 
 277     ULONG                           ulPageId 
= (ULONG
)m_alPageId
[nPage
]; 
 279     memset(&vBookText
, '\0', sizeof(BOOKTEXT
)); 
 280     vBookText
.textLen 
= 0; // This will get the length 
 281     ulRc 
= LONGFROMMR(::WinSendMsg( m_hWnd
 
 283                                    ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 286     if (ulRc 
== BOOKERR_INVALID_PARAMETERS 
|| ulRc 
== 0L) 
 288         if (ulRc 
== BOOKERR_INVALID_PARAMETERS
) 
 290             wxLogError(wxT("Invalid Page Id for page text querry.")); 
 292         return wxEmptyString
; 
 294     vBookText
.textLen 
= ulRc 
+ 1; // To get the null terminator 
 295     vBookText
.pString 
= zBuf
; 
 298     // Now get the actual text 
 300     ulRc 
= LONGFROMMR(::WinSendMsg( m_hWnd
 
 302                                    ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 305     if (ulRc 
== BOOKERR_INVALID_PARAMETERS 
|| ulRc 
== 0L) 
 307         return wxEmptyString
; 
 312     vBookText
.pString
[ulRc
] = '\0'; 
 313     sStr 
= vBookText
.pString
; 
 315 } // end of wxNotebook::GetPageText 
 317 int wxNotebook::GetPageImage ( 
 321     wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") ); 
 324     // For OS/2 just return the page 
 327 } // end of wxNotebook::GetPageImage 
 329 bool wxNotebook::SetPageImage ( 
 334     wxBitmap
*                       pBitmap 
= (wxBitmap
*)m_imageList
->GetBitmap(nImage
); 
 337     ULONG                           ulPageId 
= (ULONG
)m_alPageId
[nPage
]; 
 339     return (bool)::WinSendMsg( GetHWND() 
 341                               ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 342                               ,(MPARAM
)pBitmap
->GetHBITMAP() 
 344 } // end of wxNotebook::SetPageImage 
 346 void wxNotebook::SetImageList ( 
 347   wxImageList
*                      WXUNUSED(pImageList
) 
 351     // Does nothing under OS/2 
 353 } // end of wxNotebook::SetImageList 
 355 // ---------------------------------------------------------------------------- 
 356 // wxNotebook size settings 
 357 // ---------------------------------------------------------------------------- 
 358 void wxNotebook::SetPageSize ( 
 365     // Transform the page size into the notebook size 
 367     vRect
.xLeft   
= vRect
.yTop 
= 0; 
 368     vRect
.xRight  
= rSize
.x
; 
 369     vRect
.yBottom 
= rSize
.y
; 
 375     SetSize( vRect
.xRight 
- vRect
.xLeft
 
 376             ,vRect
.yBottom 
- vRect
.yTop
 
 378 } // end of wxNotebook::SetPageSize 
 380 void wxNotebook::SetPadding ( 
 381   const wxSize
&                     WXUNUSED(rPadding
) 
 385     // No padding in OS/2 
 387 } // end of wxNotebook::SetPadding 
 389 void wxNotebook::SetTabSize ( 
 393     ::WinSendMsg( GetHWND() 
 395                  ,MPFROM2SHORT( (USHORT
)rSize
.x
 
 398                  ,(MPARAM
)BKA_MAJORTAB
 
 400 } // end of wxNotebook::SetTabSize 
 402 // ---------------------------------------------------------------------------- 
 403 // wxNotebook operations 
 404 // ---------------------------------------------------------------------------- 
 407 // Remove one page from the notebook, without deleting 
 409 wxNotebookPage
* wxNotebook::DoRemovePage ( 
 413     wxNotebookPage
*                 pPageRemoved 
= wxNotebookBase::DoRemovePage(nPage
); 
 419     ULONG                           ulPageId 
= (ULONG
)m_alPageId
[nPage
]; 
 421     ::WinSendMsg( GetHWND() 
 423                  ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 426     if (m_pages
.IsEmpty()) 
 429         // No selection any more, the notebook becamse empty 
 433     else // notebook still not empty 
 436         // Change the selected page if it was deleted or became invalid 
 440         if (m_nSelection 
== GetPageCount()) 
 443             // Last page deleted, make the new last page the new selection 
 445             nSelNew 
= m_nSelection 
- 1; 
 447         else if (nPage 
<= m_nSelection
) 
 450             // We must show another page, even if it has the same index 
 452             nSelNew 
= m_nSelection
; 
 454         else // nothing changes for the currently selected page 
 459             // We still must refresh the current page: this needs to be done 
 460             // for some unknown reason if the tab control shows the up-down 
 461             // control (i.e. when there are too many pages) -- otherwise after 
 462             // deleting a page nothing at all is shown 
 464             m_pages
[m_nSelection
]->Refresh(); 
 470             // m_nSelection must be always valid so reset it before calling 
 474             SetSelection(nSelNew
); 
 478 } // end of wxNotebook::DoRemovePage 
 483 bool wxNotebook::DeleteAllPages() 
 485     int                             nPageCount 
= GetPageCount(); 
 488     for (nPage 
= 0; nPage 
< nPageCount
; nPage
++) 
 489         delete m_pages
[nPage
]; 
 491     ::WinSendMsg( GetHWND() 
 498 } // end of wxNotebook::DeleteAllPages 
 501 // Add a page to the notebook 
 503 bool wxNotebook::AddPage ( 
 504   wxNotebookPage
*                   pPage
 
 505 , const wxString
&                   rStrText
 
 510     return InsertPage( GetPageCount() 
 516 } // end of wxNotebook::AddPage 
 519 // Same as AddPage() but does it at given position 
 521 bool wxNotebook::InsertPage ( 
 523 , wxNotebookPage
*                   pPage
 
 524 , const wxString
&                   rsStrText
 
 531     wxASSERT( pPage 
!= NULL 
); 
 532     wxCHECK( IS_VALID_PAGE(nPage
) || nPage 
== GetPageCount(), FALSE 
); 
 535     // Under OS/2 we can only insert FIRST, LAST, NEXT or PREV.  Requires 
 536     // two different calls to the API.  Page 1 uses the BKA_FIRST.  Subsequent 
 537     // pages use the previous page ID coupled with a BKA_NEXT call.  Unlike 
 538     // Windows, OS/2 uses an internal Page ID to ID the pages. 
 540     // OS/2 also has a nice auto-size feature that automatically sizes the 
 541     // the attached window so we don't have to worry about the size of the 
 542     // window on the page. 
 546         ulApiPage 
= LONGFROMMR(::WinSendMsg( GetHWND() 
 549                                             ,MPFROM2SHORT(BKA_AUTOPAGESIZE 
| BKA_MAJOR
, BKA_FIRST
) 
 556             vError 
= ::WinGetLastError(vHabmain
); 
 557             sError 
= wxPMErrorToStr(vError
); 
 560         m_alPageId
.Insert((long)ulApiPage
, nPage
); 
 564         ulApiPage 
= LONGFROMMR(::WinSendMsg( GetHWND() 
 566                                             ,MPFROMLONG((ULONG
)m_alPageId
[nPage 
- 1]) 
 567                                             ,MPFROM2SHORT(BKA_AUTOPAGESIZE 
| BKA_MAJOR
, BKA_NEXT
) 
 574             vError 
= ::WinGetLastError(vHabmain
); 
 575             sError 
= wxPMErrorToStr(vError
); 
 578         m_alPageId
.Insert((long)ulApiPage
, nPage
); 
 582     // Associate a window handle with the page 
 586         if (!::WinSendMsg( GetHWND() 
 587                           ,BKM_SETPAGEWINDOWHWND
 
 588                           ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 589                           ,MPFROMHWND(pPage
->GetHWND()) 
 594     // If the inserted page is before the selected one, we must update the 
 595     // index of the selected page 
 597     if (nPage 
<= m_nSelection
) 
 600         // One extra page added 
 608         // Save the pointer to the page 
 610         m_pages
.Insert( pPage
 
 616     // Now set TAB dimenstions 
 619     wxWindowDC                      
vDC(this); 
 623     vDC
.GetTextExtent(rsStrText
, &nTextX
, &nTextY
); 
 626     if (nTextX 
> m_nTabSize
) 
 629         ::WinSendMsg( GetHWND() 
 631                      ,MPFROM2SHORT((USHORT
)m_nTabSize
, (USHORT
)nTextY
) 
 632                      ,(MPARAM
)BKA_MAJORTAB
 
 636     // Now set any TAB text 
 638     if (!rsStrText
.IsEmpty()) 
 640         if (!SetPageText( nPage
 
 647     // Now set any TAB bitmap image 
 651         if (!SetPageImage( nPage
 
 660         // Don't show pages by default (we'll need to adjust their size first) 
 662         HWND                        hWnd 
= GetWinHwnd(pPage
); 
 664         WinSetWindowULong( hWnd
 
 666                           ,WinQueryWindowULong( hWnd
 
 672         // This updates internal flag too - otherwise it will get out of sync 
 678     // Some page should be selected: either this one or the first one if there is 
 679     // still no selection 
 685     else if ( m_nSelection 
== -1 ) 
 689         SetSelection(nSelNew
); 
 691 } // end of wxNotebook::InsertPage 
 693 // ---------------------------------------------------------------------------- 
 694 // wxNotebook callbacks 
 695 // ---------------------------------------------------------------------------- 
 696 void wxNotebook::OnSize( 
 701     int                             nCount 
= (int)m_pages
.Count(); 
 703     for (nPage 
= 0; nPage 
< nCount
; nPage
++) 
 705         if (m_nSelection 
== nPage
) 
 706             m_pages
[nPage
]->Refresh(); 
 708             ::WinSetWindowPos(m_pages
[nPage
]->GetHWND() 
 715 } // end of wxNotebook::OnSize 
 717 void wxNotebook::OnSelChange ( 
 718   wxNotebookEvent
&                  rEvent
 
 722     // Is it our tab control? 
 724     if (rEvent
.GetEventObject() == this) 
 726         int                         nPageCount 
= GetPageCount(); 
 728         ULONG                       ulOS2Sel 
= (ULONG
)rEvent
.GetOldSelection(); 
 731         for (nSel 
= 0; nSel 
< nPageCount
; nSel
++) 
 733             if (ulOS2Sel 
== m_alPageId
[nSel
]) 
 743         m_pages
[nSel
]->Show(FALSE
); 
 745         ulOS2Sel 
= (ULONG
)rEvent
.GetSelection(); 
 749         for (nSel 
= 0; nSel 
< nPageCount
; nSel
++) 
 751             if (ulOS2Sel 
== m_alPageId
[nSel
]) 
 761         wxNotebookPage
*         pPage 
= m_pages
[nSel
]; 
 768     // We want to give others a chance to process this message as well 
 771 } // end of wxNotebook::OnSelChange 
 773 void wxNotebook::OnSetFocus ( 
 778     // This function is only called when the focus is explicitly set (i.e. from 
 779     // the program) to the notebook - in this case we don't need the 
 780     // complicated OnNavigationKey() logic because the programmer knows better 
 783     // set focus to the currently selected page if any 
 785     if (m_nSelection 
!= -1) 
 786         m_pages
[m_nSelection
]->SetFocus(); 
 788 } // end of wxNotebook::OnSetFocus 
 790 void wxNotebook::OnNavigationKey ( 
 791   wxNavigationKeyEvent
&             rEvent
 
 794     if (rEvent
.IsWindowChange()) 
 799         AdvanceSelection(rEvent
.GetDirection()); 
 804         // We get this event in 2 cases 
 806         // a) one of our pages might have generated it because the user TABbed 
 807         // out from it in which case we should propagate the event upwards and 
 808         // our parent will take care of setting the focus to prev/next sibling 
 812         // b) the parent panel wants to give the focus to us so that we 
 813         // forward it to our selected page. We can't deal with this in 
 814         // OnSetFocus() because we don't know which direction the focus came 
 815         // from in this case and so can't choose between setting the focus to 
 816         // first or last panel child 
 818         wxWindow
*                   pParent 
= GetParent(); 
 820         if (rEvent
.GetEventObject() == pParent
) 
 823             // No, it doesn't come from child, case (b): forward to a page 
 825             if (m_nSelection 
!= -1) 
 828                 // So that the page knows that the event comes from it's parent 
 829                 // and is being propagated downwards 
 831                 rEvent
.SetEventObject(this); 
 833                 wxWindow
*           pPage 
= m_pages
[m_nSelection
]; 
 835                 if (!pPage
->GetEventHandler()->ProcessEvent(rEvent
)) 
 839                 //else: page manages focus inside it itself 
 844                 // We have no pages - still have to give focus to _something_ 
 852             // It comes from our child, case (a), pass to the parent 
 856                 rEvent
.SetCurrentFocus(this); 
 857                 pParent
->GetEventHandler()->ProcessEvent(rEvent
); 
 861 } // end of wxNotebook::OnNavigationKey 
 863 // ---------------------------------------------------------------------------- 
 864 // wxNotebook base class virtuals 
 865 // ---------------------------------------------------------------------------- 
 868 // Override these 2 functions to do nothing: everything is done in OnSize 
 870 void wxNotebook::SetConstraintSizes( 
 871   bool                              WXUNUSED(bRecurse
) 
 875     // Don't set the sizes of the pages - their correct size is not yet known 
 877     wxControl::SetConstraintSizes(FALSE
); 
 878 } // end of wxNotebook::SetConstraintSizes 
 880 bool wxNotebook::DoPhase ( 
 885 } // end of wxNotebook::DoPhase 
 887 // ---------------------------------------------------------------------------- 
 888 // wxNotebook Windows message handlers 
 889 // ---------------------------------------------------------------------------- 
 890 bool wxNotebook::OS2OnScroll ( 
 898     // Don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the 
 903     return wxNotebookBase::OS2OnScroll( nOrientation
 
 908 } // end of wxNotebook::OS2OnScroll 
 910 #endif // wxUSE_NOTEBOOK