]> git.saurik.com Git - wxWidgets.git/blob - src/msw/notebook.cpp
f6d53a75f480631683c2ed5b2b49ea4fd6914578
[wxWidgets.git] / src / msw / notebook.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: msw/notebook.cpp
3 // Purpose: implementation of wxNotebook
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 11.06.98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_NOTEBOOK
20
21 // wxWidgets
22 #ifndef WX_PRECOMP
23 #include "wx/string.h"
24 #include "wx/dc.h"
25 #endif // WX_PRECOMP
26
27 #include "wx/log.h"
28 #include "wx/imaglist.h"
29 #include "wx/event.h"
30 #include "wx/control.h"
31 #include "wx/notebook.h"
32 #include "wx/app.h"
33 #include "wx/sysopt.h"
34 #include "wx/dcclient.h"
35 #include "wx/dcmemory.h"
36
37 #include "wx/msw/private.h"
38
39 #include <windowsx.h>
40
41 #include <commctrl.h>
42
43 #include "wx/msw/winundef.h"
44
45 #if wxUSE_UXTHEME
46 #include "wx/msw/uxtheme.h"
47 #endif
48
49 // ----------------------------------------------------------------------------
50 // macros
51 // ----------------------------------------------------------------------------
52
53 // check that the page index is valid
54 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount())
55
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
59 #ifdef __WXWINCE__
60 // notebooks are never resized under CE anyhow
61 #define USE_NOTEBOOK_ANTIFLICKER 0
62 #else
63 #define USE_NOTEBOOK_ANTIFLICKER 1
64 #endif
65
66 // ----------------------------------------------------------------------------
67 // constants
68 // ----------------------------------------------------------------------------
69
70 // This is a work-around for missing defines in gcc-2.95 headers
71 #ifndef TCS_RIGHT
72 #define TCS_RIGHT 0x0002
73 #endif
74
75 #ifndef TCS_VERTICAL
76 #define TCS_VERTICAL 0x0080
77 #endif
78
79 #ifndef TCS_BOTTOM
80 #define TCS_BOTTOM TCS_RIGHT
81 #endif
82
83 // ----------------------------------------------------------------------------
84 // global variables
85 // ----------------------------------------------------------------------------
86
87 #if USE_NOTEBOOK_ANTIFLICKER
88
89 // the pointer to standard spin button wnd proc
90 static WXFARPROC gs_wndprocNotebookSpinBtn = (WXFARPROC)NULL;
91
92 // the pointer to standard tab control wnd proc
93 static WXFARPROC gs_wndprocNotebook = (WXFARPROC)NULL;
94
95 LRESULT APIENTRY _EXPORT wxNotebookWndProc(HWND hwnd,
96 UINT message,
97 WPARAM wParam,
98 LPARAM lParam);
99
100 #endif // USE_NOTEBOOK_ANTIFLICKER
101
102 // ----------------------------------------------------------------------------
103 // event table
104 // ----------------------------------------------------------------------------
105
106 #include <wx/listimpl.cpp>
107
108 WX_DEFINE_LIST( wxNotebookPageInfoList ) ;
109
110 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED)
111 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING)
112
113 BEGIN_EVENT_TABLE(wxNotebook, wxControl)
114 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange)
115 EVT_SIZE(wxNotebook::OnSize)
116 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
117
118 #if USE_NOTEBOOK_ANTIFLICKER
119 EVT_ERASE_BACKGROUND(wxNotebook::OnEraseBackground)
120 EVT_PAINT(wxNotebook::OnPaint)
121 #endif // USE_NOTEBOOK_ANTIFLICKER
122 END_EVENT_TABLE()
123
124 #if wxUSE_EXTENDED_RTTI
125 WX_DEFINE_FLAGS( wxNotebookStyle )
126
127 wxBEGIN_FLAGS( wxNotebookStyle )
128 // new style border flags, we put them first to
129 // use them for streaming out
130 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
131 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
132 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
133 wxFLAGS_MEMBER(wxBORDER_RAISED)
134 wxFLAGS_MEMBER(wxBORDER_STATIC)
135 wxFLAGS_MEMBER(wxBORDER_NONE)
136
137 // old style border flags
138 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
139 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
140 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
141 wxFLAGS_MEMBER(wxRAISED_BORDER)
142 wxFLAGS_MEMBER(wxSTATIC_BORDER)
143 wxFLAGS_MEMBER(wxBORDER)
144
145 // standard window styles
146 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
147 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
148 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
149 wxFLAGS_MEMBER(wxWANTS_CHARS)
150 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
151 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
152 wxFLAGS_MEMBER(wxVSCROLL)
153 wxFLAGS_MEMBER(wxHSCROLL)
154
155 wxFLAGS_MEMBER(wxNB_FIXEDWIDTH)
156 wxFLAGS_MEMBER(wxNB_LEFT)
157 wxFLAGS_MEMBER(wxNB_RIGHT)
158 wxFLAGS_MEMBER(wxNB_BOTTOM)
159 wxFLAGS_MEMBER(wxNB_NOPAGETHEME)
160 wxFLAGS_MEMBER(wxNB_FLAT)
161
162 wxEND_FLAGS( wxNotebookStyle )
163
164 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebook, wxControl,"wx/notebook.h")
165 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebookPageInfo, wxObject , "wx/notebook.h" )
166
167 wxCOLLECTION_TYPE_INFO( wxNotebookPageInfo * , wxNotebookPageInfoList ) ;
168
169 template<> void wxCollectionToVariantArray( wxNotebookPageInfoList const &theList, wxxVariantArray &value)
170 {
171 wxListCollectionToVariantArray<wxNotebookPageInfoList::compatibility_iterator>( theList , value ) ;
172 }
173
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 )
177
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()
181
182 wxBEGIN_HANDLERS_TABLE(wxNotebook)
183 wxEND_HANDLERS_TABLE()
184
185 wxCONSTRUCTOR_5( wxNotebook , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle)
186
187
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()
194
195 wxBEGIN_HANDLERS_TABLE(wxNotebookPageInfo)
196 wxEND_HANDLERS_TABLE()
197
198 wxCONSTRUCTOR_4( wxNotebookPageInfo , wxNotebookPage* , Page , wxString , Text , bool , Selected , int , ImageId )
199
200 #else
201 IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
202 IMPLEMENT_DYNAMIC_CLASS(wxNotebookPageInfo, wxObject )
203 #endif
204 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxNotifyEvent)
205
206 // ============================================================================
207 // implementation
208 // ============================================================================
209
210 // ----------------------------------------------------------------------------
211 // wxNotebook construction
212 // ----------------------------------------------------------------------------
213
214 const wxNotebookPageInfoList& wxNotebook::GetPageInfos() const
215 {
216 wxNotebookPageInfoList* list = const_cast< wxNotebookPageInfoList* >( &m_pageInfos ) ;
217 WX_CLEAR_LIST( wxNotebookPageInfoList , *list ) ;
218 for( size_t i = 0 ; i < GetPageCount() ; ++i )
219 {
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 ) ;
223 }
224 return m_pageInfos ;
225 }
226
227 // common part of all ctors
228 void wxNotebook::Init()
229 {
230 m_imageList = NULL;
231 m_nSelection = -1;
232
233 #if wxUSE_UXTHEME
234 m_hbrBackground = NULL;
235 #endif // wxUSE_UXTHEME
236
237 #if USE_NOTEBOOK_ANTIFLICKER
238 m_hasSubclassedUpdown = false;
239 #endif // USE_NOTEBOOK_ANTIFLICKER
240 }
241
242 // default for dynamic class
243 wxNotebook::wxNotebook()
244 {
245 Init();
246 }
247
248 // the same arguments as for wxControl
249 wxNotebook::wxNotebook(wxWindow *parent,
250 wxWindowID id,
251 const wxPoint& pos,
252 const wxSize& size,
253 long style,
254 const wxString& name)
255 {
256 Init();
257
258 Create(parent, id, pos, size, style, name);
259 }
260
261 // Create() function
262 bool wxNotebook::Create(wxWindow *parent,
263 wxWindowID id,
264 const wxPoint& pos,
265 const wxSize& size,
266 long style,
267 const wxString& name)
268 {
269 #ifdef __WXWINCE__
270 // Not sure why, but without this style, there is no border
271 // around the notebook tabs.
272 if (style & wxNB_FLAT)
273 style |= wxBORDER_SUNKEN;
274 #endif
275
276 // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the
277 // control is simply not rendered correctly), so disable them in this case
278 const int verComCtl32 = wxApp::GetComCtl32Version();
279 if ( verComCtl32 == 600 )
280 {
281 // check if we use themes at all -- if we don't, we're still ok
282 #if wxUSE_UXTHEME
283 if ( wxUxThemeEngine::GetIfActive() )
284 #endif
285 {
286 style &= ~(wxNB_BOTTOM | wxNB_LEFT | wxNB_RIGHT);
287 }
288 }
289
290 LPCTSTR className = WC_TABCONTROL;
291
292 #if USE_NOTEBOOK_ANTIFLICKER
293 // SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it
294 // causes horrible flicker when resizing notebook, so get rid of it by
295 // using a class without these styles (but otherwise identical to it)
296 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
297 {
298 static ClassRegistrar s_clsNotebook;
299 if ( !s_clsNotebook.IsInitialized() )
300 {
301 // get a copy of standard class and modify it
302 WNDCLASS wc;
303
304 if ( ::GetClassInfo(NULL, WC_TABCONTROL, &wc) )
305 {
306 gs_wndprocNotebook =
307 wx_reinterpret_cast(WXFARPROC, wc.lpfnWndProc);
308 wc.lpszClassName = wxT("_wx_SysTabCtl32");
309 wc.style &= ~(CS_HREDRAW | CS_VREDRAW);
310 wc.hInstance = wxGetInstance();
311 wc.lpfnWndProc = wxNotebookWndProc;
312 s_clsNotebook.Register(wc);
313 }
314 else
315 {
316 wxLogLastError(_T("GetClassInfoEx(SysTabCtl32)"));
317 }
318 }
319
320 // use our custom class if available but fall back to the standard
321 // notebook if we failed to register it
322 if ( s_clsNotebook.IsRegistered() )
323 {
324 // it's ok to use c_str() here as the static s_clsNotebook object
325 // has sufficiently long lifetime
326 className = s_clsNotebook.GetName().c_str();
327 }
328 }
329 #endif // USE_NOTEBOOK_ANTIFLICKER
330
331 if ( !CreateControl(parent, id, pos, size, style | wxTAB_TRAVERSAL,
332 wxDefaultValidator, name) )
333 return false;
334
335 if ( !MSWCreateControl(className, wxEmptyString, pos, size) )
336 return false;
337
338 #if wxUSE_UXTHEME
339 if ( HasFlag(wxNB_NOPAGETHEME) ||
340 wxSystemOptions::IsFalse(wxT("msw.notebook.themed-background")) )
341 {
342 SetBackgroundColour(GetThemeBackgroundColour());
343 }
344 else // use themed background by default
345 {
346 // create backing store
347 UpdateBgBrush();
348 }
349 #endif // wxUSE_UXTHEME
350
351 // Undocumented hack to get flat notebook style
352 // In fact, we should probably only do this in some
353 // curcumstances, i.e. if we know we will have a border
354 // at the bottom (the tab control doesn't draw it itself)
355 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
356 if (HasFlag(wxNB_FLAT))
357 {
358 SendMessage(GetHwnd(), CCM_SETVERSION, COMCTL32_VERSION, 0);
359 if (!m_hasBgCol)
360 SetBackgroundColour(*wxWHITE);
361 }
362 #endif
363 return true;
364 }
365
366 WXDWORD wxNotebook::MSWGetStyle(long style, WXDWORD *exstyle) const
367 {
368 WXDWORD tabStyle = wxControl::MSWGetStyle(style, exstyle);
369
370 tabStyle |= WS_TABSTOP | TCS_TABS;
371
372 if ( style & wxNB_MULTILINE )
373 tabStyle |= TCS_MULTILINE;
374 if ( style & wxNB_FIXEDWIDTH )
375 tabStyle |= TCS_FIXEDWIDTH;
376
377 if ( style & wxNB_BOTTOM )
378 tabStyle |= TCS_RIGHT;
379 else if ( style & wxNB_LEFT )
380 tabStyle |= TCS_VERTICAL;
381 else if ( style & wxNB_RIGHT )
382 tabStyle |= TCS_VERTICAL | TCS_RIGHT;
383
384 // ex style
385 if ( exstyle )
386 {
387 // note that we never want to have the default WS_EX_CLIENTEDGE style
388 // as it looks too ugly for the notebooks
389 *exstyle = 0;
390 }
391
392 return tabStyle;
393 }
394
395 wxNotebook::~wxNotebook()
396 {
397 #if wxUSE_UXTHEME
398 if ( m_hbrBackground )
399 ::DeleteObject((HBRUSH)m_hbrBackground);
400 #endif // wxUSE_UXTHEME
401 }
402
403 // ----------------------------------------------------------------------------
404 // wxNotebook accessors
405 // ----------------------------------------------------------------------------
406
407 size_t wxNotebook::GetPageCount() const
408 {
409 // consistency check
410 wxASSERT( (int)m_pages.Count() == TabCtrl_GetItemCount(GetHwnd()) );
411
412 return m_pages.Count();
413 }
414
415 int wxNotebook::GetRowCount() const
416 {
417 return TabCtrl_GetRowCount(GetHwnd());
418 }
419
420 int wxNotebook::SetSelection(size_t nPage)
421 {
422 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
423
424 if ( int(nPage) != m_nSelection )
425 {
426 wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_windowId);
427 event.SetSelection(nPage);
428 event.SetOldSelection(m_nSelection);
429 event.SetEventObject(this);
430 if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
431 {
432 // program allows the page change
433 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
434 (void)GetEventHandler()->ProcessEvent(event);
435
436 TabCtrl_SetCurSel(GetHwnd(), nPage);
437 }
438 }
439
440 return m_nSelection;
441 }
442
443 bool wxNotebook::SetPageText(size_t nPage, const wxString& strText)
444 {
445 wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
446
447 TC_ITEM tcItem;
448 tcItem.mask = TCIF_TEXT;
449 tcItem.pszText = (wxChar *)strText.c_str();
450
451 return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
452 }
453
454 wxString wxNotebook::GetPageText(size_t nPage) const
455 {
456 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxEmptyString, wxT("notebook page out of range") );
457
458 wxChar buf[256];
459 TC_ITEM tcItem;
460 tcItem.mask = TCIF_TEXT;
461 tcItem.pszText = buf;
462 tcItem.cchTextMax = WXSIZEOF(buf);
463
464 wxString str;
465 if ( TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) )
466 str = tcItem.pszText;
467
468 return str;
469 }
470
471 int wxNotebook::GetPageImage(size_t nPage) const
472 {
473 wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") );
474
475 TC_ITEM tcItem;
476 tcItem.mask = TCIF_IMAGE;
477
478 return TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) ? tcItem.iImage : -1;
479 }
480
481 bool wxNotebook::SetPageImage(size_t nPage, int nImage)
482 {
483 wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
484
485 TC_ITEM tcItem;
486 tcItem.mask = TCIF_IMAGE;
487 tcItem.iImage = nImage;
488
489 return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
490 }
491
492 void wxNotebook::SetImageList(wxImageList* imageList)
493 {
494 wxNotebookBase::SetImageList(imageList);
495
496 if ( imageList )
497 {
498 TabCtrl_SetImageList(GetHwnd(), (HIMAGELIST)imageList->GetHIMAGELIST());
499 }
500 }
501
502 // ----------------------------------------------------------------------------
503 // wxNotebook size settings
504 // ----------------------------------------------------------------------------
505
506 wxRect wxNotebook::GetPageSize() const
507 {
508 wxRect r;
509
510 RECT rc;
511 ::GetClientRect(GetHwnd(), &rc);
512
513 // This check is to work around a bug in TabCtrl_AdjustRect which will
514 // cause a crash on win2k or on XP with themes disabled if either
515 // wxNB_MULTILINE is used or tabs are placed on a side, if the rectangle
516 // is too small.
517 //
518 // The value of 20 is chosen arbitrarily but seems to work
519 if ( rc.right > 20 && rc.bottom > 20 )
520 {
521 TabCtrl_AdjustRect(GetHwnd(), false, &rc);
522
523 wxCopyRECTToRect(rc, r);
524 }
525
526 return r;
527 }
528
529 void wxNotebook::SetPageSize(const wxSize& size)
530 {
531 // transform the page size into the notebook size
532 RECT rc;
533 rc.left =
534 rc.top = 0;
535 rc.right = size.x;
536 rc.bottom = size.y;
537
538 TabCtrl_AdjustRect(GetHwnd(), true, &rc);
539
540 // and now set it
541 SetSize(rc.right - rc.left, rc.bottom - rc.top);
542 }
543
544 void wxNotebook::SetPadding(const wxSize& padding)
545 {
546 TabCtrl_SetPadding(GetHwnd(), padding.x, padding.y);
547 }
548
549 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
550 // style.
551 void wxNotebook::SetTabSize(const wxSize& sz)
552 {
553 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE, 0, MAKELPARAM(sz.x, sz.y));
554 }
555
556 wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
557 {
558 wxSize sizeTotal = sizePage;
559
560 // We need to make getting tab size part of the wxWidgets API.
561 wxSize tabSize;
562 if (GetPageCount() > 0)
563 {
564 RECT rect;
565 TabCtrl_GetItemRect((HWND) GetHWND(), 0, & rect);
566 tabSize.x = rect.right - rect.left;
567 tabSize.y = rect.bottom - rect.top;
568 }
569 if ( HasFlag(wxNB_LEFT) || HasFlag(wxNB_RIGHT) )
570 {
571 sizeTotal.x += tabSize.x + 7;
572 sizeTotal.y += 7;
573 }
574 else
575 {
576 sizeTotal.x += 7;
577 sizeTotal.y += tabSize.y + 7;
578 }
579
580 return sizeTotal;
581 }
582
583 void wxNotebook::AdjustPageSize(wxNotebookPage *page)
584 {
585 wxCHECK_RET( page, _T("NULL page in wxNotebook::AdjustPageSize") );
586
587 const wxRect r = GetPageSize();
588 if ( !r.IsEmpty() )
589 {
590 page->SetSize(r);
591 }
592 }
593
594 // ----------------------------------------------------------------------------
595 // wxNotebook operations
596 // ----------------------------------------------------------------------------
597
598 // remove one page from the notebook, without deleting
599 wxNotebookPage *wxNotebook::DoRemovePage(size_t nPage)
600 {
601 wxNotebookPage *pageRemoved = wxNotebookBase::DoRemovePage(nPage);
602 if ( !pageRemoved )
603 return NULL;
604
605 TabCtrl_DeleteItem(GetHwnd(), nPage);
606
607 if ( m_pages.IsEmpty() )
608 {
609 // no selection any more, the notebook becamse empty
610 m_nSelection = -1;
611 }
612 else // notebook still not empty
613 {
614 int selNew = TabCtrl_GetCurSel(GetHwnd());
615 if (selNew != -1)
616 {
617 // No selection change, just refresh the current selection.
618 // Because it could be that the slection index changed
619 // we need to update it.
620 // Note: this does not mean the selection it self changed.
621 m_nSelection = selNew;
622 m_pages[m_nSelection]->Refresh();
623 }
624 else if (int(nPage) == m_nSelection)
625 {
626 // The selection was deleted.
627
628 // Determine new selection.
629 if (m_nSelection == int(GetPageCount()))
630 selNew = m_nSelection - 1;
631 else
632 selNew = m_nSelection;
633
634 // m_nSelection must be always valid so reset it before calling
635 // SetSelection()
636 m_nSelection = -1;
637 SetSelection(selNew);
638 }
639 else
640 {
641 wxFAIL; // Windows did not behave ok.
642 }
643 }
644
645 return pageRemoved;
646 }
647
648 // remove all pages
649 bool wxNotebook::DeleteAllPages()
650 {
651 size_t nPageCount = GetPageCount();
652 size_t nPage;
653 for ( nPage = 0; nPage < nPageCount; nPage++ )
654 delete m_pages[nPage];
655
656 m_pages.Clear();
657
658 TabCtrl_DeleteAllItems(GetHwnd());
659
660 m_nSelection = -1;
661
662 InvalidateBestSize();
663 return true;
664 }
665
666 // same as AddPage() but does it at given position
667 bool wxNotebook::InsertPage(size_t nPage,
668 wxNotebookPage *pPage,
669 const wxString& strText,
670 bool bSelect,
671 int imageId)
672 {
673 wxCHECK_MSG( pPage != NULL, false, _T("NULL page in wxNotebook::InsertPage") );
674 wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false,
675 _T("invalid index in wxNotebook::InsertPage") );
676
677 wxASSERT_MSG( pPage->GetParent() == this,
678 _T("notebook pages must have notebook as parent") );
679
680 // add a new tab to the control
681 // ----------------------------
682
683 // init all fields to 0
684 TC_ITEM tcItem;
685 wxZeroMemory(tcItem);
686
687 // set the image, if any
688 if ( imageId != -1 )
689 {
690 tcItem.mask |= TCIF_IMAGE;
691 tcItem.iImage = imageId;
692 }
693
694 // and the text
695 if ( !strText.empty() )
696 {
697 tcItem.mask |= TCIF_TEXT;
698 tcItem.pszText = (wxChar *)strText.c_str(); // const_cast
699 }
700
701 // hide the page: unless it is selected, it shouldn't be shown (and if it
702 // is selected it will be shown later)
703 HWND hwnd = GetWinHwnd(pPage);
704 SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);
705
706 // this updates internal flag too -- otherwise it would get out of sync
707 // with the real state
708 pPage->Show(false);
709
710
711 // fit the notebook page to the tab control's display area: this should be
712 // done before adding it to the notebook or TabCtrl_InsertItem() will
713 // change the notebooks size itself!
714 AdjustPageSize(pPage);
715
716 // finally do insert it
717 if ( TabCtrl_InsertItem(GetHwnd(), nPage, &tcItem) == -1 )
718 {
719 wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());
720
721 return false;
722 }
723
724 // succeeded: save the pointer to the page
725 m_pages.Insert(pPage, nPage);
726
727 // we may need to adjust the size again if the notebook size changed:
728 // normally this only happens for the first page we add (the tabs which
729 // hadn't been there before are now shown) but for a multiline notebook it
730 // can happen for any page at all as a new row could have been started
731 if ( m_pages.GetCount() == 1 || HasFlag(wxNB_MULTILINE) )
732 {
733 AdjustPageSize(pPage);
734 }
735
736 // now deal with the selection
737 // ---------------------------
738
739 // if the inserted page is before the selected one, we must update the
740 // index of the selected page
741 if ( int(nPage) <= m_nSelection )
742 {
743 // one extra page added
744 m_nSelection++;
745 }
746
747 // some page should be selected: either this one or the first one if there
748 // is still no selection
749 int selNew = -1;
750 if ( bSelect )
751 selNew = nPage;
752 else if ( m_nSelection == -1 )
753 selNew = 0;
754
755 if ( selNew != -1 )
756 SetSelection(selNew);
757
758 InvalidateBestSize();
759
760 return true;
761 }
762
763 int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
764 {
765 TC_HITTESTINFO hitTestInfo;
766 hitTestInfo.pt.x = pt.x;
767 hitTestInfo.pt.y = pt.y;
768 int item = TabCtrl_HitTest(GetHwnd(), &hitTestInfo);
769
770 if ( flags )
771 {
772 *flags = 0;
773
774 if ((hitTestInfo.flags & TCHT_NOWHERE) == TCHT_NOWHERE)
775 *flags |= wxNB_HITTEST_NOWHERE;
776 if ((hitTestInfo.flags & TCHT_ONITEM) == TCHT_ONITEM)
777 *flags |= wxNB_HITTEST_ONITEM;
778 if ((hitTestInfo.flags & TCHT_ONITEMICON) == TCHT_ONITEMICON)
779 *flags |= wxNB_HITTEST_ONICON;
780 if ((hitTestInfo.flags & TCHT_ONITEMLABEL) == TCHT_ONITEMLABEL)
781 *flags |= wxNB_HITTEST_ONLABEL;
782 }
783
784 return item;
785 }
786
787 // ----------------------------------------------------------------------------
788 // flicker-less notebook redraw
789 // ----------------------------------------------------------------------------
790
791 #if USE_NOTEBOOK_ANTIFLICKER
792
793 // wnd proc for the spin button
794 LRESULT APIENTRY _EXPORT wxNotebookSpinBtnWndProc(HWND hwnd,
795 UINT message,
796 WPARAM wParam,
797 LPARAM lParam)
798 {
799 if ( message == WM_ERASEBKGND )
800 return 0;
801
802 return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebookSpinBtn,
803 hwnd, message, wParam, lParam);
804 }
805
806 LRESULT APIENTRY _EXPORT wxNotebookWndProc(HWND hwnd,
807 UINT message,
808 WPARAM wParam,
809 LPARAM lParam)
810 {
811 return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebook,
812 hwnd, message, wParam, lParam);
813 }
814
815
816
817 void wxNotebook::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
818 {
819 // do nothing here
820 }
821
822 void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event))
823 {
824 wxPaintDC dc(this);
825 wxMemoryDC memdc;
826 RECT rc;
827 ::GetClientRect(GetHwnd(), &rc);
828 wxBitmap bmp(rc.right, rc.bottom);
829 memdc.SelectObject(bmp);
830
831 // if there is no special brush just use the solid background colour
832 HBRUSH hbr = (HBRUSH)m_hbrBackground;
833 wxBrush brush;
834 if ( !hbr )
835 {
836 brush = wxBrush(GetBackgroundColour());
837 hbr = GetHbrushOf(brush);
838 }
839
840 ::FillRect(GetHdcOf(memdc), &rc, hbr);
841
842 MSWDefWindowProc(WM_PAINT, (WPARAM)memdc.GetHDC(), 0);
843
844 dc.Blit(0, 0, rc.right, rc.bottom, &memdc, 0, 0);
845 }
846
847 #endif // USE_NOTEBOOK_ANTIFLICKER
848
849 // ----------------------------------------------------------------------------
850 // wxNotebook callbacks
851 // ----------------------------------------------------------------------------
852
853 void wxNotebook::OnSize(wxSizeEvent& event)
854 {
855 if ( GetPageCount() == 0 )
856 {
857 // Prevents droppings on resize, but does cause some flicker
858 // when there are no pages.
859 Refresh();
860 event.Skip();
861 return;
862 }
863 #ifndef __WXWINCE__
864 else
865 {
866 // Without this, we can sometimes get droppings at the edges
867 // of a notebook, for example a notebook in a splitter window.
868 // This needs to be reconciled with the RefreshRect calls
869 // at the end of this function, which weren't enough to prevent
870 // the droppings.
871
872 wxSize sz = GetClientSize();
873
874 // Refresh right side
875 wxRect rect(sz.x-4, 0, 4, sz.y);
876 RefreshRect(rect);
877
878 // Refresh bottom side
879 rect = wxRect(0, sz.y-4, sz.x, 4);
880 RefreshRect(rect);
881
882 // Refresh left side
883 rect = wxRect(0, 0, 4, sz.y);
884 RefreshRect(rect);
885 }
886 #endif // !__WXWINCE__
887
888 // fit all the notebook pages to the tab control's display area
889
890 RECT rc;
891 rc.left = rc.top = 0;
892 GetSize((int *)&rc.right, (int *)&rc.bottom);
893
894 // save the total size, we'll use it below
895 int widthNbook = rc.right - rc.left,
896 heightNbook = rc.bottom - rc.top;
897
898 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
899 // returns completely false values for multiline tab controls after the tabs
900 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
901 //
902 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
903 //
904 // and the only work around I could find was this ugly hack... without it
905 // simply toggling the "multiline" checkbox in the notebook sample resulted
906 // in a noticeable page displacement
907 if ( HasFlag(wxNB_MULTILINE) )
908 {
909 // avoid an infinite recursion: we get another notification too!
910 static bool s_isInOnSize = false;
911
912 if ( !s_isInOnSize )
913 {
914 s_isInOnSize = true;
915 SendMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED,
916 MAKELPARAM(rc.right, rc.bottom));
917 s_isInOnSize = false;
918 }
919 }
920
921 #if wxUSE_UXTHEME
922 // background bitmap size has changed, update the brush using it too
923 UpdateBgBrush();
924 #endif // wxUSE_UXTHEME
925
926 TabCtrl_AdjustRect(GetHwnd(), false, &rc);
927
928 int width = rc.right - rc.left,
929 height = rc.bottom - rc.top;
930 size_t nCount = m_pages.Count();
931 for ( size_t nPage = 0; nPage < nCount; nPage++ ) {
932 wxNotebookPage *pPage = m_pages[nPage];
933 pPage->SetSize(rc.left, rc.top, width, height);
934 }
935
936
937 // unless we had already repainted everything, we now need to refresh
938 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
939 {
940 // invalidate areas not covered by pages
941 RefreshRect(wxRect(0, 0, widthNbook, rc.top), false);
942 RefreshRect(wxRect(0, rc.top, rc.left, height), false);
943 RefreshRect(wxRect(0, rc.bottom, widthNbook, heightNbook - rc.bottom),
944 false);
945 RefreshRect(wxRect(rc.right, rc.top, widthNbook - rc.right, height),
946 false);
947 }
948
949 #if USE_NOTEBOOK_ANTIFLICKER
950 // subclass the spin control used by the notebook to scroll pages to
951 // prevent it from flickering on resize
952 if ( !m_hasSubclassedUpdown )
953 {
954 // iterate over all child windows to find spin button
955 for ( HWND child = ::GetWindow(GetHwnd(), GW_CHILD);
956 child;
957 child = ::GetWindow(child, GW_HWNDNEXT) )
958 {
959 wxWindow *childWindow = wxFindWinFromHandle((WXHWND)child);
960
961 // see if it exists, if no wxWindow found then assume it's the spin
962 // btn
963 if ( !childWindow )
964 {
965 // subclass the spin button to override WM_ERASEBKGND
966 if ( !gs_wndprocNotebookSpinBtn )
967 gs_wndprocNotebookSpinBtn = (WXFARPROC)wxGetWindowProc(child);
968
969 wxSetWindowProc(child, wxNotebookSpinBtnWndProc);
970 m_hasSubclassedUpdown = true;
971 break;
972 }
973 }
974 }
975 #endif // USE_NOTEBOOK_ANTIFLICKER
976
977 event.Skip();
978 }
979
980 void wxNotebook::OnSelChange(wxNotebookEvent& event)
981 {
982 // is it our tab control?
983 if ( event.GetEventObject() == this )
984 {
985 int sel = event.GetOldSelection();
986 if ( sel != -1 )
987 m_pages[sel]->Show(false);
988
989 sel = event.GetSelection();
990 if ( sel != -1 )
991 {
992 wxNotebookPage *pPage = m_pages[sel];
993 pPage->Show(true);
994
995 // As per bug report:
996 // http://sourceforge.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863,
997 // we should not set the page focus (and thereby the focus for
998 // a child window) since it erroneously selects radio button controls and also
999 // breaks keyboard handling for a notebook's scroll buttons. So
1000 // we always focus the notebook and not the page.
1001 SetFocus();
1002
1003 }
1004 else // no pages in the notebook, give the focus to itself
1005 {
1006 SetFocus();
1007 }
1008
1009 m_nSelection = sel;
1010 }
1011
1012 // we want to give others a chance to process this message as well
1013 event.Skip();
1014 }
1015
1016 bool wxNotebook::MSWTranslateMessage(WXMSG *wxmsg)
1017 {
1018 const MSG * const msg = (MSG *)wxmsg;
1019
1020 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
1021 // TAB will be passed to the currently selected page, CTRL+TAB and
1022 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
1023 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
1024 // process it.
1025 if ( msg->message == WM_KEYDOWN && msg->wParam == VK_TAB &&
1026 msg->hwnd == GetHwnd() &&
1027 (wxIsCtrlDown() || !wxIsShiftDown()) )
1028 {
1029 return MSWProcessMessage(wxmsg);
1030 }
1031
1032 return false;
1033 }
1034
1035 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
1036 {
1037 if ( event.IsWindowChange() ) {
1038 // change pages
1039 AdvanceSelection(event.GetDirection());
1040 }
1041 else {
1042 // we get this event in 3 cases
1043 //
1044 // a) one of our pages might have generated it because the user TABbed
1045 // out from it in which case we should propagate the event upwards and
1046 // our parent will take care of setting the focus to prev/next sibling
1047 //
1048 // or
1049 //
1050 // b) the parent panel wants to give the focus to us so that we
1051 // forward it to our selected page. We can't deal with this in
1052 // OnSetFocus() because we don't know which direction the focus came
1053 // from in this case and so can't choose between setting the focus to
1054 // first or last panel child
1055 //
1056 // or
1057 //
1058 // c) we ourselves (see MSWTranslateMessage) generated the event
1059 //
1060 wxWindow * const parent = GetParent();
1061
1062 // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
1063 const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
1064 const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
1065
1066 if ( isFromParent || isFromSelf )
1067 {
1068 // no, it doesn't come from child, case (b) or (c): forward to a
1069 // page but only if direction is backwards (TAB) or from ourselves,
1070 if ( m_nSelection != -1 &&
1071 (!event.GetDirection() || isFromSelf) )
1072 {
1073 // so that the page knows that the event comes from it's parent
1074 // and is being propagated downwards
1075 event.SetEventObject(this);
1076
1077 wxWindow *page = m_pages[m_nSelection];
1078 if ( !page->GetEventHandler()->ProcessEvent(event) )
1079 {
1080 page->SetFocus();
1081 }
1082 //else: page manages focus inside it itself
1083 }
1084 else // otherwise set the focus to the notebook itself
1085 {
1086 SetFocus();
1087 }
1088 }
1089 else
1090 {
1091 // it comes from our child, case (a), pass to the parent, but only
1092 // if the direction is forwards. Otherwise set the focus to the
1093 // notebook itself. The notebook is always the 'first' control of a
1094 // page.
1095 if ( !event.GetDirection() )
1096 {
1097 SetFocus();
1098 }
1099 else if ( parent )
1100 {
1101 event.SetCurrentFocus(this);
1102 parent->GetEventHandler()->ProcessEvent(event);
1103 }
1104 }
1105 }
1106 }
1107
1108 #if wxUSE_UXTHEME
1109
1110 bool wxNotebook::DoDrawBackground(WXHDC hDC, wxWindow *child)
1111 {
1112 wxUxThemeHandle theme(child ? child : this, L"TAB");
1113 if ( !theme )
1114 return false;
1115
1116 // get the notebook client rect (we're not interested in drawing tabs
1117 // themselves)
1118 wxRect r = GetPageSize();
1119 if ( r.IsEmpty() )
1120 return false;
1121
1122 RECT rc;
1123 wxCopyRectToRECT(r, rc);
1124
1125 // map rect to the coords of the window we're drawing in
1126 if ( child )
1127 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1128
1129 // we have the content area (page size), but we need to draw all of the
1130 // background for it to be aligned correctly
1131 wxUxThemeEngine::Get()->GetThemeBackgroundExtent
1132 (
1133 theme,
1134 (HDC) hDC,
1135 9 /* TABP_PANE */,
1136 0,
1137 &rc,
1138 &rc
1139 );
1140 wxUxThemeEngine::Get()->DrawThemeBackground
1141 (
1142 theme,
1143 (HDC) hDC,
1144 9 /* TABP_PANE */,
1145 0,
1146 &rc,
1147 NULL
1148 );
1149
1150 return true;
1151 }
1152
1153 WXHBRUSH wxNotebook::QueryBgBitmap()
1154 {
1155 wxRect r = GetPageSize();
1156 if ( r.IsEmpty() )
1157 return 0;
1158
1159 WindowHDC hDC(GetHwnd());
1160 MemoryHDC hDCMem(hDC);
1161 CompatibleBitmap hBmp(hDC, r.x + r.width, r.y + r.height);
1162
1163 SelectInHDC selectBmp(hDCMem, hBmp);
1164
1165 if ( !DoDrawBackground((WXHDC)(HDC)hDCMem) )
1166 return 0;
1167
1168 return (WXHBRUSH)::CreatePatternBrush(hBmp);
1169 }
1170
1171 void wxNotebook::UpdateBgBrush()
1172 {
1173 if ( m_hbrBackground )
1174 ::DeleteObject((HBRUSH)m_hbrBackground);
1175
1176 if ( !m_hasBgCol && wxUxThemeEngine::GetIfActive() )
1177 {
1178 m_hbrBackground = QueryBgBitmap();
1179 }
1180 else // no themes or we've got user-defined solid colour
1181 {
1182 m_hbrBackground = NULL;
1183 }
1184 }
1185
1186 WXHBRUSH wxNotebook::MSWGetBgBrushForChild(WXHDC hDC, WXHWND hWnd)
1187 {
1188 if ( m_hbrBackground )
1189 {
1190 // before drawing with the background brush, we need to position it
1191 // correctly
1192 RECT rc;
1193 ::GetWindowRect((HWND)hWnd, &rc);
1194
1195 ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
1196
1197 if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
1198 {
1199 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
1200 }
1201
1202 return m_hbrBackground;
1203 }
1204
1205 return wxNotebookBase::MSWGetBgBrushForChild(hDC, hWnd);
1206 }
1207
1208 bool wxNotebook::MSWPrintChild(WXHDC hDC, wxWindow *child)
1209 {
1210 // solid background colour overrides themed background drawing
1211 if ( !UseBgCol() && DoDrawBackground(hDC, child) )
1212 return true;
1213
1214 // If we're using a solid colour (for example if we've switched off
1215 // theming for this notebook), paint it
1216 if (UseBgCol())
1217 {
1218 wxRect r = GetPageSize();
1219 if ( r.IsEmpty() )
1220 return false;
1221
1222 RECT rc;
1223 wxCopyRectToRECT(r, rc);
1224
1225 // map rect to the coords of the window we're drawing in
1226 if ( child )
1227 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1228
1229 wxBrush brush(GetBackgroundColour());
1230 HBRUSH hbr = GetHbrushOf(brush);
1231
1232 ::FillRect((HDC) hDC, &rc, hbr);
1233
1234 return true;
1235 }
1236
1237 return wxNotebookBase::MSWPrintChild(hDC, child);
1238 }
1239
1240 #endif // wxUSE_UXTHEME
1241
1242 // Windows only: attempts to get colour for UX theme page background
1243 wxColour wxNotebook::GetThemeBackgroundColour() const
1244 {
1245 #if wxUSE_UXTHEME
1246 if (wxUxThemeEngine::Get())
1247 {
1248 wxUxThemeHandle hTheme((wxNotebook*) this, L"TAB");
1249 if (hTheme)
1250 {
1251 // This is total guesswork.
1252 // See PlatformSDK\Include\Tmschema.h for values
1253 COLORREF themeColor;
1254 wxUxThemeEngine::Get()->GetThemeColor(
1255 hTheme,
1256 10 /* TABP_BODY */,
1257 1 /* NORMAL */,
1258 3821 /* FILLCOLORHINT */,
1259 &themeColor);
1260
1261 /*
1262 [DS] Workaround for WindowBlinds:
1263 Some themes return a near black theme color using FILLCOLORHINT,
1264 this makes notebook pages have an ugly black background and makes
1265 text (usually black) unreadable. Retry again with FILLCOLOR.
1266
1267 This workaround potentially breaks appearance of some themes,
1268 but in practice it already fixes some themes.
1269 */
1270 if (themeColor == 1)
1271 {
1272 wxUxThemeEngine::Get()->GetThemeColor(
1273 hTheme,
1274 10 /* TABP_BODY */,
1275 1 /* NORMAL */,
1276 3802 /* FILLCOLOR */,
1277 &themeColor);
1278 }
1279
1280 return wxRGBToColour(themeColor);
1281 }
1282 }
1283 #endif // wxUSE_UXTHEME
1284
1285 return GetBackgroundColour();
1286 }
1287
1288 // ----------------------------------------------------------------------------
1289 // wxNotebook base class virtuals
1290 // ----------------------------------------------------------------------------
1291
1292 #if wxUSE_CONSTRAINTS
1293
1294 // override these 2 functions to do nothing: everything is done in OnSize
1295
1296 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
1297 {
1298 // don't set the sizes of the pages - their correct size is not yet known
1299 wxControl::SetConstraintSizes(false);
1300 }
1301
1302 bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
1303 {
1304 return true;
1305 }
1306
1307 #endif // wxUSE_CONSTRAINTS
1308
1309 // ----------------------------------------------------------------------------
1310 // wxNotebook Windows message handlers
1311 // ----------------------------------------------------------------------------
1312
1313 bool wxNotebook::MSWOnScroll(int orientation, WXWORD nSBCode,
1314 WXWORD pos, WXHWND control)
1315 {
1316 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1317 // up-down control
1318 if ( control )
1319 return false;
1320
1321 return wxNotebookBase::MSWOnScroll(orientation, nSBCode, pos, control);
1322 }
1323
1324 bool wxNotebook::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
1325 {
1326 wxNotebookEvent event(wxEVT_NULL, m_windowId);
1327
1328 NMHDR* hdr = (NMHDR *)lParam;
1329 switch ( hdr->code ) {
1330 case TCN_SELCHANGE:
1331 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
1332 break;
1333
1334 case TCN_SELCHANGING:
1335 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
1336 break;
1337
1338 default:
1339 return wxControl::MSWOnNotify(idCtrl, lParam, result);
1340 }
1341
1342 event.SetSelection(TabCtrl_GetCurSel(GetHwnd()));
1343 event.SetOldSelection(m_nSelection);
1344 event.SetEventObject(this);
1345 event.SetInt(idCtrl);
1346
1347 bool processed = GetEventHandler()->ProcessEvent(event);
1348 *result = !event.IsAllowed();
1349 return processed;
1350 }
1351
1352 #endif // wxUSE_NOTEBOOK