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" 
  35 #include "wx/imaglist.h" 
  36 #include "wx/sysopt.h" 
  38 #include "wx/msw/private.h" 
  41 #include "wx/msw/winundef.h" 
  44     #include "wx/msw/uxtheme.h" 
  47 // ---------------------------------------------------------------------------- 
  49 // ---------------------------------------------------------------------------- 
  51 // check that the page index is valid 
  52 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) 
  54 // you can set USE_NOTEBOOK_ANTIFLICKER to 0 for desktop Windows versions too 
  55 // to disable code whih results in flicker-less notebook redrawing at the 
  56 // expense of some extra GDI resource consumption 
  58     // notebooks are never resized under CE anyhow 
  59     #define USE_NOTEBOOK_ANTIFLICKER    0 
  61     #define USE_NOTEBOOK_ANTIFLICKER    1 
  64 // ---------------------------------------------------------------------------- 
  66 // ---------------------------------------------------------------------------- 
  68 // This is a work-around for missing defines in gcc-2.95 headers 
  70     #define TCS_RIGHT       0x0002 
  74     #define TCS_VERTICAL    0x0080 
  78     #define TCS_BOTTOM      TCS_RIGHT 
  81 // ---------------------------------------------------------------------------- 
  83 // ---------------------------------------------------------------------------- 
  85 #if USE_NOTEBOOK_ANTIFLICKER 
  87 // the pointer to standard spin button wnd proc 
  88 static WXFARPROC gs_wndprocNotebookSpinBtn 
= (WXFARPROC
)NULL
; 
  90 // the pointer to standard tab control wnd proc 
  91 static WXFARPROC gs_wndprocNotebook 
= (WXFARPROC
)NULL
; 
  93 LRESULT APIENTRY _EXPORT 
wxNotebookWndProc(HWND hwnd
, 
  98 #endif // USE_NOTEBOOK_ANTIFLICKER 
 100 // ---------------------------------------------------------------------------- 
 102 // ---------------------------------------------------------------------------- 
 104 #include "wx/listimpl.cpp" 
 106 WX_DEFINE_LIST( wxNotebookPageInfoList 
) 
 108 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
) 
 109 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
) 
 111 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
) 
 112     EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY
, wxNotebook::OnSelChange
) 
 113     EVT_SIZE(wxNotebook::OnSize
) 
 114     EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
) 
 116 #if USE_NOTEBOOK_ANTIFLICKER 
 117     EVT_ERASE_BACKGROUND(wxNotebook::OnEraseBackground
) 
 118     EVT_PAINT(wxNotebook::OnPaint
) 
 119 #endif // USE_NOTEBOOK_ANTIFLICKER 
 122 #if wxUSE_EXTENDED_RTTI 
 123 WX_DEFINE_FLAGS( wxNotebookStyle 
) 
 125 wxBEGIN_FLAGS( wxNotebookStyle 
) 
 126     // new style border flags, we put them first to 
 127     // use them for streaming out 
 128     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
 129     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
 130     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
 131     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
 132     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
 133     wxFLAGS_MEMBER(wxBORDER_NONE
) 
 135     // old style border flags 
 136     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
 137     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
 138     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
 139     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
 140     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
 141     wxFLAGS_MEMBER(wxBORDER
) 
 143     // standard window styles 
 144     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
 145     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
 146     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
 147     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
 148     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
 149     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
 150     wxFLAGS_MEMBER(wxVSCROLL
) 
 151     wxFLAGS_MEMBER(wxHSCROLL
) 
 153     wxFLAGS_MEMBER(wxNB_FIXEDWIDTH
) 
 154     wxFLAGS_MEMBER(wxBK_DEFAULT
) 
 155     wxFLAGS_MEMBER(wxBK_TOP
) 
 156     wxFLAGS_MEMBER(wxBK_LEFT
) 
 157     wxFLAGS_MEMBER(wxBK_RIGHT
) 
 158     wxFLAGS_MEMBER(wxBK_BOTTOM
) 
 159     wxFLAGS_MEMBER(wxNB_NOPAGETHEME
) 
 160     wxFLAGS_MEMBER(wxNB_FLAT
) 
 162 wxEND_FLAGS( wxNotebookStyle 
) 
 164 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebook
, wxControl
,"wx/notebook.h") 
 165 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebookPageInfo
, wxObject 
, "wx/notebook.h" ) 
 167 wxCOLLECTION_TYPE_INFO( wxNotebookPageInfo 
* , wxNotebookPageInfoList 
) ; 
 169 template<> void wxCollectionToVariantArray( wxNotebookPageInfoList 
const &theList
, wxxVariantArray 
&value
) 
 171     wxListCollectionToVariantArray
