1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/notebook.cpp 
   3 // Purpose:     implementation of wxNotebook 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  21 #include "wx/notebook.h" 
  24     #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly" 
  25     #include "wx/string.h" 
  30     #include "wx/dcclient.h" 
  31     #include "wx/dcmemory.h" 
  32     #include "wx/control.h" 
  36 #include "wx/imaglist.h" 
  37 #include "wx/sysopt.h" 
  39 #include "wx/msw/private.h" 
  40 #include "wx/msw/dc.h" 
  43 #include "wx/msw/winundef.h" 
  46     #include "wx/msw/uxtheme.h" 
  49 // ---------------------------------------------------------------------------- 
  51 // ---------------------------------------------------------------------------- 
  53 // check that the page index is valid 
  54 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) 
  56 // you can set USE_NOTEBOOK_ANTIFLICKER to 0 for desktop Windows versions too 
  57 // to disable code whih results in flicker-less notebook redrawing at the 
  58 // expense of some extra GDI resource consumption 
  60     // notebooks are never resized under CE anyhow 
  61     #define USE_NOTEBOOK_ANTIFLICKER    0 
  63     #define USE_NOTEBOOK_ANTIFLICKER    1 
  66 // ---------------------------------------------------------------------------- 
  68 // ---------------------------------------------------------------------------- 
  70 // This is a work-around for missing defines in gcc-2.95 headers 
  72     #define TCS_RIGHT       0x0002 
  76     #define TCS_VERTICAL    0x0080 
  80     #define TCS_BOTTOM      TCS_RIGHT 
  83 // ---------------------------------------------------------------------------- 
  85 // ---------------------------------------------------------------------------- 
  87 #if USE_NOTEBOOK_ANTIFLICKER 
  89 // the pointer to standard spin button wnd proc 
  90 static WXFARPROC gs_wndprocNotebookSpinBtn 
= (WXFARPROC
)NULL
; 
  92 // the pointer to standard tab control wnd proc 
  93 static WXFARPROC gs_wndprocNotebook 
= (WXFARPROC
)NULL
; 
  95 LRESULT APIENTRY _EXPORT 
wxNotebookWndProc(HWND hwnd
, 
 100 #endif // USE_NOTEBOOK_ANTIFLICKER 
 102 // ---------------------------------------------------------------------------- 
 104 // ---------------------------------------------------------------------------- 
 106 static bool HasTroubleWithNonTopTabs() 
 108     const int verComCtl32 
= wxApp::GetComCtl32Version(); 
 110     // 600 is XP, 616 is Vista -- and both have a problem with tabs not on top 
 111     // (but don't just test for >= 600 as Microsoft might decide to fix it in 
 112     // later versions, who knows...) 
 113     return verComCtl32 
>= 600 && verComCtl32 
<= 616; 
 116 // ---------------------------------------------------------------------------- 
 118 // ---------------------------------------------------------------------------- 
 120 #include "wx/listimpl.cpp" 
 122 WX_DEFINE_LIST( wxNotebookPageInfoList 
) 
 124 BEGIN_EVENT_TABLE(wxNotebook
, wxBookCtrlBase
) 
 125     EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY
, wxNotebook::OnSelChange
) 
 126     EVT_SIZE(wxNotebook::OnSize
) 
 127     EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
) 
 129 #if USE_NOTEBOOK_ANTIFLICKER 
 130     EVT_ERASE_BACKGROUND(wxNotebook::OnEraseBackground
) 
 131     EVT_PAINT(wxNotebook::OnPaint
) 
 132 #endif // USE_NOTEBOOK_ANTIFLICKER 
 135 #if wxUSE_EXTENDED_RTTI 
 136 WX_DEFINE_FLAGS( wxNotebookStyle 
) 
 138 wxBEGIN_FLAGS( wxNotebookStyle 
) 
 139     // new style border flags, we put them first to 
 140     // use them for streaming out 
 141     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
 142     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
 143     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
 144     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
 145     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
 146     wxFLAGS_MEMBER(wxBORDER_NONE
) 
 148     // old style border flags 
 149     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
 150     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
 151     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
 152     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
 153     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
 154     wxFLAGS_MEMBER(wxBORDER
) 
 156     // standard window styles 
 157     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
 158     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
 159     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
 160     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
 161     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
 162     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
 163     wxFLAGS_MEMBER(wxVSCROLL
) 
 164     wxFLAGS_MEMBER(wxHSCROLL
) 
 166     wxFLAGS_MEMBER(wxNB_FIXEDWIDTH
) 
 167     wxFLAGS_MEMBER(wxBK_DEFAULT
) 
 168     wxFLAGS_MEMBER(wxBK_TOP
) 
 169     wxFLAGS_MEMBER(wxBK_LEFT
) 
 170     wxFLAGS_MEMBER(wxBK_RIGHT
) 
 171     wxFLAGS_MEMBER(wxBK_BOTTOM
) 
 172     wxFLAGS_MEMBER(wxNB_NOPAGETHEME
) 
 173     wxFLAGS_MEMBER(wxNB_FLAT
) 
 175 wxEND_FLAGS( wxNotebookStyle 
) 
 177 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebook
, wxBookCtrlBase
,"wx/notebook.h") 
 178 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebookPageInfo
, wxObject 
, "wx/notebook.h" ) 
 180 wxCOLLECTION_TYPE_INFO( wxNotebookPageInfo 
* , wxNotebookPageInfoList 
) ; 
 182 template<> void wxCollectionToVariantArray( wxNotebookPageInfoList 
const &theList
, wxxVariantArray 
&value
) 
 184     wxListCollectionToVariantArray
