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() 
 243     m_nSelection 
= wxNOT_FOUND
; 
 246     m_hbrBackground 
= NULL
; 
 247 #endif // wxUSE_UXTHEME 
 249 #if USE_NOTEBOOK_ANTIFLICKER 
 250     m_hasSubclassedUpdown 
= false; 
 251 #endif // USE_NOTEBOOK_ANTIFLICKER 
 254 // default for dynamic class 
 255 wxNotebook::wxNotebook() 
 260 // the same arguments as for wxControl 
 261 wxNotebook::wxNotebook(wxWindow 
*parent
, 
 266                        const wxString
& name
) 
 270   Create(parent
, id
, pos
, size
, style
, name
); 
 274 bool wxNotebook::Create(wxWindow 
*parent
, 
 279                         const wxString
& name
) 
 281     if ( (style 
& wxBK_ALIGN_MASK
) == wxBK_DEFAULT 
) 
 283 #if defined(__POCKETPC__) 
 284         style 
|= wxBK_BOTTOM 
| wxNB_FLAT
; 
 291     // Not sure why, but without this style, there is no border 
 292     // around the notebook tabs. 
 293     if (style 
& wxNB_FLAT
) 
 294         style 
|= wxBORDER_SUNKEN
; 
 298     // ComCtl32 notebook tabs simply don't work unless they're on top if we 
 299     // have uxtheme, we can work around it later (after control creation), but 
 300     // if we have been compiled without uxtheme support, we have to clear those 
 302     if ( HasTroubleWithNonTopTabs() ) 
 304         style 
&= ~(wxBK_BOTTOM 
| wxBK_LEFT 
| wxBK_RIGHT
); 
 306 #endif //wxUSE_UXTHEME 
 308 #if defined(__WINE__) && wxUSE_UNICODE 
 309     LPCTSTR className 
= L
"SysTabControl32"; 
 311     LPCTSTR className 
= WC_TABCONTROL
; 
 314 #if USE_NOTEBOOK_ANTIFLICKER 
 315     // SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it 
 316     // causes horrible flicker when resizing notebook, so get rid of it by 
 317     // using a class without these styles (but otherwise identical to it) 
 318     if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) ) 
 320         static ClassRegistrar s_clsNotebook
; 
 321         if ( !s_clsNotebook
.IsInitialized() ) 
 323             // get a copy of standard class and modify it 
 326             if ( ::GetClassInfo(NULL
, WC_TABCONTROL
, &wc
) ) 
 329                     reinterpret_cast<WXFARPROC
>(wc
.lpfnWndProc
); 
 330                 wc
.lpszClassName 
= wxT("_wx_SysTabCtl32"); 
 331                 wc
.style 
&= ~(CS_HREDRAW 
| CS_VREDRAW
); 
 332                 wc
.hInstance 
= wxGetInstance(); 
 333                 wc
.lpfnWndProc 
= wxNotebookWndProc
; 
 334                 s_clsNotebook
.Register(wc
); 
 338                 wxLogLastError(wxT("GetClassInfoEx(SysTabCtl32)")); 
 342         // use our custom class if available but fall back to the standard 
 343         // notebook if we failed to register it 
 344         if ( s_clsNotebook
.IsRegistered() ) 
 346             // it's ok to use c_str() here as the static s_clsNotebook object 
 347             // has sufficiently long lifetime 
 348             className 
= s_clsNotebook
.GetName().c_str(); 
 351 #endif // USE_NOTEBOOK_ANTIFLICKER 
 353     if ( !CreateControl(parent
, id
, pos
, size
, style 
| wxTAB_TRAVERSAL
, 
 354                         wxDefaultValidator
, name
) ) 
 357     if ( !MSWCreateControl(className
, wxEmptyString
, pos
, size
) ) 
 361     if ( HasFlag(wxNB_NOPAGETHEME
) || 
 362             wxSystemOptions::IsFalse(wxT("msw.notebook.themed-background")) ) 
 364         SetBackgroundColour(GetThemeBackgroundColour()); 
 366     else // use themed background by default 
 368         // create backing store 
 372     // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the 
 373     // control is simply not rendered correctly), so we disable themes 
 374     // if possible, otherwise we simply clear the styles. 
 375     if ( HasTroubleWithNonTopTabs() && 
 376             (style 
& (wxBK_BOTTOM 
| wxBK_LEFT 
| wxBK_RIGHT
)) ) 
 378         // check if we use themes at all -- if we don't, we're still okay 
 379         if ( wxUxThemeEngine::GetIfActive() ) 
 381             wxUxThemeEngine::GetIfActive()->SetWindowTheme(GetHwnd(), L
"", L
""); 
 383             // correct the background color for the new non-themed control 
 384             SetBackgroundColour(GetThemeBackgroundColour()); 
 387 #endif // wxUSE_UXTHEME 
 389     // Undocumented hack to get flat notebook style 
 390     // In fact, we should probably only do this in some 
 391     // curcumstances, i.e. if we know we will have a border 
 392     // at the bottom (the tab control doesn't draw it itself) 
 393 #if defined(__POCKETPC__) || defined(__SMARTPHONE__) 
 394     if (HasFlag(wxNB_FLAT
)) 
 396         SendMessage(GetHwnd(), CCM_SETVERSION
, COMCTL32_VERSION
, 0); 
 398             SetBackgroundColour(*wxWHITE
); 
 404 WXDWORD 