<wxNotebookPageInfoList::compatibility_iterator
>( theList 
, value 
) ; 
 174 wxBEGIN_PROPERTIES_TABLE(wxNotebook
) 
 175     wxEVENT_PROPERTY( PageChanging 
, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING 
, wxNotebookEvent 
) 
 176     wxEVENT_PROPERTY( PageChanged 
, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED 
, wxNotebookEvent 
) 
 178     wxPROPERTY_COLLECTION( PageInfos 
, wxNotebookPageInfoList 
, wxNotebookPageInfo
* , AddPageInfo 
, GetPageInfos 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 179     wxPROPERTY_FLAGS( WindowStyle 
, wxNotebookStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 180 wxEND_PROPERTIES_TABLE() 
 182 wxBEGIN_HANDLERS_TABLE(wxNotebook
) 
 183 wxEND_HANDLERS_TABLE() 
 185 wxCONSTRUCTOR_5( wxNotebook 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxPoint 
, Position 
, wxSize 
, Size 
, long , WindowStyle
) 
 188 wxBEGIN_PROPERTIES_TABLE(wxNotebookPageInfo
) 
 189     wxREADONLY_PROPERTY( Page 
, wxNotebookPage
* , GetPage 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 190     wxREADONLY_PROPERTY( Text 
, wxString 
, GetText 
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 191     wxREADONLY_PROPERTY( Selected 
, bool , GetSelected 
, false, 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) 
 192     wxREADONLY_PROPERTY( ImageId 
, int , GetImageId 
, -1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 193 wxEND_PROPERTIES_TABLE() 
 195 wxBEGIN_HANDLERS_TABLE(wxNotebookPageInfo
) 
 196 wxEND_HANDLERS_TABLE() 
 198 wxCONSTRUCTOR_4( wxNotebookPageInfo 
, wxNotebookPage
* , Page 
, wxString 
, Text 
, bool , Selected 
, int , ImageId 
) 
 201 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
) 
 202 IMPLEMENT_DYNAMIC_CLASS(wxNotebookPageInfo
, wxObject 
) 
 204 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxNotifyEvent
) 
 206 // ============================================================================ 
 208 // ============================================================================ 
 210 // ---------------------------------------------------------------------------- 
 211 // wxNotebook construction 
 212 // ---------------------------------------------------------------------------- 
 214 const wxNotebookPageInfoList
& wxNotebook::GetPageInfos() const 
 216     wxNotebookPageInfoList
* list 
= const_cast< wxNotebookPageInfoList
* >( &m_pageInfos 
) ; 
 217     WX_CLEAR_LIST( wxNotebookPageInfoList 
, *list 
) ; 
 218     for( size_t i 
= 0 ; i 
< GetPageCount() ; ++i 
) 
 220         wxNotebookPageInfo 
*info 
= new wxNotebookPageInfo() ; 
 221         info
->Create( const_cast<wxNotebook
*>(this)->GetPage(i
) , GetPageText(i
) , GetSelection() == int(i
) , GetPageImage(i
) ) ; 
 222         list
->Append( info 
) ; 
 227 // common part of all ctors 
 228 void wxNotebook::Init() 
 231     m_nSelection 
= wxNOT_FOUND
; 
 234     m_hbrBackground 
= NULL
; 
 235 #endif // wxUSE_UXTHEME 
 237 #if USE_NOTEBOOK_ANTIFLICKER 
 238     m_hasSubclassedUpdown 
= false; 
 239 #endif // USE_NOTEBOOK_ANTIFLICKER 
 242 // default for dynamic class 
 243 wxNotebook::wxNotebook() 
 248 // the same arguments as for wxControl 
 249 wxNotebook::wxNotebook(wxWindow 
*parent
, 
 254                        const wxString
& name
) 
 258   Create(parent
, id
, pos
, size
, style
, name
); 
 262 bool wxNotebook::Create(wxWindow 
*parent
, 
 267                         const wxString
& name
) 
 269     if ( (style 
& wxBK_ALIGN_MASK
) == wxBK_DEFAULT 
) 
 271 #if defined(__POCKETPC__) 
 272         style 
|= wxBK_BOTTOM 
| wxNB_FLAT
; 
 279     // Not sure why, but without this style, there is no border 
 280     // around the notebook tabs. 
 281     if (style 
& wxNB_FLAT
) 
 282         style 
|= wxBORDER_SUNKEN
; 
 286     // ComCtl32 notebook tabs simply don't work unless they're on top if we have uxtheme, we can 
 287     // work around it later (after control creation), but if we don't have uxtheme, we have to clear 
 289     const int verComCtl32 
= wxApp::GetComCtl32Version(); 
 290     if ( verComCtl32 
== 600 ) 
 292         style 
&= ~(wxBK_BOTTOM 
| wxBK_LEFT 
| wxBK_RIGHT
); 
 294 #endif //wxUSE_UXTHEME 
 296 #if defined(__WINE__) && wxUSE_UNICODE 
 297     LPCTSTR className 
= L
"SysTabControl32"; 
 299     LPCTSTR className 
= WC_TABCONTROL
; 
 302 #if USE_NOTEBOOK_ANTIFLICKER 
 303     // SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it 
 304     // causes horrible flicker when resizing notebook, so get rid of it by 
 305     // using a class without these styles (but otherwise identical to it) 
 306     if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) ) 
 308         static ClassRegistrar s_clsNotebook
; 
 309         if ( !s_clsNotebook
.IsInitialized() ) 
 311             // get a copy of standard class and modify it 
 314             if ( ::GetClassInfo(NULL
, WC_TABCONTROL
, &wc
) ) 
 317                     wx_reinterpret_cast(WXFARPROC
, wc
.lpfnWndProc
); 
 318                 wc
.lpszClassName 
= wxT("_wx_SysTabCtl32"); 
 319                 wc
.style 
&= ~(CS_HREDRAW 
| CS_VREDRAW
); 
 320                 wc
.hInstance 
= wxGetInstance(); 
 321                 wc
.lpfnWndProc 
= wxNotebookWndProc
; 
 322                 s_clsNotebook
.Register(wc
); 
 326                 wxLogLastError(_T("GetClassInfoEx(SysTabCtl32)")); 
 330         // use our custom class if available but fall back to the standard 
 331         // notebook if we failed to register it 
 332         if ( s_clsNotebook
.IsRegistered() ) 
 334             // it's ok to use c_str() here as the static s_clsNotebook object 
 335             // has sufficiently long lifetime 
 336             className 
= s_clsNotebook
.GetName().c_str(); 
 339 #endif // USE_NOTEBOOK_ANTIFLICKER 
 341     if ( !CreateControl(parent
, id
, pos
, size
, style 
| wxTAB_TRAVERSAL
, 
 342                         wxDefaultValidator
, name
) ) 
 345     if ( !MSWCreateControl(className
, wxEmptyString
, pos
, size
) ) 
 349     if ( HasFlag(wxNB_NOPAGETHEME
) || 
 350             wxSystemOptions::IsFalse(wxT("msw.notebook.themed-background")) ) 
 352         SetBackgroundColour(GetThemeBackgroundColour()); 
 354     else // use themed background by default 
 356         // create backing store 
 360     // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the 
 361     // control is simply not rendered correctly), so we disable themes 
 362     // if possible, otherwise we simply clear the styles. 
 363     // It's probably not possible to have UXTHEME without ComCtl32 6 or better, but lets 
 365     const int verComCtl32 
= wxApp::GetComCtl32Version(); 
 366     if ( verComCtl32 
== 600 ) 
 368         // check if we use themes at all -- if we don't, we're still okay 
 369         if ( wxUxThemeEngine::GetIfActive() && (style 
& (wxBK_BOTTOM
|wxBK_LEFT
|wxBK_RIGHT
))) 
 371             wxUxThemeEngine::GetIfActive()->SetWindowTheme((HWND
)this->GetHandle(), L
"", L
""); 
 372             SetBackgroundColour(GetThemeBackgroundColour());    //correct the background color for the new non-themed control 
 375 #endif // wxUSE_UXTHEME 
 377     // Undocumented hack to get flat notebook style 
 378     // In fact, we should probably only do this in some 
 379     // curcumstances, i.e. if we know we will have a border 
 380     // at the bottom (the tab control doesn't draw it itself) 
 381 #if defined(__POCKETPC__) || defined(__SMARTPHONE__) 
 382     if (HasFlag(wxNB_FLAT
)) 
 384         SendMessage(GetHwnd(), CCM_SETVERSION
, COMCTL32_VERSION
, 0); 
 386             SetBackgroundColour(*wxWHITE
); 
 392 WXDWORD 
wxNotebook::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 394     WXDWORD tabStyle 
= wxControl::MSWGetStyle(style
, exstyle
); 
 396     tabStyle 
|= WS_TABSTOP 
| TCS_TABS
; 
 398     if ( style 
& wxNB_MULTILINE 
) 
 399         tabStyle 
|= TCS_MULTILINE
; 
 400     if ( style 
& wxNB_FIXEDWIDTH 
) 
 401         tabStyle 
|= TCS_FIXEDWIDTH
; 
 403     if ( style 
& wxBK_BOTTOM 
) 
 404         tabStyle 
|= TCS_RIGHT
; 
 405     else if ( style 
& wxBK_LEFT 
) 
 406         tabStyle 
|= TCS_VERTICAL
; 
 407     else if ( style 
& wxBK_RIGHT 
) 
 408         tabStyle 
|= TCS_VERTICAL 
| TCS_RIGHT
; 
 413         // note that we never want to have the default WS_EX_CLIENTEDGE style 
 414         // as it looks too ugly for the notebooks 
 421 wxNotebook::~wxNotebook() 
 424     if ( m_hbrBackground 
) 
 425         ::DeleteObject((HBRUSH
)m_hbrBackground
); 
 426 #endif // wxUSE_UXTHEME 
 429 // ---------------------------------------------------------------------------- 
 430 // wxNotebook accessors 
 431 // ---------------------------------------------------------------------------- 
 433 size_t wxNotebook::GetPageCount() const 
 436     wxASSERT( (int)m_pages
.Count() == TabCtrl_GetItemCount(GetHwnd()) ); 
 438     return m_pages
.Count(); 
 441 int wxNotebook::GetRowCount() const 
 443     return TabCtrl_GetRowCount(GetHwnd()); 
 446 int wxNotebook::SetSelection(size_t nPage
) 
 448     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 450     if ( m_nSelection 
== wxNOT_FOUND 
|| nPage 
!= (size_t)m_nSelection 
) 
 452         if ( SendPageChangingEvent(nPage
) ) 
 454             // program allows the page change 
 455             SendPageChangedEvent(m_nSelection
, nPage
); 
 457             TabCtrl_SetCurSel(GetHwnd(), nPage
); 
 464 void wxNotebook::UpdateSelection(int selNew
) 
 466     if ( m_nSelection 
!= wxNOT_FOUND 
) 
 467         m_pages
[m_nSelection
]->Show(false); 
 469     if ( selNew 
!= wxNOT_FOUND 
) 
 471         wxNotebookPage 
*pPage 
= m_pages
[selNew
]; 
 475     // Changing the page should give the focus to it but, as per bug report 
 476     // http://sf.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863, 
 477     // we should not set the focus to it directly since it erroneously 
 478     // selects radio buttons and breaks keyboard handling for a notebook's 
 479     // scroll buttons. So give focus to the notebook and not the page. 
 481     // but don't do this is the notebook is hidden 
 482     if ( ::IsWindowVisible(GetHwnd()) ) 
 485     m_nSelection 
= selNew
; 
 488 int wxNotebook::ChangeSelection(size_t nPage
) 
 490     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 492     if ( m_nSelection 
== wxNOT_FOUND 
|| nPage 
!= (size_t)m_nSelection 
) 
 494         TabCtrl_SetCurSel(GetHwnd(), nPage
); 
 496         UpdateSelection(nPage
); 
 502 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
) 
 504     wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") ); 
 507     tcItem