<wxNotebookPageInfoList::compatibility_iterator
>( theList 
, value 
) ; 
 187 wxBEGIN_PROPERTIES_TABLE(wxNotebook
) 
 188     wxEVENT_PROPERTY( PageChanging 
, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING 
, wxBookCtrlEvent 
) 
 189     wxEVENT_PROPERTY( PageChanged 
, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED 
, wxBookCtrlEvent 
) 
 191     wxPROPERTY_COLLECTION( PageInfos 
, wxNotebookPageInfoList 
, wxNotebookPageInfo
* , AddPageInfo 
, GetPageInfos 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 192     wxPROPERTY_FLAGS( WindowStyle 
, wxNotebookStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 193 wxEND_PROPERTIES_TABLE() 
 195 wxBEGIN_HANDLERS_TABLE(wxNotebook
) 
 196 wxEND_HANDLERS_TABLE() 
 198 wxCONSTRUCTOR_5( wxNotebook 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxPoint 
, Position 
, wxSize 
, Size 
, long , WindowStyle
) 
 201 wxBEGIN_PROPERTIES_TABLE(wxNotebookPageInfo
) 
 202     wxREADONLY_PROPERTY( Page 
, wxNotebookPage
* , GetPage 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 203     wxREADONLY_PROPERTY( Text 
, wxString 
, GetText 
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 204     wxREADONLY_PROPERTY( Selected 
, bool , GetSelected 
, false, 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) 
 205     wxREADONLY_PROPERTY( ImageId 
, int , GetImageId 
, -1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 206 wxEND_PROPERTIES_TABLE() 
 208 wxBEGIN_HANDLERS_TABLE(wxNotebookPageInfo
) 
 209 wxEND_HANDLERS_TABLE() 
 211 wxCONSTRUCTOR_4( wxNotebookPageInfo 
, wxNotebookPage
* , Page 
, wxString 
, Text 
, bool , Selected 
, int , ImageId 
) 
 214 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxBookCtrlBase
) 
 215 IMPLEMENT_DYNAMIC_CLASS(wxNotebookPageInfo
, wxObject 
) 
 218 // ============================================================================ 
 220 // ============================================================================ 
 222 // ---------------------------------------------------------------------------- 
 223 // wxNotebook construction 
 224 // ---------------------------------------------------------------------------- 
 226 const wxNotebookPageInfoList
& wxNotebook::GetPageInfos() const 
 228     wxNotebookPageInfoList
* list 
= const_cast< wxNotebookPageInfoList
* >( &m_pageInfos 
) ; 
 229     WX_CLEAR_LIST( wxNotebookPageInfoList 
, *list 
) ; 
 230     for( size_t i 
= 0 ; i 
< GetPageCount() ; ++i 
) 
 232         wxNotebookPageInfo 
*info 
= new wxNotebookPageInfo() ; 
 233         info
->Create( const_cast<wxNotebook
*>(this)->GetPage(i
) , GetPageText(i
) , GetSelection() == int(i
) , GetPageImage(i
) ) ; 
 234         list
->Append( info 
) ; 
 239 // common part of all ctors 
 240 void wxNotebook::Init() 
 245     m_hbrBackground 
= NULL
; 
 246 #endif // wxUSE_UXTHEME 
 248 #if USE_NOTEBOOK_ANTIFLICKER 
 249     m_hasSubclassedUpdown 
= false; 
 250 #endif // USE_NOTEBOOK_ANTIFLICKER 
 253 // default for dynamic class 
 254 wxNotebook::wxNotebook() 
 259 // the same arguments as for wxControl 
 260 wxNotebook::wxNotebook(wxWindow 
*parent
, 
 265                        const wxString
& name
) 
 269   Create(parent
, id
, pos
, size
, style
, name
); 
 273 bool wxNotebook::Create(wxWindow 
*parent
, 
 278                         const wxString
& name
) 
 280     if ( (style 
& wxBK_ALIGN_MASK
) == wxBK_DEFAULT 
) 
 282 #if defined(__POCKETPC__) 
 283         style 
|= wxBK_BOTTOM 
| wxNB_FLAT
; 
 290     // Not sure why, but without this style, there is no border 
 291     // around the notebook tabs. 
 292     if (style 
& wxNB_FLAT
) 
 293         style 
|= wxBORDER_SUNKEN
; 
 297     // ComCtl32 notebook tabs simply don't work unless they're on top if we 
 298     // have uxtheme, we can work around it later (after control creation), but 
 299     // if we have been compiled without uxtheme support, we have to clear those 
 301     if ( HasTroubleWithNonTopTabs() ) 
 303         style 
&= ~(wxBK_BOTTOM 
| wxBK_LEFT 
| wxBK_RIGHT
); 
 305 #endif //wxUSE_UXTHEME 
 307 #if defined(__WINE__) && wxUSE_UNICODE 
 308     LPCTSTR className 
= L
"SysTabControl32"; 
 310     LPCTSTR className 
= WC_TABCONTROL
; 
 313 #if USE_NOTEBOOK_ANTIFLICKER 
 314     // SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it 
 315     // causes horrible flicker when resizing notebook, so get rid of it by 
 316     // using a class without these styles (but otherwise identical to it) 
 317     if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) ) 
 319         static ClassRegistrar s_clsNotebook
; 
 320         if ( !s_clsNotebook
.IsInitialized() ) 
 322             // get a copy of standard class and modify it 
 325             if ( ::GetClassInfo(NULL
, WC_TABCONTROL
, &wc
) ) 
 328                     reinterpret_cast<WXFARPROC
>(wc
.lpfnWndProc
); 
 329                 wc
.lpszClassName 
= wxT("_wx_SysTabCtl32"); 
 330                 wc
.style 
&= ~(CS_HREDRAW 
| CS_VREDRAW
); 
 331                 wc
.hInstance 
= wxGetInstance(); 
 332                 wc
.lpfnWndProc 
= wxNotebookWndProc
; 
 333                 s_clsNotebook
.Register(wc
); 
 337                 wxLogLastError(wxT("GetClassInfoEx(SysTabCtl32)")); 
 341         // use our custom class if available but fall back to the standard 
 342         // notebook if we failed to register it 
 343         if ( s_clsNotebook
.IsRegistered() ) 
 345             // it's ok to use c_str() here as the static s_clsNotebook object 
 346             // has sufficiently long lifetime 
 347             className 
= s_clsNotebook
.GetName().c_str(); 
 350 #endif // USE_NOTEBOOK_ANTIFLICKER 
 352     if ( !CreateControl(parent
, id
, pos
, size
, style 
| wxTAB_TRAVERSAL
, 
 353                         wxDefaultValidator
, name
) ) 
 356     if ( !MSWCreateControl(className
, wxEmptyString
, pos
, size
) ) 
 360     if ( HasFlag(wxNB_NOPAGETHEME
) || 
 361             wxSystemOptions::IsFalse(wxT("msw.notebook.themed-background")) ) 
 363         SetBackgroundColour(GetThemeBackgroundColour()); 
 365     else // use themed background by default 
 367         // create backing store 
 371     // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the 
 372     // control is simply not rendered correctly), so we disable themes 
 373     // if possible, otherwise we simply clear the styles. 
 374     if ( HasTroubleWithNonTopTabs() && 
 375             (style 
& (wxBK_BOTTOM 
| wxBK_LEFT 
| wxBK_RIGHT
)) ) 
 377         // check if we use themes at all -- if we don't, we're still okay 
 378         if ( wxUxThemeEngine::GetIfActive() ) 
 380             wxUxThemeEngine::GetIfActive()->SetWindowTheme(GetHwnd(), L
"", L
""); 
 382             // correct the background color for the new non-themed control 
 383             SetBackgroundColour(GetThemeBackgroundColour()); 
 386 #endif // wxUSE_UXTHEME 
 388     // Undocumented hack to get flat notebook style 
 389     // In fact, we should probably only do this in some 
 390     // curcumstances, i.e. if we know we will have a border 
 391     // at the bottom (the tab control doesn't draw it itself) 
 392 #if defined(__POCKETPC__) || defined(__SMARTPHONE__) 
 393     if (HasFlag(wxNB_FLAT
)) 
 395         SendMessage(GetHwnd(), CCM_SETVERSION
, COMCTL32_VERSION
, 0); 
 397             SetBackgroundColour(*wxWHITE
); 
 403 WXDWORD 
wxNotebook::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 405     WXDWORD tabStyle 
= wxControl::MSWGetStyle(style
, exstyle
); 
 407     tabStyle 
|= WS_TABSTOP 
| TCS_TABS
; 
 409     if ( style 
& wxNB_MULTILINE 
) 
 410         tabStyle 
|= TCS_MULTILINE
; 
 411     if ( style 
& wxNB_FIXEDWIDTH 
) 
 412         tabStyle 
|= TCS_FIXEDWIDTH
; 
 414     if ( style 
& wxBK_BOTTOM 
) 
 415         tabStyle 
|= TCS_RIGHT
; 
 416     else if ( style 
& wxBK_LEFT 
) 
 417         tabStyle 
|= TCS_VERTICAL
; 
 418     else if ( style 
& wxBK_RIGHT 
) 
 419         tabStyle 
|= TCS_VERTICAL 
| TCS_RIGHT
; 
 424 wxNotebook::~wxNotebook() 
 427     if ( m_hbrBackground 
) 
 428         ::DeleteObject((HBRUSH
)m_hbrBackground
); 
 429 #endif // wxUSE_UXTHEME 
 432 // ---------------------------------------------------------------------------- 
 433 // wxNotebook accessors 
 434 // ---------------------------------------------------------------------------- 
 436 size_t wxNotebook::GetPageCount() const 
 439     wxASSERT( (int)m_pages
.Count() == TabCtrl_GetItemCount(GetHwnd()) ); 
 441     return m_pages
.Count(); 
 444 int wxNotebook::GetRowCount() const 
 446     return TabCtrl_GetRowCount(GetHwnd()); 
 449 int wxNotebook::SetSelection(size_t nPage
) 
 451     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 453     if ( m_selection 
== wxNOT_FOUND 
|| nPage 
!= (size_t)m_selection 
) 
 455         if ( SendPageChangingEvent(nPage
) ) 
 457             // program allows the page change 
 458             SendPageChangedEvent(m_selection
, nPage
); 
 460             TabCtrl_SetCurSel(GetHwnd(), nPage
); 
 467 void wxNotebook::UpdateSelection(int selNew
) 
 469     if ( m_selection 
!= wxNOT_FOUND 
) 
 470         m_pages
[m_selection
]->Show(false); 
 472     if ( selNew 
!= wxNOT_FOUND 
) 
 474         wxNotebookPage 
*pPage 
= m_pages
[selNew
]; 
 478     // Changing the page should give the focus to it but, as per bug report 
 479     // http://sf.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863, 
 480     // we should not set the focus to it directly since it erroneously 
 481     // selects radio buttons and breaks keyboard handling for a notebook's 
 482     // scroll buttons. So give focus to the notebook and not the page. 
 484     // but don't do this is the notebook is hidden 
 485     if ( ::IsWindowVisible(GetHwnd()) ) 
 488     m_selection 
= selNew
; 
 491 int wxNotebook::ChangeSelection(size_t nPage
) 
 493     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 495     const int selOld 
= m_selection
; 
 497     if ( m_selection 
== wxNOT_FOUND 
|| nPage 
!= (size_t)m_selection 
) 
 499         TabCtrl_SetCurSel(GetHwnd(), nPage
); 
 501         UpdateSelection(nPage
); 
 507 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
) 
 509     wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") ); 
 512     tcItem
.mask 
= TCIF_TEXT
; 
 513     tcItem
.pszText 
= (wxChar 
*)strText
.wx_str(); 
 515     if ( !HasFlag(wxNB_MULTILINE
) ) 
 516         return TabCtrl_SetItem(GetHwnd(), nPage
, &tcItem
) != 0; 
 518     // multiline - we need to set new page size if a line is added or removed 
 519     int rows 
= GetRowCount(); 
 520     bool ret 
= TabCtrl_SetItem(GetHwnd(), nPage
, &tcItem
) != 0; 
 522     if ( ret 
&& rows 
!= GetRowCount() ) 
 524         const wxRect r 
= GetPageSize(); 
 525         const size_t count 
= m_pages
.Count(); 
 526         for ( size_t page 
= 0; page 
< count
; page
++ ) 
 527             m_pages
[page
]->SetSize(r
); 
 533 wxString 
wxNotebook::GetPageText(size_t nPage
) const 
 535     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") ); 
 539     tcItem
.mask 
= TCIF_TEXT
; 
 540     tcItem
.pszText 
= buf
; 
 541     tcItem
.cchTextMax 
= WXSIZEOF(buf
); 
 544     if ( TabCtrl_GetItem(GetHwnd(), nPage
, &tcItem
) ) 
 545         str 
= tcItem
.pszText
; 
 550 int wxNotebook::GetPageImage(size_t nPage
) const 
 552     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 555     tcItem
.mask 
= TCIF_IMAGE
; 
 557     return TabCtrl_GetItem(GetHwnd(), nPage
, &tcItem
) ? tcItem
.iImage
 
 561 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
) 
 563     wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") ); 
 566     tcItem