wxNotebook::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 406     WXDWORD tabStyle 
= wxControl::MSWGetStyle(style
, exstyle
); 
 408     tabStyle 
|= WS_TABSTOP 
| TCS_TABS
; 
 410     if ( style 
& wxNB_MULTILINE 
) 
 411         tabStyle 
|= TCS_MULTILINE
; 
 412     if ( style 
& wxNB_FIXEDWIDTH 
) 
 413         tabStyle 
|= TCS_FIXEDWIDTH
; 
 415     if ( style 
& wxBK_BOTTOM 
) 
 416         tabStyle 
|= TCS_RIGHT
; 
 417     else if ( style 
& wxBK_LEFT 
) 
 418         tabStyle 
|= TCS_VERTICAL
; 
 419     else if ( style 
& wxBK_RIGHT 
) 
 420         tabStyle 
|= TCS_VERTICAL 
| TCS_RIGHT
; 
 425 wxNotebook::~wxNotebook() 
 428     if ( m_hbrBackground 
) 
 429         ::DeleteObject((HBRUSH
)m_hbrBackground
); 
 430 #endif // wxUSE_UXTHEME 
 433 // ---------------------------------------------------------------------------- 
 434 // wxNotebook accessors 
 435 // ---------------------------------------------------------------------------- 
 437 size_t wxNotebook::GetPageCount() const 
 440     wxASSERT( (int)m_pages
.Count() == TabCtrl_GetItemCount(GetHwnd()) ); 
 442     return m_pages
.Count(); 
 445 int wxNotebook::GetRowCount() const 
 447     return TabCtrl_GetRowCount(GetHwnd()); 
 450 int wxNotebook::SetSelection(size_t nPage
) 
 452     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 454     if ( m_nSelection 
== wxNOT_FOUND 
|| nPage 
!= (size_t)m_nSelection 
) 
 456         if ( SendPageChangingEvent(nPage
) ) 
 458             // program allows the page change 
 459             SendPageChangedEvent(m_nSelection
, nPage
); 
 461             TabCtrl_SetCurSel(GetHwnd(), nPage
); 
 468 void wxNotebook::UpdateSelection(int selNew
) 
 470     if ( m_nSelection 
!= wxNOT_FOUND 
) 
 471         m_pages
[m_nSelection
]->Show(false); 
 473     if ( selNew 
!= wxNOT_FOUND 
) 
 475         wxNotebookPage 
*pPage 
= m_pages
[selNew
]; 
 479     // Changing the page should give the focus to it but, as per bug report 
 480     // http://sf.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863, 
 481     // we should not set the focus to it directly since it erroneously 
 482     // selects radio buttons and breaks keyboard handling for a notebook's 
 483     // scroll buttons. So give focus to the notebook and not the page. 
 485     // but don't do this is the notebook is hidden 
 486     if ( ::IsWindowVisible(GetHwnd()) ) 
 489     m_nSelection 
= selNew
; 
 492 int wxNotebook::ChangeSelection(size_t nPage
) 
 494     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 496     const int selOld 
= m_nSelection
; 
 498     if ( m_nSelection 
== wxNOT_FOUND 
|| nPage 
!= (size_t)m_nSelection 
) 
 500         TabCtrl_SetCurSel(GetHwnd(), nPage
); 
 502         UpdateSelection(nPage
); 
 508 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
) 
 510     wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") ); 
 513     tcItem
.mask 
= TCIF_TEXT
; 
 514     tcItem
.pszText 
= (wxChar 
*)strText
.wx_str(); 
 516     if ( !HasFlag(wxNB_MULTILINE
) ) 
 517         return TabCtrl_SetItem(GetHwnd(), nPage
, &tcItem
) != 0; 
 519     // multiline - we need to set new page size if a line is added or removed 
 520     int rows 
= GetRowCount(); 
 521     bool ret 
= TabCtrl_SetItem(GetHwnd(), nPage
, &tcItem
) != 0; 
 523     if ( ret 
&& rows 
!= GetRowCount() ) 
 525         const wxRect r 
= GetPageSize(); 
 526         const size_t count 
= m_pages
.Count(); 
 527         for ( size_t page 
= 0; page 
< count
; page
++ ) 
 528             m_pages