.mask 
= TCIF_TEXT
; 
 508     tcItem
.pszText 
= (wxChar 
*)strText
.wx_str(); 
 510     if ( !HasFlag(wxNB_MULTILINE
) ) 
 511         return TabCtrl_SetItem(GetHwnd(), nPage
, &tcItem
) != 0; 
 513     // multiline - we need to set new page size if a line is added or removed 
 514     int rows 
= GetRowCount(); 
 515     bool ret 
= TabCtrl_SetItem(GetHwnd(), nPage
, &tcItem
) != 0; 
 517     if ( ret 
&& rows 
!= GetRowCount() ) 
 519         const wxRect r 
= GetPageSize(); 
 520         const size_t count 
= m_pages
.Count(); 
 521         for ( size_t page 
= 0; page 
< count
; page
++ ) 
 522             m_pages
[page
]->SetSize(r
); 
 528 wxString 
wxNotebook::GetPageText(size_t nPage
) const 
 530     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") ); 
 534     tcItem
.mask 
= TCIF_TEXT
; 
 535     tcItem
.pszText 
= buf
; 
 536     tcItem
.cchTextMax 
= WXSIZEOF(buf
); 
 539     if ( TabCtrl_GetItem(GetHwnd(), nPage
, &tcItem
) ) 
 540         str 
