1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/os2/notebook.cpp 
   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" 
  17 #include  "wx/notebook.h" 
  22     #include "wx/dcclient.h" 
  23     #include "wx/string.h" 
  24     #include "wx/settings.h" 
  27     #include  "wx/control.h" 
  30 #include  "wx/imaglist.h" 
  32 #include  "wx/os2/private.h" 
  34 // ---------------------------------------------------------------------------- 
  36 // ---------------------------------------------------------------------------- 
  38 // check that the page index is valid 
  39 #define IS_VALID_PAGE(nPage) (                                \ 
  40                                /* size_t is _always_ >= 0 */  \ 
  41                                /* ((nPage) >= 0) && */        \ 
  42                                ((nPage) < GetPageCount())     \ 
  46 #define m_hWnd    (HWND)GetHWND() 
  48 // ---------------------------------------------------------------------------- 
  50 // ---------------------------------------------------------------------------- 
  52 // ---------------------------------------------------------------------------- 
  54 // ---------------------------------------------------------------------------- 
  56 BEGIN_EVENT_TABLE(wxNotebook
, wxBookCtrlBase
) 
  57     EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY
, wxNotebook::OnSelChange
) 
  58     EVT_SIZE(wxNotebook::OnSize
) 
  59     EVT_SET_FOCUS(wxNotebook::OnSetFocus
) 
  60     EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
) 
  63 // ============================================================================ 
  65 // ============================================================================ 
  67 // ---------------------------------------------------------------------------- 
  68 // wxNotebook construction 
  69 // ---------------------------------------------------------------------------- 
  72 // Common part of all ctors 
  74 void wxNotebook::Init() 
  78 } // end of wxNotebook::Init 
  81 // Default for dynamic class 
  83 wxNotebook::wxNotebook() 
  86 } // end of wxNotebook::wxNotebook 
  89 // The same arguments as for wxControl 
  91 wxNotebook::wxNotebook( 
  97 , const wxString
&                   rsName
 
 108 } // end of wxNotebook::wxNotebook 
 113 bool wxNotebook::Create( wxWindow
*       pParent
, 
 118                          const wxString
& rsName 
) 
 120     if ( (lStyle 
& wxBK_ALIGN_MASK
) == wxBK_DEFAULT 
) 
 125     if (!CreateControl( pParent
 
 136     // Notebook, so explicitly specify 0 as last parameter 
 138     if (!OS2CreateControl( wxT("NOTEBOOK") 
 142                           ,lStyle 
| wxTAB_TRAVERSAL
 
 146     SetBackgroundColour(wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))); 
 148 } // end of wxNotebook::Create 
 150 WXDWORD 
wxNotebook::OS2GetStyle ( 
 152 , WXDWORD
*                          pdwExstyle
 
 155     WXDWORD                         dwTabStyle 
= wxControl::OS2GetStyle( lStyle
 
 159     dwTabStyle 
|= WS_TABSTOP 
| BKS_SOLIDBIND 
| BKS_ROUNDEDTABS 
| BKS_TABTEXTCENTER 
| BKS_TABBEDDIALOG
; 
 161     if (lStyle 
& wxBK_BOTTOM
) 
 162         dwTabStyle 
|= BKS_MAJORTABBOTTOM 
| BKS_BACKPAGESBL
; 
 163     else if (lStyle 
& wxBK_RIGHT
) 
 164         dwTabStyle 
|= BKS_MAJORTABRIGHT 
| BKS_BACKPAGESBR
; 
 165     else if (lStyle 
& wxBK_LEFT
) 
 166         dwTabStyle 
|= BKS_MAJORTABLEFT 
| BKS_BACKPAGESTL
; 
 167     else // default to top 
 168         dwTabStyle 
|= BKS_MAJORTABTOP 
| BKS_BACKPAGESTR
; 
 176         // Note that we never want to have the default WS_EX_CLIENTEDGE style 
 177         // as it looks too ugly for the notebooks 
 182 } // end of wxNotebook::OS2GetStyle 
 184 // ---------------------------------------------------------------------------- 
 185 // wxNotebook accessors 
 186 // ---------------------------------------------------------------------------- 
 188 size_t wxNotebook::GetPageCount() const 
 193     wxASSERT((int)m_pages
.Count() == (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT
, (MPARAM
)0, (MPARAM
)BKA_END
)); 
 194     return m_pages
.Count(); 
 195 } // end of wxNotebook::GetPageCount 
 197 int wxNotebook::GetRowCount() const 
 199     return (int)::WinSendMsg( GetHWND() 
 204 } // end of wxNotebook::GetRowCount 
 206 int wxNotebook::SetSelection( size_t nPage 
) 
 208     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 210     if (nPage 
!= (size_t)m_selection
) 
 212         wxBookCtrlEvent             
vEvent( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
 
 216         vEvent
.SetSelection(nPage
); 
 217         vEvent
.SetOldSelection(m_selection
); 
 218         vEvent
.SetEventObject(this); 
 219         if (!HandleWindowEvent(vEvent
) || vEvent
.IsAllowed()) 
 223             // Program allows the page change 
 225             vEvent
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
); 
 226             HandleWindowEvent(vEvent
); 
 228             ::WinSendMsg( GetHWND() 
 230                          ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 237 } // end of wxNotebook::SetSelection 
 239 int wxNotebook::ChangeSelection( size_t nPage 
) 
 241     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 243     if (nPage 
!= (size_t)m_selection
) 
 245         ::WinSendMsg( GetHWND() 
 247                 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 255 bool wxNotebook::SetPageText( size_t nPage
, 
 256                               const wxString
& rsStrText 
) 
 258     wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") ); 
 259     return (bool)::WinSendMsg( m_hWnd
 
 261                               ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 262                               ,MPFROMP((const char*)rsStrText
.c_str()) 
 264 } // end of wxNotebook::SetPageText 
 266 wxString 
wxNotebook::GetPageText ( size_t nPage 
) const 
 273     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") ); 
 275     memset(&vBookText
, '\0', sizeof(BOOKTEXT
)); 
 276     vBookText
.textLen 
= 0; // This will get the length 
 277     ulRc 
= LONGFROMMR(::WinSendMsg( m_hWnd
 
 279                                    ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 282     if (ulRc 
== (ULONG
)BOOKERR_INVALID_PARAMETERS 
|| ulRc 
== 0L) 
 284         if (ulRc 
== (ULONG
)BOOKERR_INVALID_PARAMETERS
) 
 286             wxLogError(wxT("Invalid Page Id for page text querry.")); 
 288         return wxEmptyString
; 
 290     vBookText
.textLen 
= ulRc 
+ 1; // To get the null terminator 
 291     vBookText
.pString 
= (char*)zBuf
; 
 294     // Now get the actual text 
 296     ulRc 
= LONGFROMMR(::WinSendMsg( m_hWnd
 
 298                                    ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 301     if (ulRc 
== (ULONG
)BOOKERR_INVALID_PARAMETERS 
|| ulRc 
== 0L) 
 303         return wxEmptyString
; 
 308     vBookText
.pString
[ulRc
] = '\0'; 
 309     sStr 
= (wxChar
*)vBookText
.pString
; 
 311 } // end of wxNotebook::GetPageText 
 313 int wxNotebook::GetPageImage ( size_t nPage 
) const 
 315     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 318     // For OS/2 just return the page 
 321 } // end of wxNotebook::GetPageImage 
 323 bool wxNotebook::SetPageImage ( 
 328     wxBitmap                        vBitmap 
= (wxBitmap
)m_imageList
->GetBitmap(nImage
); 
 330     return (bool)::WinSendMsg( GetHWND() 
 332                               ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 333                               ,(MPARAM
)wxCopyBmp(vBitmap
.GetHBITMAP(), true) 
 335 } // end of wxNotebook::SetPageImage 
 337 void wxNotebook::SetImageList ( 
 338   wxImageList
*                      pImageList
 
 342     // Does not really do anything yet, but at least we need to 
 343     // update the base class. 
 345     wxNotebookBase::SetImageList(pImageList
); 
 346 } // end of wxNotebook::SetImageList 
 348 // ---------------------------------------------------------------------------- 
 349 // wxNotebook size settings 
 350 // ---------------------------------------------------------------------------- 
 351 void wxNotebook::SetPageSize ( 
 356 } // end of wxNotebook::SetPageSize 
 358 void wxNotebook::SetPadding ( 
 359   const wxSize
&                     WXUNUSED(rPadding
) 
 363     // No padding in OS/2 
 365 } // end of wxNotebook::SetPadding 
 367 void wxNotebook::SetTabSize ( 
 371     ::WinSendMsg( GetHWND() 
 373                  ,MPFROM2SHORT( (USHORT
)rSize
.x
 
 376                  ,(MPARAM
)BKA_MAJORTAB
 
 378 } // end of wxNotebook::SetTabSize 
 380 // ---------------------------------------------------------------------------- 
 381 // wxNotebook operations 
 382 // ---------------------------------------------------------------------------- 
 385 // Remove one page from the notebook, without deleting 
 387 wxNotebookPage
* wxNotebook::DoRemovePage ( size_t nPage 
) 
 389     wxNotebookPage
* pPageRemoved 
= wxNotebookBase::DoRemovePage(nPage
); 
 394     ::WinSendMsg( GetHWND() 
 396                  ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 399     if (m_pages
.IsEmpty()) 
 402         // No selection any more, the notebook becamse empty 
 404         m_selection 
= wxNOT_FOUND
; 
 406     else // notebook still not empty 
 409         // Change the selected page if it was deleted or became invalid 
 413         if (m_selection 
== (int)GetPageCount()) 
 416             // Last page deleted, make the new last page the new selection 
 418             nSelNew 
= m_selection 
- 1; 
 420         else if (nPage 
<= (size_t)m_selection
) 
 423             // We must show another page, even if it has the same index 
 425             nSelNew 
= m_selection
; 
 427         else // nothing changes for the currently selected page 
 429             nSelNew 
= wxNOT_FOUND
; 
 432             // We still must refresh the current page: this needs to be done 
 433             // for some unknown reason if the tab control shows the up-down 
 434             // control (i.e. when there are too many pages) -- otherwise after 
 435             // deleting a page nothing at all is shown 
 437             m_pages
[m_selection
]->Refresh(); 
 440         if (nSelNew 
!= wxNOT_FOUND
) 
 443             // m_selection must be always valid so reset it before calling 
 446             m_selection 
= wxNOT_FOUND
; 
 447             SetSelection(nSelNew
); 
 451 } // end of wxNotebook::DoRemovePage 
 456 bool wxNotebook::DeleteAllPages() 
 458     int                             nPageCount 
= GetPageCount(); 
 461     for (nPage 
= 0; nPage 
< nPageCount
; nPage
++) 
 462         delete m_pages
[nPage
]; 
 464     ::WinSendMsg( GetHWND() 
 469     m_selection 
= wxNOT_FOUND
; 
 472 } // end of wxNotebook::DeleteAllPages 
 475 // Add a page to the notebook 
 477 bool wxNotebook::AddPage ( 
 478   wxNotebookPage
*                   pPage
 
 479 , const wxString
&                   rStrText
 
 484     return InsertPage( GetPageCount() 
 490 } // end of wxNotebook::AddPage 
 493 // Same as AddPage() but does it at given position 
 495 bool wxNotebook::InsertPage ( size_t          nPage
, 
 496                               wxNotebookPage
* pPage
, 
 497                               const wxString
& rsStrText
, 
 503     wxASSERT( pPage 
!= NULL 
); 
 504     wxCHECK( IS_VALID_PAGE(nPage
) || nPage 
== GetPageCount(), false ); 
 507     // Under OS/2 we can only insert FIRST, LAST, NEXT or PREV.  Requires 
 508     // two different calls to the API.  Page 1 uses the BKA_FIRST.  Subsequent 
 509     // pages use the previous page ID coupled with a BKA_NEXT call.  Unlike 
 510     // Windows, OS/2 uses an internal Page ID to ID the pages. 
 512     // OS/2 also has a nice auto-size feature that automatically sizes the 
 513     // the attached window so we don't have to worry about the size of the 
 514     // window on the page. 
 518         ulApiPage 
= LONGFROMMR(::WinSendMsg( GetHWND() 
 521                                             ,MPFROM2SHORT(BKA_AUTOPAGESIZE 
| BKA_MAJOR
, BKA_FIRST
) 
 528             vError 
= ::WinGetLastError(vHabmain
); 
 529             sError 
= wxPMErrorToStr(vError
); 
 532         m_alPageId
.Insert((long)ulApiPage
, nPage
); 
 536         ulApiPage 
= LONGFROMMR(::WinSendMsg( GetHWND() 
 538                                             ,MPFROMLONG((ULONG
)m_alPageId
[nPage 
- 1]) 
 539                                             ,MPFROM2SHORT(BKA_AUTOPAGESIZE 
| BKA_MAJOR
, BKA_NEXT
) 
 546             vError 
= ::WinGetLastError(vHabmain
); 
 547             sError 
= wxPMErrorToStr(vError
); 
 550         m_alPageId
.Insert((long)ulApiPage
, nPage
); 
 554     // Associate a window handle with the page 
 558         if (!::WinSendMsg( GetHWND() 
 559                           ,BKM_SETPAGEWINDOWHWND
 
 560                           ,MPFROMLONG((ULONG
)m_alPageId
[nPage
]) 
 561                           ,MPFROMHWND(pPage
->GetHWND()) 
 566     // If the inserted page is before the selected one, we must update the 
 567     // index of the selected page 
 569     if (nPage 
<= (size_t)m_selection
) 
 572         // One extra page added 
 580         // Save the pointer to the page 
 582         m_pages
.Insert( pPage
 
 588     // Now set TAB dimenstions 
 591     wxWindowDC 
vDC(this); 
 595     vDC
.GetTextExtent(rsStrText
, &nTextX
, &nTextY
); 
 597     nTextX  
= (wxCoord
)(nTextX 
* 1.3); 
 598     if (nTextX 
> m_nTabSize
) 
 601         ::WinSendMsg( GetHWND() 
 603                      ,MPFROM2SHORT((USHORT
)m_nTabSize
, (USHORT
)nTextY
) 
 604                      ,(MPARAM
)BKA_MAJORTAB
 
 608     // Now set any TAB text 
 610     if (!rsStrText
.empty()) 
 612         if (!SetPageText( nPage
 
 619     // Now set any TAB bitmap image 
 623         if (!SetPageImage( nPage
 
 632         // Don't show pages by default (we'll need to adjust their size first) 
 634         HWND hWnd 
= GetWinHwnd(pPage
); 
 636         WinSetWindowULong( hWnd
 
 638                           ,WinQueryWindowULong( hWnd
 
 644         // This updates internal flag too - otherwise it will get out of sync 
 649     DoSetSelectionAfterInsertion(nPage
, bSelect
); 
 651     InvalidateBestSize(); 
 654 } // end of wxNotebook::InsertPage 
 656 // ---------------------------------------------------------------------------- 
 657 // wxNotebook callbacks 
 658 // ---------------------------------------------------------------------------- 
 659 void wxNotebook::OnSize( 
 664 } // end of wxNotebook::OnSize 
 666 void wxNotebook::OnSelChange ( 
 667   wxBookCtrlEvent
&                  rEvent
 
 671     // Is it our tab control? 
 673     if (rEvent
.GetEventObject() == this) 
 675         int   nPageCount 
= GetPageCount(); 
 677         ULONG ulOS2Sel 
= (ULONG
)rEvent
.GetOldSelection(); 
 680         for (nSel 
= 0; nSel 
< nPageCount
; nSel
++) 
 682             if (ulOS2Sel 
== (ULONG
)m_alPageId
[nSel
]) 
 692         m_pages
[nSel
]->Show(false); 
 694         ulOS2Sel 
= (ULONG
)rEvent
.GetSelection(); 
 698         for (nSel 
= 0; nSel 
< nPageCount
; nSel
++) 
 700             if (ulOS2Sel 
== (ULONG
)m_alPageId
[nSel
]) 
 710         wxNotebookPage
*         pPage 
= m_pages
[nSel
]; 
 717     // We want to give others a chance to process this message as well 
 720 } // end of wxNotebook::OnSelChange 
 722 void wxNotebook::OnSetFocus ( 
 727     // This function is only called when the focus is explicitly set (i.e. from 
 728     // the program) to the notebook - in this case we don't need the 
 729     // complicated OnNavigationKey() logic because the programmer knows better 
 732     // set focus to the currently selected page if any 
 734     if (m_selection 
!= wxNOT_FOUND
) 
 735         m_pages
[m_selection
]->SetFocus(); 
 737 } // end of wxNotebook::OnSetFocus 
 739 void wxNotebook::OnNavigationKey ( 
 740   wxNavigationKeyEvent
&             rEvent
 
 743     if (rEvent
.IsWindowChange()) 
 748         AdvanceSelection(rEvent
.GetDirection()); 
 753         // We get this event in 2 cases 
 755         // a) one of our pages might have generated it because the user TABbed 
 756         // out from it in which case we should propagate the event upwards and 
 757         // our parent will take care of setting the focus to prev/next sibling 
 761         // b) the parent panel wants to give the focus to us so that we 
 762         // forward it to our selected page. We can't deal with this in 
 763         // OnSetFocus() because we don't know which direction the focus came 
 764         // from in this case and so can't choose between setting the focus to 
 765         // first or last panel child 
 767         wxWindow
*                   pParent 
= GetParent(); 
 769         if (rEvent
.GetEventObject() == pParent
) 
 772             // No, it doesn't come from child, case (b): forward to a page 
 774             if (m_selection 
!= wxNOT_FOUND
) 
 777                 // So that the page knows that the event comes from it's parent 
 778                 // and is being propagated downwards 
 780                 rEvent
.SetEventObject(this); 
 782                 wxWindow
*           pPage 
= m_pages
[m_selection
]; 
 784                 if (!pPage
->HandleWindowEvent(rEvent
)) 
 788                 //else: page manages focus inside it itself 
 793                 // We have no pages - still have to give focus to _something_ 
 801             // It comes from our child, case (a), pass to the parent 
 805                 rEvent
.SetCurrentFocus(this); 
 806                 pParent
->HandleWindowEvent(rEvent
); 
 810 } // end of wxNotebook::OnNavigationKey 
 812 // ---------------------------------------------------------------------------- 
 813 // wxNotebook base class virtuals 
 814 // ---------------------------------------------------------------------------- 
 817 // Override these 2 functions to do nothing: everything is done in OnSize 
 819 void wxNotebook::SetConstraintSizes( bool WXUNUSED(bRecurse
) ) 
 822     // Don't set the sizes of the pages - their correct size is not yet known 
 824     wxControl::SetConstraintSizes(false); 
 825 } // end of wxNotebook::SetConstraintSizes 
 827 bool wxNotebook::DoPhase ( int WXUNUSED(nPhase
) ) 
 830 } // end of wxNotebook::DoPhase 
 832 // ---------------------------------------------------------------------------- 
 833 // wxNotebook Windows message handlers 
 834 // ---------------------------------------------------------------------------- 
 835 bool wxNotebook::OS2OnScroll ( int    nOrientation
, 
 841     // Don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the 
 846     return wxNotebookBase::OS2OnScroll( nOrientation
 
 851 } // end of wxNotebook::OS2OnScroll 
 853 #endif // wxUSE_NOTEBOOK