[page
]->SetSize(r
); 
 534 wxString 
wxNotebook::GetPageText(size_t nPage
) const 
 536     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") ); 
 540     tcItem
.mask 
= TCIF_TEXT
; 
 541     tcItem
.pszText 
= buf
; 
 542     tcItem
.cchTextMax 
= WXSIZEOF(buf
); 
 545     if ( TabCtrl_GetItem(GetHwnd(), nPage
, &tcItem
) ) 
 546         str 
= tcItem
.pszText
; 
 551 int wxNotebook::GetPageImage(size_t nPage
) const 
 553     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 556     tcItem
.mask 
= TCIF_IMAGE
; 
 558     return TabCtrl_GetItem(GetHwnd(), nPage
, &tcItem
) ? tcItem
.iImage
 
 562 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
) 
 564     wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") ); 
 567     tcItem
.mask 
= TCIF_IMAGE
; 
 568     tcItem
.iImage 
= nImage
; 
 570     return TabCtrl_SetItem(GetHwnd(), nPage
, &tcItem
) != 0; 
 573 void wxNotebook::SetImageList(wxImageList
* imageList
) 
 575     wxNotebookBase::SetImageList(imageList
); 
 579         (void) TabCtrl_SetImageList(GetHwnd(), GetHimagelistOf(imageList
)); 
 583 // ---------------------------------------------------------------------------- 
 584 // wxNotebook size settings 
 585 // ---------------------------------------------------------------------------- 
 587 wxRect 
wxNotebook::GetPageSize() const 
 592     ::GetClientRect(GetHwnd(), &rc
); 
 594     // This check is to work around a bug in TabCtrl_AdjustRect which will 
 595     // cause a crash on win2k or on XP with themes disabled if either 
 596     // wxNB_MULTILINE is used or tabs are placed on a side, if the rectangle 
 599     // The value of 20 is chosen arbitrarily but seems to work 
 600     if ( rc
.right 
> 20 && rc
.bottom 
> 20 ) 
 602         TabCtrl_AdjustRect(GetHwnd(), false, &rc
); 
 604         wxCopyRECTToRect(rc
, r
); 
 610 void wxNotebook::SetPageSize(const wxSize
& size
) 
 612     // transform the page size into the notebook size 
 619     TabCtrl_AdjustRect(GetHwnd(), true, &rc
); 
 622     SetSize(rc
.right 
- rc
.left
, rc
.bottom 
- rc
.top
); 
 625 void wxNotebook::SetPadding(const wxSize
& padding
) 
 627     TabCtrl_SetPadding(GetHwnd(), padding
.x
, padding
.y
); 
 630 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH 
 632 void wxNotebook::SetTabSize(const wxSize
& sz
) 
 634     ::SendMessage(GetHwnd(), TCM_SETITEMSIZE
, 0, MAKELPARAM(sz
.x
, sz
.y
)); 
 637 wxSize 
wxNotebook::CalcSizeFromPage(const wxSize
& sizePage
) const 
 639     // we can't use TabCtrl_AdjustRect here because it only works for wxNB_TOP 
 640     wxSize sizeTotal 
= sizePage
; 
 643     if ( GetPageCount() > 0 ) 
 646         TabCtrl_GetItemRect(GetHwnd(), 0, &rect
); 
 647         tabSize
.x 
= rect
.right 
- rect
.left
; 
 648         tabSize
.y 
= rect
.bottom 
- rect
.top
; 
 651     const int rows 
= GetRowCount(); 
 653     // add an extra margin in both directions 
 654     const int MARGIN 
= 8; 
 657         sizeTotal
.x 
+= MARGIN
; 
 658         sizeTotal
.y 
+= tabSize
.y 
* rows 
+ MARGIN
; 
 660     else // horizontal layout 
 662         sizeTotal
.x 
+= tabSize
.x 
* rows 
+ MARGIN
; 
 663         sizeTotal
.y 
+= MARGIN
; 
 669 void wxNotebook::AdjustPageSize(wxNotebookPage 
*page
) 
 671     wxCHECK_RET( page
, wxT("NULL page in wxNotebook::AdjustPageSize") ); 
 673     const wxRect r 
= GetPageSize(); 
 680 // ---------------------------------------------------------------------------- 
 681 // wxNotebook operations 
 682 // ---------------------------------------------------------------------------- 
 684 // remove one page from the notebook, without deleting 
 685 wxNotebookPage 
*wxNotebook::DoRemovePage(size_t nPage
) 
 687     wxNotebookPage 
*pageRemoved 
= wxNotebookBase::DoRemovePage(nPage
); 
 691     // hide the removed page to maintain the invariant that only the 
 692     // selected page is visible and others are hidden: 
 693     pageRemoved