.mask 
= TCIF_IMAGE
; 
 567     tcItem
.iImage 
= nImage
; 
 569     return TabCtrl_SetItem(GetHwnd(), nPage
, &tcItem
) != 0; 
 572 void wxNotebook::SetImageList(wxImageList
* imageList
) 
 574     wxNotebookBase::SetImageList(imageList
); 
 578         (void) TabCtrl_SetImageList(GetHwnd(), GetHimagelistOf(imageList
)); 
 582 // ---------------------------------------------------------------------------- 
 583 // wxNotebook size settings 
 584 // ---------------------------------------------------------------------------- 
 586 wxRect 
wxNotebook::GetPageSize() const 
 591     ::GetClientRect(GetHwnd(), &rc
); 
 593     // This check is to work around a bug in TabCtrl_AdjustRect which will 
 594     // cause a crash on win2k or on XP with themes disabled if either 
 595     // wxNB_MULTILINE is used or tabs are placed on a side, if the rectangle 
 598     // The value of 20 is chosen arbitrarily but seems to work 
 599     if ( rc
.right 
> 20 && rc
.bottom 
> 20 ) 
 601         TabCtrl_AdjustRect(GetHwnd(), false, &rc
); 
 603         wxCopyRECTToRect(rc
, r
); 
 609 void wxNotebook::SetPageSize(const wxSize
& size
) 
 611     // transform the page size into the notebook size 
 618     TabCtrl_AdjustRect(GetHwnd(), true, &rc
); 
 621     SetSize(rc
.right 
- rc
.left
, rc
.bottom 
- rc
.top
); 
 624 void wxNotebook::SetPadding(const wxSize
& padding
) 
 626     TabCtrl_SetPadding(GetHwnd(), padding
.x
, padding
.y
); 
 629 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH 
 631 void wxNotebook::SetTabSize(const wxSize
& sz
) 
 633     ::SendMessage(GetHwnd(), TCM_SETITEMSIZE
, 0, MAKELPARAM(sz
.x
, sz
.y
)); 
 636 wxSize 