= tcItem
.pszText
; 
 545 int wxNotebook::GetPageImage(size_t nPage
) const 
 547     wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") ); 
 550     tcItem
.mask 
= TCIF_IMAGE
; 
 552     return TabCtrl_GetItem(GetHwnd(), nPage
, &tcItem
) ? tcItem
.iImage
 
 556 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
) 
 558     wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") ); 
 561     tcItem
.mask 
= TCIF_IMAGE
; 
 562     tcItem
.iImage 
= nImage
; 
 564     return TabCtrl_SetItem(GetHwnd(), nPage
, &tcItem
) != 0; 
 567 void wxNotebook::SetImageList(wxImageList
* imageList
) 
 569     wxNotebookBase::SetImageList(imageList
); 
 573         (void) TabCtrl_SetImageList(GetHwnd(), GetHimagelistOf(imageList
)); 
 577 // ---------------------------------------------------------------------------- 
 578 // wxNotebook size settings 
 579 // ---------------------------------------------------------------------------- 
 581 wxRect 
wxNotebook::GetPageSize() const 
 586     ::GetClientRect(GetHwnd(), &rc
); 
 588     // This check is to work around a bug in TabCtrl_AdjustRect which will 
 589     // cause a crash on win2k or on XP with themes disabled if either 
 590     // wxNB_MULTILINE is used or tabs are placed on a side, if the rectangle 
 593     // The value of 20 is chosen arbitrarily but seems to work 
 594     if ( rc
.right 
> 20 && rc
.bottom 
> 20 ) 
 596         TabCtrl_AdjustRect(GetHwnd(), false, &rc
); 
 598         wxCopyRECTToRect(rc
, r
); 
 604 void wxNotebook::SetPageSize(const wxSize
& size
) 
 606     // transform the page size into the notebook size 
 613     TabCtrl_AdjustRect(GetHwnd(), true, &rc
); 
 616     SetSize(rc
.right 
- rc
.left
, rc
.bottom 
- rc
.top
); 
 619 void wxNotebook::SetPadding(const wxSize
& padding
) 
 621     TabCtrl_SetPadding(GetHwnd(), padding
.x
, padding
.y
); 
 624 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH 
 626 void wxNotebook::SetTabSize(const wxSize
& sz
) 
 628     ::SendMessage(GetHwnd(), TCM_SETITEMSIZE
, 0, MAKELPARAM(sz
.x
, sz
.y
)); 
 631 wxSize 
wxNotebook::CalcSizeFromPage(const wxSize
& sizePage
) const 
 633     // we can't use TabCtrl_AdjustRect here because it only works for wxNB_TOP 
 634     wxSize sizeTotal 
= sizePage
; 
 637     if ( GetPageCount() > 0 ) 
 640         TabCtrl_GetItemRect(GetHwnd(), 0, &rect
); 
 641         tabSize
.x 
= rect
.right 
- rect
.left
; 
 642         tabSize
.y 
= rect
.bottom 
- rect
.top
; 
 645     // add an extra margin in both directions 
 646     const int MARGIN 
= 8; 
 649         sizeTotal
.x 
+= MARGIN
; 
 650         sizeTotal
.y 
+= tabSize
.y 
+ MARGIN
; 
 652     else // horizontal layout 
 654         sizeTotal
.x 
+= tabSize
.x 
+ MARGIN
; 
 655         sizeTotal
.y 
+= MARGIN
; 
 661 void wxNotebook::AdjustPageSize(wxNotebookPage 
*page
) 
 663     wxCHECK_RET( page
, _T("NULL page in wxNotebook::AdjustPageSize") ); 
 665     const wxRect r 
= GetPageSize(); 
 672 // ---------------------------------------------------------------------------- 
 673 // wxNotebook operations 
 674 // ---------------------------------------------------------------------------- 
 676 // remove one page from the notebook, without deleting 
 677 wxNotebookPage 
*wxNotebook::DoRemovePage(size_t nPage
) 
 679     wxNotebookPage 
*pageRemoved 
= wxNotebookBase::DoRemovePage(nPage
); 
 683     TabCtrl_DeleteItem(GetHwnd(), nPage
); 
 685     if ( m_pages
.IsEmpty() ) 
 687         // no selection any more, the notebook becamse empty 
 688         m_nSelection 
= wxNOT_FOUND
; 
 690     else // notebook still not empty 
 692         int selNew 
= TabCtrl_GetCurSel(GetHwnd()); 
 693         if ( selNew 
!= wxNOT_FOUND 
) 
 695             // No selection change, just refresh the current selection. 
 696             // Because it could be that the slection index changed 
 697             // we need to update it. 
 698             // Note: this does not mean the selection it self changed. 
 699             m_nSelection 