->Show(false); 
 695     TabCtrl_DeleteItem(GetHwnd(), nPage
); 
 697     if ( m_pages
.IsEmpty() ) 
 699         // no selection any more, the notebook becamse empty 
 700         m_nSelection 
= wxNOT_FOUND
; 
 702     else // notebook still not empty 
 704         int selNew 
= TabCtrl_GetCurSel(GetHwnd()); 
 705         if ( selNew 
!= wxNOT_FOUND 
) 
 707             // No selection change, just refresh the current selection. 
 708             // Because it could be that the slection index changed 
 709             // we need to update it. 
 710             // Note: this does not mean the selection it self changed. 
 711             m_nSelection 
= selNew
; 
 712             m_pages
[m_nSelection
]->Refresh(); 
 714         else if (int(nPage
) == m_nSelection
) 
 716             // The selection was deleted. 
 718             // Determine new selection. 
 719             if (m_nSelection 
== int(GetPageCount())) 
 720                 selNew 
= m_nSelection 
- 1; 
 722                 selNew 
= m_nSelection
; 
 724             // m_nSelection must be always valid so reset it before calling 
 726             m_nSelection 
= wxNOT_FOUND
; 
 727             SetSelection(selNew
); 
 731             wxFAIL
; // Windows did not behave ok. 
 739 bool wxNotebook::DeleteAllPages() 
 741     size_t nPageCount 
= GetPageCount(); 
 743     for ( nPage 
= 0; nPage 
< nPageCount
; nPage
++ ) 
 744         delete m_pages
[nPage
]; 
 748     TabCtrl_DeleteAllItems(GetHwnd()); 
 750     m_nSelection 
= wxNOT_FOUND
; 
 752     InvalidateBestSize(); 
 756 // same as AddPage() but does it at given position 
 757 bool wxNotebook::InsertPage(size_t nPage
, 
 758                             wxNotebookPage 
*pPage
, 
 759                             const wxString
& strText
, 
 763     wxCHECK_MSG( pPage 
!= NULL
, false, wxT("NULL page in wxNotebook::InsertPage") ); 
 764     wxCHECK_MSG( IS_VALID_PAGE(nPage
) || nPage 
== GetPageCount(), false, 
 765                  wxT("invalid index in wxNotebook::InsertPage") ); 
 767     wxASSERT_MSG( pPage
->GetParent() == this, 
 768                     wxT("notebook pages must have notebook as parent") ); 
 770     // add a new tab to the control 
 771     // ---------------------------- 
 773     // init all fields to 0 
 775     wxZeroMemory(tcItem
); 
 777     // set the image, if any 
 780         tcItem
.mask 
|= TCIF_IMAGE
; 
 781         tcItem
.iImage  
= imageId
; 
 785     if ( !strText
.empty() ) 
 787         tcItem
.mask 
|= TCIF_TEXT
; 
 788         tcItem
.pszText 
= (wxChar 
*)strText
.wx_str(); // const_cast 
 791     // hide the page: unless it is selected, it shouldn't be shown (and if it 
 792     // is selected it will be shown later) 
 793     HWND hwnd 
= GetWinHwnd(pPage
); 
 794     SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~WS_VISIBLE
); 
 796     // this updates internal flag too -- otherwise it would get out of sync 
 797     // with the real state 
 801     // fit the notebook page to the tab control's display area: this should be 
 802     // done before adding it to the notebook or TabCtrl_InsertItem() will 
 803     // change the notebooks size itself! 
 804     AdjustPageSize(pPage
); 
 806     // finally do insert it 
 807     if ( TabCtrl_InsertItem(GetHwnd(), nPage
, &tcItem
) == -1 ) 
 809         wxLogError(wxT("Can't create the notebook page '%s'."), strText
.c_str()); 
 814     // need to update the bg brush when the first page is added 
 815     // so the first panel gets the correct themed background 
 816     if ( m_pages
.empty() ) 
 820 #endif // wxUSE_UXTHEME 
 823     // succeeded: save the pointer to the page 
 824     m_pages
.Insert(pPage
, nPage
); 
 826     // we may need to adjust the size again if the notebook size changed: 
 827     // normally this only happens for the first page we add (the tabs which 
 828     // hadn't been there before are now shown) but for a multiline notebook it 
 829     // can happen for any page at all as a new row could have been started 
 830     if ( m_pages
.GetCount() == 1 || HasFlag(wxNB_MULTILINE
) ) 
 832         AdjustPageSize(pPage
); 
 835     // now deal with the selection 
 836     // --------------------------- 
 838     // if the inserted page is before the selected one, we must update the 
 839     // index of the selected page 
 840     if ( int(nPage
) <= m_nSelection 
) 
 842         // one extra page added 
 846     // some page should be selected: either this one or the first one if there 
 847     // is still no selection 
 848     int selNew 
