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