wxNotebook::CalcSizeFromPage(const wxSize
& sizePage
) const 
 638     // we can't use TabCtrl_AdjustRect here because it only works for wxNB_TOP 
 639     wxSize sizeTotal 
= sizePage
; 
 642     if ( GetPageCount() > 0 ) 
 645         TabCtrl_GetItemRect(GetHwnd(), 0, &rect
); 
 646         tabSize
.x 
= rect
.right 
- rect
.left
; 
 647         tabSize
.y 
= rect
.bottom 
- rect
.top
; 
 650     const int rows 
= GetRowCount(); 
 652     // add an extra margin in both directions 
 653     const int MARGIN 
= 8; 
 656         sizeTotal
.x 
+= MARGIN
; 
 657         sizeTotal
.y 
+= tabSize
.y 
* rows 
+ MARGIN
; 
 659     else // horizontal layout 
 661         sizeTotal
.x 
+= tabSize
.x 
* rows 
+ MARGIN
; 
 662         sizeTotal
.y 
+= MARGIN
; 
 668 void wxNotebook::AdjustPageSize(wxNotebookPage 
*page
) 
 670     wxCHECK_RET( page
, wxT("NULL page in wxNotebook::AdjustPageSize") ); 
 672     const wxRect r 
= GetPageSize(); 
 679 // ---------------------------------------------------------------------------- 
 680 // wxNotebook operations 
 681 // ---------------------------------------------------------------------------- 
 683 // remove one page from the notebook, without deleting 
 684 wxNotebookPage 
*wxNotebook::DoRemovePage(size_t nPage
) 
 686     wxNotebookPage 
*pageRemoved 
= wxNotebookBase::DoRemovePage(nPage
); 
 690     // hide the removed page to maintain the invariant that only the 
 691     // selected page is visible and others are hidden: 
 692     pageRemoved
->Show(false); 
 694     TabCtrl_DeleteItem(GetHwnd(), nPage
); 
 696     if ( m_pages
.IsEmpty() ) 
 698         // no selection any more, the notebook becamse empty 
 699         m_selection 
= wxNOT_FOUND
; 
 701     else // notebook still not empty 
 703         int selNew 
= TabCtrl_GetCurSel(GetHwnd()); 
 704         if ( selNew 
!= wxNOT_FOUND 
) 
 706             // No selection change, just refresh the current selection. 
 707             // Because it could be that the slection index changed 
 708             // we need to update it. 
 709             // Note: this does not mean the selection it self changed. 
 710             m_selection 