= wxNOT_FOUND
; 
 851     else if ( m_nSelection 
== wxNOT_FOUND 
) 
 854     if ( selNew 
!= wxNOT_FOUND 
) 
 855         SetSelection(selNew
); 
 857     InvalidateBestSize(); 
 862 int wxNotebook::HitTest(const wxPoint
& pt
, long *flags
) const 
 864     TC_HITTESTINFO hitTestInfo
; 
 865     hitTestInfo
.pt
.x 
= pt
.x
; 
 866     hitTestInfo
.pt
.y 
= pt
.y
; 
 867     int item 
= TabCtrl_HitTest(GetHwnd(), &hitTestInfo
); 
 873         if ((hitTestInfo
.flags 
& TCHT_NOWHERE
) == TCHT_NOWHERE
) 
 874             *flags 
|= wxBK_HITTEST_NOWHERE
; 
 875         if ((hitTestInfo
.flags 
& TCHT_ONITEM
) == TCHT_ONITEM
) 
 876             *flags 
|= wxBK_HITTEST_ONITEM
; 
 877         if ((hitTestInfo
.flags 
& TCHT_ONITEMICON
) == TCHT_ONITEMICON
) 
 878             *flags 
|= wxBK_HITTEST_ONICON
; 
 879         if ((hitTestInfo
.flags 
& TCHT_ONITEMLABEL
) == TCHT_ONITEMLABEL
) 
 880             *flags 
|= wxBK_HITTEST_ONLABEL
; 
 881         if ( item 
== wxNOT_FOUND 
&& GetPageSize().Contains(pt
) ) 
 882             *flags 
|= wxBK_HITTEST_ONPAGE
; 
 888 // ---------------------------------------------------------------------------- 
 889 // flicker-less notebook redraw 
 890 // ---------------------------------------------------------------------------- 
 892 #if USE_NOTEBOOK_ANTIFLICKER 
 894 // wnd proc for the spin button 
 895 LRESULT APIENTRY _EXPORT 
wxNotebookSpinBtnWndProc(HWND hwnd
, 
 900     if ( message 
== WM_ERASEBKGND 
) 
 903     return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebookSpinBtn
, 
 904                             hwnd
, message
, wParam
, lParam
); 
 907 LRESULT APIENTRY _EXPORT 
wxNotebookWndProc(HWND hwnd
, 
 912     return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebook
, 
 913                             hwnd
, message
, wParam
, lParam
); 
 916 void wxNotebook::OnEraseBackground(wxEraseEvent
& WXUNUSED(event
)) 
 921 void wxNotebook::OnPaint(wxPaintEvent
& WXUNUSED(event
)) 
 926     ::GetClientRect(GetHwnd(), &rc
); 
 927     wxBitmap 
bmp(rc
.right
, rc
.bottom
); 
 928     memdc
.SelectObject(bmp
); 
 930     const wxLayoutDirection dir 
= dc
.GetLayoutDirection(); 
 931     memdc
.SetLayoutDirection(dir
); 
 933     // if there is no special brush just use the solid background colour 
 935     HBRUSH hbr 
= (HBRUSH
)m_hbrBackground
; 
 942         brush 
= wxBrush(GetBackgroundColour()); 
 943         hbr 
= GetHbrushOf(brush
); 
 946     wxMSWDCImpl 
*impl 
= (wxMSWDCImpl
*) memdc
.GetImpl(); 
 948     ::FillRect(GetHdcOf(*impl
), &rc
, hbr
); 
 950     MSWDefWindowProc(WM_PAINT
, (WPARAM
)(impl
->GetHDC()), 0); 
 952     // For some reason in RTL mode, source offset has to be -1, otherwise the 
 953     // right border (physical) remains unpainted. 
 954     const wxCoord ofs 
= dir 
== wxLayout_RightToLeft 
? -1 : 0; 
 955     dc
.Blit(ofs
, 0, rc
.right
, rc
.bottom
, &memdc
, ofs
, 0); 
 958 #endif // USE_NOTEBOOK_ANTIFLICKER 
 960 // ---------------------------------------------------------------------------- 
 961 // wxNotebook callbacks 
 962 // ---------------------------------------------------------------------------- 
 964 void wxNotebook::OnSize(wxSizeEvent
& event
) 
 966     if ( GetPageCount() == 0 ) 
 968         // Prevents droppings on resize, but does cause some flicker 
 969         // when there are no pages. 
 977         // Without this, we can sometimes get droppings at the edges 
 978         // of a notebook, for example a notebook in a splitter window. 
 979         // This needs to be reconciled with the RefreshRect calls 
 980         // at the end of this function, which weren't enough to prevent 
 983         wxSize sz 
= GetClientSize(); 
 985         // Refresh right side 
 986         wxRect 
rect(sz
.x
-4, 0, 4, sz
.y
); 
 989         // Refresh bottom side 
 990         rect 