= selNew
; 
 700             m_pages
[m_nSelection
]->Refresh(); 
 702         else if (int(nPage
) == m_nSelection
) 
 704             // The selection was deleted. 
 706             // Determine new selection. 
 707             if (m_nSelection 
== int(GetPageCount())) 
 708                 selNew 
= m_nSelection 
- 1; 
 710                 selNew 
= m_nSelection
; 
 712             // m_nSelection must be always valid so reset it before calling 
 714             m_nSelection 
= wxNOT_FOUND
; 
 715             SetSelection(selNew
); 
 719             wxFAIL
; // Windows did not behave ok. 
 727 bool wxNotebook::DeleteAllPages() 
 729     size_t nPageCount 
= GetPageCount(); 
 731     for ( nPage 
= 0; nPage 
< nPageCount
; nPage
++ ) 
 732         delete m_pages
[nPage
]; 
 736     TabCtrl_DeleteAllItems(GetHwnd()); 
 738     m_nSelection 
= wxNOT_FOUND
; 
 740     InvalidateBestSize(); 
 744 // same as AddPage() but does it at given position 
 745 bool wxNotebook::InsertPage(size_t nPage
, 
 746                             wxNotebookPage 
*pPage
, 
 747                             const wxString
& strText
, 
 751     wxCHECK_MSG( pPage 
!= NULL
, false, _T("NULL page in wxNotebook::InsertPage") ); 
 752     wxCHECK_MSG( IS_VALID_PAGE(nPage
) || nPage 
== GetPageCount(), false, 
 753                  _T("invalid index in wxNotebook::InsertPage") ); 
 755     wxASSERT_MSG( pPage
->GetParent() == this, 
 756                     _T("notebook pages must have notebook as parent") ); 
 758     // add a new tab to the control 
 759     // ---------------------------- 
 761     // init all fields to 0 
 763     wxZeroMemory(tcItem
); 
 765     // set the image, if any 
 768         tcItem
.mask 
|= TCIF_IMAGE
; 
 769         tcItem
.iImage  
= imageId
; 
 773     if ( !strText
.empty() ) 
 775         tcItem
.mask 
|= TCIF_TEXT
; 
 776         tcItem
.pszText 
= (wxChar 
*)strText
.wx_str(); // const_cast 
 779     // hide the page: unless it is selected, it shouldn't be shown (and if it 
 780     // is selected it will be shown later) 
 781     HWND hwnd 
= GetWinHwnd(pPage
); 
 782     SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~WS_VISIBLE
); 
 784     // this updates internal flag too -- otherwise it would get out of sync 
 785     // with the real state 
 789     // fit the notebook page to the tab control's display area: this should be 
 790     // done before adding it to the notebook or TabCtrl_InsertItem() will 
 791     // change the notebooks size itself! 
 792     AdjustPageSize(pPage
); 
 794     // finally do insert it 
 795     if ( TabCtrl_InsertItem(GetHwnd(), nPage
, &tcItem
) == -1 ) 
 797         wxLogError(wxT("Can't create the notebook page '%s'."), strText
.c_str()); 
 802     // need to update the bg brush when the first page is added 
 803     // so the first panel gets the correct themed background 
 804     if ( m_pages
.empty() ) 
 808 #endif // wxUSE_UXTHEME 
 811     // succeeded: save the pointer to the page 
 812     m_pages
.Insert(pPage
, nPage
); 
 814     // we may need to adjust the size again if the notebook size changed: 
 815     // normally this only happens for the first page we add (the tabs which 
 816     // hadn't been there before are now shown) but for a multiline notebook it 
 817     // can happen for any page at all as a new row could have been started 
 818     if ( m_pages
.GetCount() == 1 || HasFlag(wxNB_MULTILINE
) ) 
 820         AdjustPageSize(pPage
); 
 823     // now deal with the selection 
 824     // --------------------------- 
 826     // if the inserted page is before the selected one, we must update the 
 827     // index of the selected page 
 828     if ( int(nPage
) <= m_nSelection 
) 
 830         // one extra page added 
 834     // some page should be selected: either this one or the first one if there 
 835     // is still no selection 
 836     int selNew 
= wxNOT_FOUND
; 
 839     else if ( m_nSelection 
== wxNOT_FOUND 
) 
 842     if ( selNew 
!= wxNOT_FOUND 
) 
 843         SetSelection(selNew
); 
 845     InvalidateBestSize(); 
 850 int wxNotebook::HitTest(const wxPoint
& pt
, long *flags
) const 
 852     TC_HITTESTINFO hitTestInfo
; 
 853     hitTestInfo
.pt
.x 
= pt
.x
; 
 854     hitTestInfo
.pt
.y 
= pt
.y
; 
 855     int item 
= TabCtrl_HitTest(GetHwnd(), &hitTestInfo
); 
 861         if ((hitTestInfo
.flags 
& TCHT_NOWHERE
) == TCHT_NOWHERE
) 
 862             *flags 
|= wxBK_HITTEST_NOWHERE
; 
 863         if ((hitTestInfo
.flags 
& TCHT_ONITEM
) == TCHT_ONITEM
) 
 864             *flags 
|= wxBK_HITTEST_ONITEM
; 
 865         if ((hitTestInfo
.flags 
& TCHT_ONITEMICON
) == TCHT_ONITEMICON
) 
 866             *flags 
|= wxBK_HITTEST_ONICON
; 
 867         if ((hitTestInfo
.flags 
& TCHT_ONITEMLABEL
) == TCHT_ONITEMLABEL
) 
 868             *flags 