= selNew
; 
 711             m_pages
[m_selection
]->Refresh(); 
 713         else if (int(nPage
) == m_selection
) 
 715             // The selection was deleted. 
 717             // Determine new selection. 
 718             if (m_selection 
== int(GetPageCount())) 
 719                 selNew 
= m_selection 
- 1; 
 721                 selNew 
= m_selection
; 
 723             // m_selection must be always valid so reset it before calling 
 725             m_selection 
= wxNOT_FOUND
; 
 726             SetSelection(selNew
); 
 730             wxFAIL
; // Windows did not behave ok. 
 738 bool wxNotebook::DeleteAllPages() 
 740     size_t nPageCount 
= GetPageCount(); 
 742     for ( nPage 
= 0; nPage 
< nPageCount
; nPage
++ ) 
 743         delete m_pages
[nPage
]; 
 747     TabCtrl_DeleteAllItems(GetHwnd()); 
 749     m_selection 
= wxNOT_FOUND
; 
 751     InvalidateBestSize(); 
 755 // same as AddPage() but does it at given position 
 756 bool wxNotebook::InsertPage(size_t nPage
, 
 757                             wxNotebookPage 
*pPage
, 
 758                             const wxString
& strText
, 
 762     wxCHECK_MSG( pPage 
!= NULL
, false, wxT("NULL page in wxNotebook::InsertPage") ); 
 763     wxCHECK_MSG( IS_VALID_PAGE(nPage
) || nPage 
== GetPageCount(), false, 
 764                  wxT("invalid index in wxNotebook::InsertPage") ); 
 766     wxASSERT_MSG( pPage
->GetParent() == this, 
 767                     wxT("notebook pages must have notebook as parent") ); 
 769     // add a new tab to the control 
 770     // ---------------------------- 
 772     // init all fields to 0 
 774     wxZeroMemory(tcItem
); 
 776     // set the image, if any 
 779         tcItem
.mask 
|= TCIF_IMAGE
; 
 780         tcItem
.iImage  
= imageId
; 
 784     if ( !strText
.empty() ) 
 786         tcItem
.mask 
|= TCIF_TEXT
; 
 787         tcItem
.pszText 
= const_cast<wxChar 
*>(strText
.wx_str()); 
 790     // hide the page: unless it is selected, it shouldn't be shown (and if it 
 791     // is selected it will be shown later) 
 792     HWND hwnd 
= GetWinHwnd(pPage
); 
 793     SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~WS_VISIBLE
); 
 795     // this updates internal flag too -- otherwise it would get out of sync 
 796     // with the real state 
 800     // fit the notebook page to the tab control's display area: this should be 
 801     // done before adding it to the notebook or TabCtrl_InsertItem() will 
 802     // change the notebooks size itself! 
 803     AdjustPageSize(pPage
); 
 805     // finally do insert it 
 806     if ( TabCtrl_InsertItem(GetHwnd(), nPage
, &tcItem
) == -1 ) 
 808         wxLogError(wxT("Can't create the notebook page '%s'."), strText
.c_str()); 
 813     // need to update the bg brush when the first page is added 
 814     // so the first panel gets the correct themed background 
 815     if ( m_pages
.empty() ) 
 819 #endif // wxUSE_UXTHEME 
 822     // succeeded: save the pointer to the page 
 823     m_pages
.Insert(pPage
, nPage
); 
 825     // we may need to adjust the size again if the notebook size changed: 
 826     // normally this only happens for the first page we add (the tabs which 
 827     // hadn't been there before are now shown) but for a multiline notebook it 
 828     // can happen for any page at all as a new row could have been started 
 829     if ( m_pages
.GetCount() == 1 || HasFlag(wxNB_MULTILINE
) ) 
 831         AdjustPageSize(pPage
); 
 834     // now deal with the selection 
 835     // --------------------------- 
 837     // if the inserted page is before the selected one, we must update the 
 838     // index of the selected page 
 839     if ( int(nPage
) <= m_selection 
) 
 841         // one extra page added 
 845     // some page should be selected: either this one or the first one if there 
 846     // is still no selection 
 847     int selNew 
= wxNOT_FOUND
; 
 850     else if ( m_selection 
== wxNOT_FOUND 
) 
 853     if ( selNew 
!= wxNOT_FOUND 
) 
 854         SetSelection(selNew
); 
 856     InvalidateBestSize(); 
 861 int wxNotebook::HitTest(const wxPoint
& pt
, long *flags
) const 
 863     TC_HITTESTINFO hitTestInfo
; 
 864     hitTestInfo
.pt
.x 
= pt
.x
; 
 865     hitTestInfo
.pt
.y 
= pt
.y
; 
 866     int item 
= TabCtrl_HitTest(GetHwnd(), &hitTestInfo
); 
 872         if ((hitTestInfo
.flags 
& TCHT_NOWHERE
) == TCHT_NOWHERE
) 
 873             *flags 
|= wxBK_HITTEST_NOWHERE
; 
 874         if ((hitTestInfo
.flags 
& TCHT_ONITEM
) == TCHT_ONITEM
) 
 875             *flags 
|= wxBK_HITTEST_ONITEM
; 
 876         if ((hitTestInfo
.flags 
& TCHT_ONITEMICON
) == TCHT_ONITEMICON
) 
 877             *flags 
|= wxBK_HITTEST_ONICON
; 
 878         if ((hitTestInfo
.flags 
& TCHT_ONITEMLABEL
) == TCHT_ONITEMLABEL
) 
 879             *flags 
|= wxBK_HITTEST_ONLABEL
; 
 880         if ( item 
== wxNOT_FOUND 
&& GetPageSize().Contains(pt
) ) 
 881             *flags 