= wxRect(0, sz
.y
-4, sz
.x
, 4); 
 994         rect 
= wxRect(0, 0, 4, sz
.y
); 
 997 #endif // !__WXWINCE__ 
 999     // fit all the notebook pages to the tab control's display area 
1002     rc
.left 
= rc
.top 
= 0; 
1003     GetSize((int *)&rc
.right
, (int *)&rc
.bottom
); 
1005     // save the total size, we'll use it below 
1006     int widthNbook 
= rc
.right 
- rc
.left
, 
1007         heightNbook 
= rc
.bottom 
- rc
.top
; 
1009     // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it 
1010     // returns completely false values for multiline tab controls after the tabs 
1011     // are added but before getting the first WM_SIZE (off by ~50 pixels, see 
1013     // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863 
1015     // and the only work around I could find was this ugly hack... without it 
1016     // simply toggling the "multiline" checkbox in the notebook sample resulted 
1017     // in a noticeable page displacement 
1018     if ( HasFlag(wxNB_MULTILINE
) ) 
1020         // avoid an infinite recursion: we get another notification too! 
1021         static bool s_isInOnSize 
= false; 
1023         if ( !s_isInOnSize 
) 
1025             s_isInOnSize 
= true; 
1026             SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
, 
1027                     MAKELPARAM(rc
.right
, rc
.bottom
)); 
1028             s_isInOnSize 
= false; 
1031         // The best size depends on the number of rows of tabs, which can 
1032         // change when the notepad is resized. 
1033         InvalidateBestSize(); 
1037     // background bitmap size has changed, update the brush using it too 
1039 #endif // wxUSE_UXTHEME 
1041     TabCtrl_AdjustRect(GetHwnd(), false, &rc
); 
1043     int width 
= rc
.right 
- rc
.left
, 
1044         height 
= rc
.bottom 
- rc
.top
; 
1045     size_t nCount 
= m_pages
.Count(); 
1046     for ( size_t nPage 
= 0; nPage 
< nCount
; nPage
++ ) { 
1047         wxNotebookPage 
*pPage 
= m_pages
[nPage
]; 
1048         pPage
->SetSize(rc
.left
, rc
.top
, width
, height
); 
1052     // unless we had already repainted everything, we now need to refresh 
1053     if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) ) 
1055         // invalidate areas not covered by pages 
1056         RefreshRect(wxRect(0, 0, widthNbook
, rc
.top
), false); 
1057         RefreshRect(wxRect(0, rc
.top
, rc
.left
, height
), false); 
1058         RefreshRect(wxRect(0, rc
.bottom
, widthNbook
, heightNbook 
- rc
.bottom
), 
1060         RefreshRect(wxRect(rc
.right
, rc
.top
, widthNbook 
- rc
.right
, height
), 
1064 #if USE_NOTEBOOK_ANTIFLICKER 
1065     // subclass the spin control used by the notebook to scroll pages to 
1066     // prevent it from flickering on resize 
1067     if ( !m_hasSubclassedUpdown 
) 
1069         // iterate over all child windows to find spin button 
1070         for ( HWND child 
= ::GetWindow(GetHwnd(), GW_CHILD
); 
1072               child 
= ::GetWindow(child
, GW_HWNDNEXT
) ) 
1074             wxWindow 
*childWindow 
= wxFindWinFromHandle((WXHWND
)child
); 
1076             // see if it exists, if no wxWindow found then assume it's the spin 
1080                 // subclass the spin button to override WM_ERASEBKGND 
1081                 if ( !gs_wndprocNotebookSpinBtn 
) 
1082                     gs_wndprocNotebookSpinBtn 
= (WXFARPROC
)wxGetWindowProc(child
); 
1084                 wxSetWindowProc(child
, wxNotebookSpinBtnWndProc
); 
1085                 m_hasSubclassedUpdown 
= true; 
1090 #endif // USE_NOTEBOOK_ANTIFLICKER 
1095 void wxNotebook::OnSelChange(wxBookCtrlEvent
& event
) 
1097     // is it our tab control? 
1098     if ( event
.GetEventObject() == this ) 
1100         UpdateSelection(event
.GetSelection()); 
1103     // we want to give others a chance to process this message as well 
1107 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
) 
1109     if ( event
.IsWindowChange() ) { 
1111         AdvanceSelection(event
.GetDirection()); 
1114         // we get this event in 3 cases 
1116         // a) one of our pages might have generated it because the user TABbed 
1117         // out from it in which case we should propagate the event upwards and 
1118         // our parent will take care of setting the focus to prev/next sibling 
1122         // b) the parent panel wants to give the focus to us so that we 
1123         // forward it to our selected page. We can't deal with this in 
1124         // OnSetFocus() because we don't know which direction the focus came 
1125         // from in this case and so can't choose between setting the focus to 
1126         // first or last panel child 
1130         // c) we ourselves (see MSWTranslateMessage) generated the event 
1132         wxWindow 
* const parent 
= GetParent(); 
1134         // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE 
1135         const bool isFromParent 
= event
.GetEventObject() == (wxObject
*) parent
; 
1136         const bool isFromSelf 
= event
.GetEventObject() == (wxObject
*) this; 
1137         const bool isForward 
= event
.GetDirection(); 
1139         if ( isFromSelf 
&& !isForward 
) 
1141             // focus is currently on notebook tab and should leave 
1142             // it backwards (Shift-TAB) 
1143             event
.SetCurrentFocus(this); 
1144             parent
->HandleWindowEvent(event
); 
1146         else if ( isFromParent 
|| isFromSelf 
) 
1148             // no, it doesn't come from child, case (b) or (c): forward to a 
1149             // page but only if entering notebook page (i.e. direction is 
1150             // backwards (Shift-TAB) comething from out-of-notebook, or 
1151             // direction is forward (TAB) from ourselves), 
1152             if ( m_nSelection 
!= wxNOT_FOUND 
&& 
1153                     (!event
.GetDirection() || isFromSelf
) ) 
1155                 // so that the page knows that the event comes from it's parent 
1156                 // and is being propagated downwards 
1157                 event
.SetEventObject(this); 
1159                 wxWindow 
*page 
= m_pages
[m_nSelection
]; 
1160                 if ( !page
->HandleWindowEvent(event
) ) 
1164                 //else: page manages focus inside it itself 
1166             else // otherwise set the focus to the notebook itself 
1173             // it comes from our child, case (a), pass to the parent, but only 
1174             // if the direction is forwards. Otherwise set the focus to the 
1175             // notebook itself. The notebook is always the 'first' control of a 
1183                 event
.SetCurrentFocus(this); 
1184                 parent
->HandleWindowEvent(event
); 
1192 bool wxNotebook::DoDrawBackground(WXHDC hDC
, wxWindow 
*child
) 
1194     wxUxThemeHandle 
theme(child 
? child 
: this, L
"TAB"); 
1198     // get the notebook client rect (we're not interested in drawing tabs 
1200     wxRect r 
= GetPageSize(); 
1205     wxCopyRectToRECT(r
, rc
); 
1207     // map rect to the coords of the window we're drawing in 
1209         ::MapWindowPoints(GetHwnd(), GetHwndOf(child
), (POINT 
*)&rc
, 2); 
1211     // we have the content area (page size), but we need to draw all of the 
1212     // background for it to be aligned correctly 
1213     wxUxThemeEngine::Get()->GetThemeBackgroundExtent
 
1222     wxUxThemeEngine::Get()->DrawThemeBackground
 
1235 WXHBRUSH 
wxNotebook::QueryBgBitmap() 
1237     wxRect r 
= GetPageSize(); 
1241     WindowHDC 
hDC(GetHwnd()); 
1242     MemoryHDC 
hDCMem(hDC
); 
1243     CompatibleBitmap 
hBmp(hDC
, r
.x 
+ r
.width
, r
.y 
+ r
.height
); 
1245     SelectInHDC 
selectBmp(hDCMem
, hBmp
); 
1247     if ( !DoDrawBackground((WXHDC
)(HDC
)hDCMem
) ) 
1250     return (WXHBRUSH
)::CreatePatternBrush(hBmp
); 
1253 void wxNotebook::UpdateBgBrush() 
1255     if ( m_hbrBackground 
) 
1256         ::DeleteObject((HBRUSH
)m_hbrBackground
); 
1258     if ( !m_hasBgCol 
&& wxUxThemeEngine::GetIfActive() ) 
1260         m_hbrBackground 
= QueryBgBitmap(); 
1262     else // no themes or we've got user-defined solid colour 
1264         m_hbrBackground 
= NULL
; 
1268 WXHBRUSH 
wxNotebook::MSWGetBgBrushForChild(WXHDC hDC
, wxWindow 
*child
) 
1270     if ( m_hbrBackground 
) 
1272         // before drawing with the background brush, we need to position it 
1275         ::GetWindowRect(GetHwndOf(child
), &rc
); 
1277         ::MapWindowPoints(NULL
, GetHwnd(), (POINT 
*)&rc
, 1); 
1279         if ( !::SetBrushOrgEx((HDC
)hDC
, -rc
.left
, -rc
.top
, NULL
) ) 
1281             wxLogLastError(wxT("SetBrushOrgEx(notebook bg brush)")); 
1284         return m_hbrBackground
; 
1287     return wxNotebookBase::MSWGetBgBrushForChild(hDC
, child
); 
1290 bool wxNotebook::MSWPrintChild(WXHDC hDC
, wxWindow 
*child
) 
1292     // solid background colour overrides themed background drawing 
1293     if ( !UseBgCol() && DoDrawBackground(hDC
, child
) ) 
1296     // If we're using a solid colour (for example if we've switched off 
1297     // theming for this notebook), paint it 
1300         wxRect r 
= GetPageSize(); 
1305         wxCopyRectToRECT(r
, rc
); 
1307         // map rect to the coords of the window we're drawing in 
1309             ::MapWindowPoints(GetHwnd(), GetHwndOf(child
), (POINT 
*)&rc
, 2); 
1311         wxBrush 
brush(GetBackgroundColour()); 
1312         HBRUSH hbr 
= GetHbrushOf(brush
); 
1314         ::FillRect((HDC
) hDC
, &rc
, hbr
); 
1319     return wxNotebookBase::MSWPrintChild(hDC
, child
); 
1322 #endif // wxUSE_UXTHEME 
1324 // Windows only: attempts to get colour for UX theme page background 
1325 wxColour 
wxNotebook::GetThemeBackgroundColour() const 
1328     if (wxUxThemeEngine::Get()) 
1330         wxUxThemeHandle 
hTheme((wxNotebook
*) this, L
"TAB"); 
1333             // This is total guesswork. 
1334             // See PlatformSDK\Include\Tmschema.h for values. 
1335             // JACS: can also use 9 (TABP_PANE) 
1336             COLORREF themeColor
; 
1337             bool success 
= (S_OK 
== wxUxThemeEngine::Get()->GetThemeColor( 
1341                                         3821 /* FILLCOLORHINT */, 
1344                 return GetBackgroundColour(); 
1347             [DS] Workaround for WindowBlinds: 
1348             Some themes return a near black theme color using FILLCOLORHINT, 
1349             this makes notebook pages have an ugly black background and makes 
1350             text (usually black) unreadable. Retry again with FILLCOLOR. 
1352             This workaround potentially breaks appearance of some themes, 
1353             but in practice it already fixes some themes. 
1355             if (themeColor 
== 1) 
1357                 wxUxThemeEngine::Get()->GetThemeColor( 
1361                                             3802 /* FILLCOLOR */, 
1365             wxColour colour 
= wxRGBToColour(themeColor
); 
1367             // Under Vista, the tab background colour is reported incorrectly. 
1368             // So for the default theme at least, hard-code the colour to something 
1369             // that will blend in. 
1371             static int s_AeroStatus 
= -1; 
1372             if (s_AeroStatus 
== -1) 
1374                 WCHAR szwThemeFile
[1024]; 
1375                 WCHAR szwThemeColor
[256]; 
1376                 if (S_OK 
== wxUxThemeEngine::Get()->GetCurrentThemeName(szwThemeFile
, 1024, szwThemeColor
, 256, NULL
, 0)) 
1378                     wxString 
themeFile(szwThemeFile
), themeColor(szwThemeColor
); 
1379                     if (themeFile
.Find(wxT("Aero")) != -1 && themeColor 
== wxT("NormalColor")) 
1388             if (s_AeroStatus 
== 1) 
1389                 colour 
= wxColour(255, 255, 255); 
1394 #endif // wxUSE_UXTHEME 
1396     return GetBackgroundColour(); 
1399 // ---------------------------------------------------------------------------- 
1400 // wxNotebook base class virtuals 
1401 // ---------------------------------------------------------------------------- 
1403 #if wxUSE_CONSTRAINTS 
1405 // override these 2 functions to do nothing: everything is done in OnSize 
1407 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
)) 
1409   // don't set the sizes of the pages - their correct size is not yet known 
1410   wxControl::SetConstraintSizes(false); 
1413 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
)) 
1418 #endif // wxUSE_CONSTRAINTS 
1420 // ---------------------------------------------------------------------------- 
1421 // wxNotebook Windows message handlers 
1422 // ---------------------------------------------------------------------------- 
1424 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
, 
1425                              WXWORD pos
, WXHWND control
) 
1427     // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the 
1432     return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
); 
1435 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
) 
1437   wxBookCtrlEvent 
event(wxEVT_NULL
, m_windowId
); 
1439   NMHDR
* hdr 
= (NMHDR 
*)lParam
; 
1440   switch ( hdr
->code 
) { 
1442       event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
); 
1445     case TCN_SELCHANGING
: 
1446       event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
); 
1450       return wxControl::MSWOnNotify(idCtrl
, lParam
, result
); 
1453   event
.SetSelection(TabCtrl_GetCurSel(GetHwnd())); 
1454   event
.SetOldSelection(m_nSelection
); 
1455   event
.SetEventObject(this); 
1456   event
.SetInt(idCtrl
); 
1458   bool processed 
= HandleWindowEvent(event
); 
1459   *result 
= !event
.IsAllowed(); 
1463 #endif // wxUSE_NOTEBOOK