|= wxBK_HITTEST_ONLABEL
; 
 869         if ( item 
== wxNOT_FOUND 
&& GetPageSize().Contains(pt
) ) 
 870             *flags 
|= wxBK_HITTEST_ONPAGE
; 
 876 // ---------------------------------------------------------------------------- 
 877 // flicker-less notebook redraw 
 878 // ---------------------------------------------------------------------------- 
 880 #if USE_NOTEBOOK_ANTIFLICKER 
 882 // wnd proc for the spin button 
 883 LRESULT APIENTRY _EXPORT 
wxNotebookSpinBtnWndProc(HWND hwnd
, 
 888     if ( message 
== WM_ERASEBKGND 
) 
 891     return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebookSpinBtn
, 
 892                             hwnd
, message
, wParam
, lParam
); 
 895 LRESULT APIENTRY _EXPORT 
wxNotebookWndProc(HWND hwnd
, 
 900     return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebook
, 
 901                             hwnd
, message
, wParam
, lParam
); 
 904 void wxNotebook::OnEraseBackground(wxEraseEvent
& WXUNUSED(event
)) 
 909 void wxNotebook::OnPaint(wxPaintEvent
& WXUNUSED(event
)) 
 914     ::GetClientRect(GetHwnd(), &rc
); 
 915     wxBitmap 
bmp(rc
.right
, rc
.bottom
); 
 916     memdc
.SelectObject(bmp
); 
 918     const wxLayoutDirection dir 
= dc
.GetLayoutDirection(); 
 919     memdc
.SetLayoutDirection(dir
); 
 921     // if there is no special brush just use the solid background colour 
 923     HBRUSH hbr 
= (HBRUSH
)m_hbrBackground
; 
 930         brush 
= wxBrush(GetBackgroundColour()); 
 931         hbr 
= GetHbrushOf(brush
); 
 934     ::FillRect(GetHdcOf(memdc
), &rc
, hbr
); 
 936     MSWDefWindowProc(WM_PAINT
, (WPARAM
)memdc
.GetHDC(), 0); 
 938     // For some reason in RTL mode, source offset has to be -1, otherwise the 
 939     // right border (physical) remains unpainted. 
 940     const wxCoord ofs 
= dir 
== wxLayout_RightToLeft 
? -1 : 0; 
 941     dc
.Blit(ofs
, 0, rc
.right
, rc
.bottom
, &memdc
, ofs
, 0); 
 944 #endif // USE_NOTEBOOK_ANTIFLICKER 
 946 // ---------------------------------------------------------------------------- 
 947 // wxNotebook callbacks 
 948 // ---------------------------------------------------------------------------- 
 950 void wxNotebook::OnSize(wxSizeEvent
& event
) 
 952     if ( GetPageCount() == 0 ) 
 954         // Prevents droppings on resize, but does cause some flicker 
 955         // when there are no pages. 
 963         // Without this, we can sometimes get droppings at the edges 
 964         // of a notebook, for example a notebook in a splitter window. 
 965         // This needs to be reconciled with the RefreshRect calls 
 966         // at the end of this function, which weren't enough to prevent 
 969         wxSize sz 
= GetClientSize(); 
 971         // Refresh right side 
 972         wxRect 
rect(sz
.x
-4, 0, 4, sz
.y
); 
 975         // Refresh bottom side 
 976         rect 
= wxRect(0, sz
.y
-4, sz
.x
, 4); 
 980         rect 
= wxRect(0, 0, 4, sz
.y
); 
 983 #endif // !__WXWINCE__ 
 985     // fit all the notebook pages to the tab control's display area 
 988     rc
.left 
= rc
.top 
= 0; 
 989     GetSize((int *)&rc
.right
, (int *)&rc
.bottom
); 
 991     // save the total size, we'll use it below 
 992     int widthNbook 
= rc
.right 
- rc
.left
, 
 993         heightNbook 
= rc
.bottom 
- rc
.top
; 
 995     // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it 
 996     // returns completely false values for multiline tab controls after the tabs 
 997     // are added but before getting the first WM_SIZE (off by ~50 pixels, see 
 999     // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863 