|= wxBK_HITTEST_ONPAGE
; 
 887 // ---------------------------------------------------------------------------- 
 888 // flicker-less notebook redraw 
 889 // ---------------------------------------------------------------------------- 
 891 #if USE_NOTEBOOK_ANTIFLICKER 
 893 // wnd proc for the spin button 
 894 LRESULT APIENTRY _EXPORT 
wxNotebookSpinBtnWndProc(HWND hwnd
, 
 899     if ( message 
== WM_ERASEBKGND 
) 
 902     return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebookSpinBtn
, 
 903                             hwnd
, message
, wParam
, lParam
); 
 906 LRESULT APIENTRY _EXPORT 
wxNotebookWndProc(HWND hwnd
, 
 911     return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebook
, 
 912                             hwnd
, message
, wParam
, lParam
); 
 915 void wxNotebook::OnEraseBackground(wxEraseEvent
& WXUNUSED(event
)) 
 920 void wxNotebook::OnPaint(wxPaintEvent
& WXUNUSED(event
)) 
 925     ::GetClientRect(GetHwnd(), &rc
); 
 926     wxBitmap 
bmp(rc
.right
, rc
.bottom
); 
 927     memdc
.SelectObject(bmp
); 
 929     const wxLayoutDirection dir 
= dc
.GetLayoutDirection(); 
 930     memdc
.SetLayoutDirection(dir
); 
 932     // if there is no special brush just use the solid background colour 
 934     HBRUSH hbr 
= (HBRUSH
)m_hbrBackground
; 
 941         brush 
= wxBrush(GetBackgroundColour()); 
 942         hbr 
= GetHbrushOf(brush
); 
 945     wxMSWDCImpl 
*impl 
= (wxMSWDCImpl
*) memdc
.GetImpl(); 
 947     ::FillRect(GetHdcOf(*impl
), &rc
, hbr
); 
 949     MSWDefWindowProc(WM_PAINT
, (WPARAM
)(impl
->GetHDC()), 0); 
 951     // For some reason in RTL mode, source offset has to be -1, otherwise the 
 952     // right border (physical) remains unpainted. 
 953     const wxCoord ofs 
= dir 
== wxLayout_RightToLeft 
? -1 : 0; 
 954     dc
.Blit(ofs
, 0, rc
.right
, rc
.bottom
, &memdc
, ofs
, 0); 
 957 #endif // USE_NOTEBOOK_ANTIFLICKER 
 959 // ---------------------------------------------------------------------------- 
 960 // wxNotebook callbacks 
 961 // ---------------------------------------------------------------------------- 
 963 void wxNotebook::OnSize(wxSizeEvent
& event
) 
 965     if ( GetPageCount() == 0 ) 
 967         // Prevents droppings on resize, but does cause some flicker 
 968         // when there are no pages. 
 976         // Without this, we can sometimes get droppings at the edges 
 977         // of a notebook, for example a notebook in a splitter window. 
 978         // This needs to be reconciled with the RefreshRect calls 
 979         // at the end of this function, which weren't enough to prevent 
 982         wxSize sz 
= GetClientSize(); 
 984         // Refresh right side 
 985         wxRect 
rect(sz
.x
-4, 0, 4, sz
.y
); 
 988         // Refresh bottom side 
 989         rect 
= wxRect(0, sz
.y
-4, sz
.x
, 4); 
 993         rect 
= wxRect(0, 0, 4, sz
.y
); 
 996 #endif // !__WXWINCE__ 
 998     // fit all the notebook pages to the tab control's display area 
1001     rc
.left 
= rc
.top 
= 0; 
1002     GetSize((int *)&rc
.right
, (int *)&rc
.bottom
); 
1004     // save the total size, we'll use it below 
1005     int widthNbook 
= rc
.right 
- rc
.left
, 
1006         heightNbook 
= rc
.bottom 
- rc
.top
; 
1008     // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it 
1009     // returns completely false values for multiline tab controls after the tabs 
1010     // are added but before getting the first WM_SIZE (off by ~50 pixels, see 
1012     // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863 
1014     // and the only work around I could find was this ugly hack... without it 
1015     // simply toggling the "multiline" checkbox in the notebook sample resulted 
1016     // in a noticeable page displacement 
1017     if ( HasFlag(wxNB_MULTILINE
) ) 
1019         // avoid an infinite recursion: we get another notification too! 
1020         static bool s_isInOnSize 
= false; 
1022         if ( !s_isInOnSize 
) 
1024             s_isInOnSize 
= true; 
1025             SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
, 
1026                     MAKELPARAM(rc
.right
, rc
.bottom
)); 
1027             s_isInOnSize 
= false; 
1030         // The best size depends on the number of rows of tabs, which can 
1031         // change when the notepad is resized. 
1032         InvalidateBestSize(); 
1036     // background bitmap size has changed, update the brush using it too 
1038 #endif // wxUSE_UXTHEME 
1040     TabCtrl_AdjustRect(GetHwnd(), false, &rc
); 
1042     int width 
= rc
.right 
- rc
.left
, 
1043         height 
= rc
.bottom 
- rc
.top
; 
1044     size_t nCount 
= m_pages
.Count(); 
1045     for ( size_t nPage 
= 0; nPage 
< nCount
; nPage
++ ) { 
1046         wxNotebookPage 
*pPage 
= m_pages
[nPage
]; 
1047         pPage
->SetSize(rc
.left
, rc
.top
, width
, height
); 
1051     // unless we had already repainted everything, we now need to refresh 
1052     if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) ) 
1054         // invalidate areas not covered by pages 
1055         RefreshRect(wxRect(0, 0, widthNbook
, rc
.top
), false); 
1056         RefreshRect(wxRect(0, rc
.top
, rc
.left
, height
), false); 
1057         RefreshRect(wxRect(0, rc
.bottom
, widthNbook
, heightNbook 
- rc
.bottom
), 
1059         RefreshRect(wxRect(rc
.right
, rc
.top
, widthNbook 
- rc
.right
, height
), 
1063 #if USE_NOTEBOOK_ANTIFLICKER 
1064     // subclass the spin control used by the notebook to scroll pages to 
1065     // prevent it from flickering on resize 
1066     if ( !m_hasSubclassedUpdown 
) 
1068         // iterate over all child windows to find spin button 
1069         for ( HWND child 
= ::GetWindow(GetHwnd(), GW_CHILD
); 
1071               child 
= ::GetWindow(child
, GW_HWNDNEXT
) ) 
1073             wxWindow 
*childWindow 
= wxFindWinFromHandle((WXHWND
)child
); 
1075             // see if it exists, if no wxWindow found then assume it's the spin 
1079                 // subclass the spin button to override WM_ERASEBKGND 
1080                 if ( !gs_wndprocNotebookSpinBtn 
) 
1081                     gs_wndprocNotebookSpinBtn 
= (WXFARPROC
)wxGetWindowProc(child
); 
1083                 wxSetWindowProc(child
, wxNotebookSpinBtnWndProc
); 
1084                 m_hasSubclassedUpdown 
= true; 
1089 #endif // USE_NOTEBOOK_ANTIFLICKER 
1094 void wxNotebook::OnSelChange(wxBookCtrlEvent
& event
) 
1096     // is it our tab control? 
1097     if ( event
.GetEventObject() == this ) 
1099         UpdateSelection(event
.GetSelection()); 
1102     // we want to give others a chance to process this message as well 
1106 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
) 
1108     if ( event
.IsWindowChange() ) { 
1110         AdvanceSelection(event
.GetDirection()); 
1113         // we get this event in 3 cases 
1115         // a) one of our pages might have generated it because the user TABbed 
1116         // out from it in which case we should propagate the event upwards and 
1117         // our parent will take care of setting the focus to prev/next sibling 
1121         // b) the parent panel wants to give the focus to us so that we 
1122         // forward it to our selected page. We can't deal with this in 
1123         // OnSetFocus() because we don't know which direction the focus came 
1124         // from in this case and so can't choose between setting the focus to 
1125         // first or last panel child 
1129         // c) we ourselves (see MSWTranslateMessage) generated the event 
1131         wxWindow 
* const parent 
= GetParent(); 
1133         // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE 
1134         const bool isFromParent 
= event
.GetEventObject() == (wxObject
*) parent
; 
1135         const bool isFromSelf 
= event
.GetEventObject() == (wxObject
*) this; 
1136         const bool isForward 
= event
.GetDirection(); 
1138         if ( isFromSelf 
&& !isForward 
) 
1140             // focus is currently on notebook tab and should leave 
1141             // it backwards (Shift-TAB) 
1142             event
.SetCurrentFocus(this); 
1143             parent
->HandleWindowEvent(event
); 
1145         else if ( isFromParent 
|| isFromSelf 
) 
1147             // no, it doesn't come from child, case (b) or (c): forward to a 
1148             // page but only if entering notebook page (i.e. direction is 
1149             // backwards (Shift-TAB) comething from out-of-notebook, or 
1150             // direction is forward (TAB) from ourselves), 
1151             if ( m_selection 
!= wxNOT_FOUND 
&& 
1152                     (!event
.GetDirection() || isFromSelf
) ) 
1154                 // so that the page knows that the event comes from it's parent 
1155                 // and is being propagated downwards 
1156                 event
.SetEventObject(this); 
1158                 wxWindow 
*page 
= m_pages
[m_selection
]; 
1159                 if ( !page
->HandleWindowEvent(event
) ) 
1163                 //else: page manages focus inside it itself 
1165             else // otherwise set the focus to the notebook itself 
1172             // it comes from our child, case (a), pass to the parent, but only 
1173             // if the direction is forwards. Otherwise set the focus to the 
1174             // notebook itself. The notebook is always the 'first' control of a 
1182                 event
.SetCurrentFocus(this); 
1183                 parent
->HandleWindowEvent(event
); 
1191 bool wxNotebook::DoDrawBackground(WXHDC hDC
, wxWindow 
*child
) 
1193     wxUxThemeHandle 
theme(child 
? child 
: this, L
"TAB"); 
1197     // get the notebook client rect (we're not interested in drawing tabs 
1199     wxRect r 
= GetPageSize(); 
1204     wxCopyRectToRECT(r
, rc
); 
1206     // map rect to the coords of the window we're drawing in 
1208         ::MapWindowPoints(GetHwnd(), GetHwndOf(child
), (POINT 
*)&rc
, 2); 
1210     // we have the content area (page size), but we need to draw all of the 
1211     // background for it to be aligned correctly 
1212     wxUxThemeEngine::Get()->GetThemeBackgroundExtent
 
1221     wxUxThemeEngine::Get()->DrawThemeBackground
 
1234 WXHBRUSH 
wxNotebook::QueryBgBitmap() 
1236     wxRect r 
= GetPageSize(); 
1240     WindowHDC 
hDC(GetHwnd()); 
1241     MemoryHDC 
hDCMem(hDC
); 
1242     CompatibleBitmap 
hBmp(hDC
, r
.x 
+ r
.width
, r
.y 
+ r
.height
); 
1244     SelectInHDC 
selectBmp(hDCMem
, hBmp
); 
1246     if ( !DoDrawBackground((WXHDC
)(HDC
)hDCMem
) ) 
1249     return (WXHBRUSH
)::CreatePatternBrush(hBmp
); 
1252 void wxNotebook::UpdateBgBrush() 
1254     if ( m_hbrBackground 
) 
1255         ::DeleteObject((HBRUSH
)m_hbrBackground
); 
1257     if ( !m_hasBgCol 
&& wxUxThemeEngine::GetIfActive() ) 
1259         m_hbrBackground 
= QueryBgBitmap(); 
1261     else // no themes or we've got user-defined solid colour 
1263         m_hbrBackground 
= NULL
; 
1267 WXHBRUSH 
wxNotebook::MSWGetBgBrushForChild(WXHDC hDC
, wxWindow 
*child
) 
1269     if ( m_hbrBackground 
) 
1271         // before drawing with the background brush, we need to position it 
1274         ::GetWindowRect(GetHwndOf(child
), &rc
); 
1276         ::MapWindowPoints(NULL
, GetHwnd(), (POINT 
*)&rc
, 1); 
1278         if ( !::SetBrushOrgEx((HDC
)hDC
, -rc
.left
, -rc
.top
, NULL
) ) 
1280             wxLogLastError(wxT("SetBrushOrgEx(notebook bg brush)")); 
1283         return m_hbrBackground
; 
1286     return wxNotebookBase::MSWGetBgBrushForChild(hDC
, child
); 
1289 bool wxNotebook::MSWPrintChild(WXHDC hDC
, wxWindow 
*child
) 
1291     // solid background colour overrides themed background drawing 
1292     if ( !UseBgCol() && DoDrawBackground(hDC
, child
) ) 
1295     // If we're using a solid colour (for example if we've switched off 
1296     // theming for this notebook), paint it 
1299         wxRect r 
= GetPageSize(); 
1304         wxCopyRectToRECT(r
, rc
); 
1306         // map rect to the coords of the window we're drawing in 
1308             ::MapWindowPoints(GetHwnd(), GetHwndOf(child
), (POINT 
*)&rc
, 2); 
1310         wxBrush 
brush(GetBackgroundColour()); 
1311         HBRUSH hbr 
= GetHbrushOf(brush
); 
1313         ::FillRect((HDC
) hDC
, &rc
, hbr
); 
1318     return wxNotebookBase::MSWPrintChild(hDC
, child
); 
1321 #endif // wxUSE_UXTHEME 
1323 // Windows only: attempts to get colour for UX theme page background 
1324 wxColour 
wxNotebook::GetThemeBackgroundColour() const 
1327     if (wxUxThemeEngine::Get()) 
1329         wxUxThemeHandle 
hTheme((wxNotebook
*) this, L
"TAB"); 
1332             // This is total guesswork. 
1333             // See PlatformSDK\Include\Tmschema.h for values. 
1334             // JACS: can also use 9 (TABP_PANE) 
1335             COLORREF themeColor
; 
1336             bool success 
= (S_OK 
== wxUxThemeEngine::Get()->GetThemeColor( 
1340                                         3821 /* FILLCOLORHINT */, 
1343                 return GetBackgroundColour(); 
1346             [DS] Workaround for WindowBlinds: 
1347             Some themes return a near black theme color using FILLCOLORHINT, 
1348             this makes notebook pages have an ugly black background and makes 
1349             text (usually black) unreadable. Retry again with FILLCOLOR. 
1351             This workaround potentially breaks appearance of some themes, 
1352             but in practice it already fixes some themes. 
1354             if (themeColor 
== 1) 
1356                 wxUxThemeEngine::Get()->GetThemeColor( 
1360                                             3802 /* FILLCOLOR */, 
1364             wxColour colour 
= wxRGBToColour(themeColor
); 
1366             // Under Vista, the tab background colour is reported incorrectly. 
1367             // So for the default theme at least, hard-code the colour to something 
1368             // that will blend in. 
1370             static int s_AeroStatus 
= -1; 
1371             if (s_AeroStatus 
== -1) 
1373                 WCHAR szwThemeFile
[1024]; 
1374                 WCHAR szwThemeColor
[256]; 
1375                 if (S_OK 
== wxUxThemeEngine::Get()->GetCurrentThemeName(szwThemeFile
, 1024, szwThemeColor
, 256, NULL
, 0)) 
1377                     wxString 
themeFile(szwThemeFile
), themeColor(szwThemeColor
); 
1378                     if (themeFile
.Find(wxT("Aero")) != -1 && themeColor 
== wxT("NormalColor")) 
1387             if (s_AeroStatus 
== 1) 
1388                 colour 
= wxColour(255, 255, 255); 
1393 #endif // wxUSE_UXTHEME 
1395     return GetBackgroundColour(); 
1398 // ---------------------------------------------------------------------------- 
1399 // wxNotebook base class virtuals 
1400 // ---------------------------------------------------------------------------- 
1402 #if wxUSE_CONSTRAINTS 
1404 // override these 2 functions to do nothing: everything is done in OnSize 
1406 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
)) 
1408   // don't set the sizes of the pages - their correct size is not yet known 
1409   wxControl::SetConstraintSizes(false); 
1412 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
)) 
1417 #endif // wxUSE_CONSTRAINTS 
1419 // ---------------------------------------------------------------------------- 
1420 // wxNotebook Windows message handlers 
1421 // ---------------------------------------------------------------------------- 
1423 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
, 
1424                              WXWORD pos
, WXHWND control
) 
1426     // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the 
1431     return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
); 
1434 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
) 
1436   wxBookCtrlEvent 
event(wxEVT_NULL
, m_windowId
); 
1438   NMHDR
* hdr 
= (NMHDR 
*)lParam
; 
1439   switch ( hdr
->code 
) { 
1441       event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
); 
1444     case TCN_SELCHANGING
: 
1445       event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
); 
1449       return wxControl::MSWOnNotify(idCtrl
, lParam
, result
); 
1452   event
.SetSelection(TabCtrl_GetCurSel(GetHwnd())); 
1453   event
.SetOldSelection(m_selection
); 
1454   event
.SetEventObject(this); 
1455   event
.SetInt(idCtrl
); 
1457   bool processed 
= HandleWindowEvent(event
); 
1458   *result 
= !event
.IsAllowed(); 
1462 #endif // wxUSE_NOTEBOOK