1001     // and the only work around I could find was this ugly hack... without it 
1002     // simply toggling the "multiline" checkbox in the notebook sample resulted 
1003     // in a noticeable page displacement 
1004     if ( HasFlag(wxNB_MULTILINE
) ) 
1006         // avoid an infinite recursion: we get another notification too! 
1007         static bool s_isInOnSize 
= false; 
1009         if ( !s_isInOnSize 
) 
1011             s_isInOnSize 
= true; 
1012             SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
, 
1013                     MAKELPARAM(rc
.right
, rc
.bottom
)); 
1014             s_isInOnSize 
= false; 
1019     // background bitmap size has changed, update the brush using it too 
1021 #endif // wxUSE_UXTHEME 
1023     TabCtrl_AdjustRect(GetHwnd(), false, &rc
); 
1025     int width 
= rc
.right 
- rc
.left
, 
1026         height 
= rc
.bottom 
- rc
.top
; 
1027     size_t nCount 
= m_pages
.Count(); 
1028     for ( size_t nPage 
= 0; nPage 
< nCount
; nPage
++ ) { 
1029         wxNotebookPage 
*pPage 
= m_pages
[nPage
]; 
1030         pPage
->SetSize(rc
.left
, rc
.top
, width
, height
); 
1034     // unless we had already repainted everything, we now need to refresh 
1035     if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) ) 
1037         // invalidate areas not covered by pages 
1038         RefreshRect(wxRect(0, 0, widthNbook
, rc
.top
), false); 
1039         RefreshRect(wxRect(0, rc
.top
, rc
.left
, height
), false); 
1040         RefreshRect(wxRect(0, rc
.bottom
, widthNbook
, heightNbook 
- rc
.bottom
), 
1042         RefreshRect(wxRect(rc
.right
, rc
.top
, widthNbook 
- rc
.right
, height
), 
1046 #if USE_NOTEBOOK_ANTIFLICKER 
1047     // subclass the spin control used by the notebook to scroll pages to 
1048     // prevent it from flickering on resize 
1049     if ( !m_hasSubclassedUpdown 
) 
1051         // iterate over all child windows to find spin button 
1052         for ( HWND child 
= ::GetWindow(GetHwnd(), GW_CHILD
); 
1054               child 
= ::GetWindow(child
, GW_HWNDNEXT
) ) 
1056             wxWindow 
*childWindow 
= wxFindWinFromHandle((WXHWND
)child
); 
1058             // see if it exists, if no wxWindow found then assume it's the spin 
1062                 // subclass the spin button to override WM_ERASEBKGND 
1063                 if ( !gs_wndprocNotebookSpinBtn 
) 
1064                     gs_wndprocNotebookSpinBtn 
= (WXFARPROC
)wxGetWindowProc(child
); 
1066                 wxSetWindowProc(child
, wxNotebookSpinBtnWndProc
); 
1067                 m_hasSubclassedUpdown 
= true; 
1072 #endif // USE_NOTEBOOK_ANTIFLICKER 
1077 void wxNotebook::OnSelChange(wxNotebookEvent
& event
) 
1079     // is it our tab control? 
1080     if ( event
.GetEventObject() == this ) 
1082         UpdateSelection(event
.GetSelection()); 
1085     // we want to give others a chance to process this message as well 
1089 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
) 
1091     if ( event
.IsWindowChange() ) { 
1093         AdvanceSelection(event
.GetDirection()); 
1096         // we get this event in 3 cases 
1098         // a) one of our pages might have generated it because the user TABbed 
1099         // out from it in which case we should propagate the event upwards and 
1100         // our parent will take care of setting the focus to prev/next sibling 
1104         // b) the parent panel wants to give the focus to us so that we 
1105         // forward it to our selected page. We can't deal with this in 
1106         // OnSetFocus() because we don't know which direction the focus came 
1107         // from in this case and so can't choose between setting the focus to 
1108         // first or last panel child 
1112         // c) we ourselves (see MSWTranslateMessage) generated the event 
1114         wxWindow 
* const parent 
= GetParent(); 
1116         // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE 
1117         const bool isFromParent 
= event
.GetEventObject() == (wxObject
*) parent
; 
1118         const bool isFromSelf 
= event
.GetEventObject() == (wxObject
*) this; 
1120         if ( isFromParent 
|| isFromSelf 
) 
1122             // no, it doesn't come from child, case (b) or (c): forward to a 
1123             // page but only if direction is backwards (TAB) or from ourselves, 
1124             if ( m_nSelection 
!= wxNOT_FOUND 
&& 
1125                     (!event
.GetDirection() || isFromSelf
) ) 
1127                 // so that the page knows that the event comes from it's parent 
1128                 // and is being propagated downwards 
1129                 event
.SetEventObject(this); 
1131                 wxWindow 
*page 
= m_pages
[m_nSelection
]; 
1132                 if ( !page
->GetEventHandler()->ProcessEvent(event
) ) 
1136                 //else: page manages focus inside it itself 
1138             else // otherwise set the focus to the notebook itself 
1145             // it comes from our child, case (a), pass to the parent, but only 
1146             // if the direction is forwards. Otherwise set the focus to the 
1147             // notebook itself. The notebook is always the 'first' control of a 
1149             if ( !event
.GetDirection() ) 
1155                 event
.SetCurrentFocus(this); 
1156                 parent
->GetEventHandler()->ProcessEvent(event
); 
1164 bool wxNotebook::DoDrawBackground(WXHDC hDC
, wxWindow 
*child
) 
1166     wxUxThemeHandle 
theme(child 
? child 
: this, L
"TAB"); 
1170     // get the notebook client rect (we're not interested in drawing tabs 
1172     wxRect r 
= GetPageSize(); 
1177     wxCopyRectToRECT(r
, rc
); 
1179     // map rect to the coords of the window we're drawing in 
1181         ::MapWindowPoints(GetHwnd(), GetHwndOf(child
), (POINT 
*)&rc
, 2); 
1183     // we have the content area (page size), but we need to draw all of the 
1184     // background for it to be aligned correctly 
1185     wxUxThemeEngine::Get()->GetThemeBackgroundExtent
 
1194     wxUxThemeEngine::Get()->DrawThemeBackground
 
1207 WXHBRUSH 
wxNotebook::QueryBgBitmap() 
1209     wxRect r 
= GetPageSize(); 
1213     WindowHDC 
hDC(GetHwnd()); 
1214     MemoryHDC 
hDCMem(hDC
); 
1215     CompatibleBitmap 
hBmp(hDC
, r
.x 
+ r
.width
, r
.y 
+ r
.height
); 
1217     SelectInHDC 
selectBmp(hDCMem
, hBmp
); 
1219     if ( !DoDrawBackground((WXHDC
)(HDC
)hDCMem
) ) 
1222     return (WXHBRUSH
)::CreatePatternBrush(hBmp
); 
1225 void wxNotebook::UpdateBgBrush() 
1227     if ( m_hbrBackground 
) 
1228         ::DeleteObject((HBRUSH
)m_hbrBackground
); 
1230     if ( !m_hasBgCol 
&& wxUxThemeEngine::GetIfActive() ) 
1232         m_hbrBackground 
= QueryBgBitmap(); 
1234     else // no themes or we've got user-defined solid colour 
1236         m_hbrBackground 
= NULL
; 
1240 WXHBRUSH 
wxNotebook::MSWGetBgBrushForChild(WXHDC hDC
, WXHWND hWnd
) 
1242     if ( m_hbrBackground 
) 
1244         // before drawing with the background brush, we need to position it 
1247         ::GetWindowRect((HWND
)hWnd
, &rc
); 
1249         ::MapWindowPoints(NULL
, GetHwnd(), (POINT 
*)&rc
, 1); 
1251         if ( !::SetBrushOrgEx((HDC
)hDC
, -rc
.left
, -rc
.top
, NULL
) ) 
1253             wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)")); 
1256         return m_hbrBackground
; 
1259     return wxNotebookBase::MSWGetBgBrushForChild(hDC
, hWnd
); 
1262 bool wxNotebook::MSWPrintChild(WXHDC hDC
, wxWindow 
*child
) 
1264     // solid background colour overrides themed background drawing 
1265     if ( !UseBgCol() && DoDrawBackground(hDC
, child
) ) 
1268     // If we're using a solid colour (for example if we've switched off 
1269     // theming for this notebook), paint it 
1272         wxRect r 
= GetPageSize(); 
1277         wxCopyRectToRECT(r
, rc
); 
1279         // map rect to the coords of the window we're drawing in 
1281             ::MapWindowPoints(GetHwnd(), GetHwndOf(child
), (POINT 
*)&rc
, 2); 
1283         wxBrush 
brush(GetBackgroundColour()); 
1284         HBRUSH hbr 
= GetHbrushOf(brush
); 
1286         ::FillRect((HDC
) hDC
, &rc
, hbr
); 
1291     return wxNotebookBase::MSWPrintChild(hDC
, child
); 
1294 #endif // wxUSE_UXTHEME 
1296 // Windows only: attempts to get colour for UX theme page background 
1297 wxColour 
wxNotebook::GetThemeBackgroundColour() const 
1300     if (wxUxThemeEngine::Get()) 
1302         wxUxThemeHandle 
hTheme((wxNotebook
*) this, L
"TAB"); 
1305             // This is total guesswork. 
1306             // See PlatformSDK\Include\Tmschema.h for values. 
1307             // JACS: can also use 9 (TABP_PANE) 
1308             COLORREF themeColor
; 
1309             bool success 
= (S_OK 
== wxUxThemeEngine::Get()->GetThemeColor( 
1313                                         3821 /* FILLCOLORHINT */, 
1316                 return GetBackgroundColour(); 
1319             [DS] Workaround for WindowBlinds: 
1320             Some themes return a near black theme color using FILLCOLORHINT, 
1321             this makes notebook pages have an ugly black background and makes 
1322             text (usually black) unreadable. Retry again with FILLCOLOR. 
1324             This workaround potentially breaks appearance of some themes, 
1325             but in practice it already fixes some themes. 
1327             if (themeColor 
== 1) 
1329                 wxUxThemeEngine::Get()->GetThemeColor( 
1333                                             3802 /* FILLCOLOR */, 
1337             wxColour colour 
= wxRGBToColour(themeColor
); 
1339             // Under Vista, the tab background colour is reported incorrectly. 
1340             // So for the default theme at least, hard-code the colour to something 
1341             // that will blend in. 
1343             static int s_AeroStatus 
= -1; 
1344             if (s_AeroStatus 
== -1) 
1346                 WCHAR szwThemeFile
[1024]; 
1347                 WCHAR szwThemeColor
[256]; 
1348                 if (S_OK 
== wxUxThemeEngine::Get()->GetCurrentThemeName(szwThemeFile
, 1024, szwThemeColor
, 256, NULL
, 0)) 
1350                     wxString 
themeFile(szwThemeFile
), themeColor(szwThemeColor
); 
1351                     if (themeFile
.Find(wxT("Aero")) != -1 && themeColor 
== wxT("NormalColor")) 
1360             if (s_AeroStatus 
== 1) 
1361                 colour 
= wxColour(255, 255, 255); 
1366 #endif // wxUSE_UXTHEME 
1368     return GetBackgroundColour(); 
1371 // ---------------------------------------------------------------------------- 
1372 // wxNotebook base class virtuals 
1373 // ---------------------------------------------------------------------------- 
1375 #if wxUSE_CONSTRAINTS 
1377 // override these 2 functions to do nothing: everything is done in OnSize 
1379 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
)) 
1381   // don't set the sizes of the pages - their correct size is not yet known 
1382   wxControl::SetConstraintSizes(false); 
1385 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
)) 
1390 #endif // wxUSE_CONSTRAINTS 
1392 // ---------------------------------------------------------------------------- 
1393 // wxNotebook Windows message handlers 
1394 // ---------------------------------------------------------------------------- 
1396 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
, 
1397                              WXWORD pos
, WXHWND control
) 
1399     // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the 
1404     return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
); 
1407 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
) 
1409   wxNotebookEvent 
event(wxEVT_NULL
, m_windowId
); 
1411   NMHDR
* hdr 
= (NMHDR 
*)lParam
; 
1412   switch ( hdr
->code 
) { 
1414       event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
); 
1417     case TCN_SELCHANGING
: 
1418       event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
); 
1422       return wxControl::MSWOnNotify(idCtrl
, lParam
, result
); 
1425   event
.SetSelection(TabCtrl_GetCurSel(GetHwnd())); 
1426   event
.SetOldSelection(m_nSelection
); 
1427   event
.SetEventObject(this); 
1428   event
.SetInt(idCtrl
); 
1430   bool processed 
= GetEventHandler()->ProcessEvent(event
); 
1431   *result 
= !event
.IsAllowed(); 
1435 #endif // wxUSE_NOTEBOOK