]> git.saurik.com Git - wxWidgets.git/blob - src/msw/notebook.cpp
checking whether a size_t page index is >= 0 is unnecessary (and generates a SGI...
[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 else // use themed background by default
349 {
350 // create backing store
351 UpdateBgBrush();
352 }
353 #endif // wxUSE_UXTHEME
354
355 // Undocumented hack to get flat notebook style
356 // In fact, we should probably only do this in some
357 // curcumstances, i.e. if we know we will have a border
358 // at the bottom (the tab control doesn't draw it itself)
359 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
360 if (HasFlag(wxNB_FLAT))
361 {
362 SendMessage(GetHwnd(), CCM_SETVERSION, COMCTL32_VERSION, 0);
363 if (!m_hasBgCol)
364 SetBackgroundColour(*wxWHITE);
365 }
366 #endif
367 return true;
368 }
369
370 WXDWORD wxNotebook::MSWGetStyle(long style, WXDWORD *exstyle) const
371 {
372 WXDWORD tabStyle = wxControl::MSWGetStyle(style, exstyle);
373
374 tabStyle |= WS_TABSTOP | TCS_TABS;
375
376 if ( style & wxNB_MULTILINE )
377 tabStyle |= TCS_MULTILINE;
378 if ( style & wxNB_FIXEDWIDTH )
379 tabStyle |= TCS_FIXEDWIDTH;
380
381 if ( style & wxNB_BOTTOM )
382 tabStyle |= TCS_RIGHT;
383 else if ( style & wxNB_LEFT )
384 tabStyle |= TCS_VERTICAL;
385 else if ( style & wxNB_RIGHT )
386 tabStyle |= TCS_VERTICAL | TCS_RIGHT;
387
388 // ex style
389 if ( exstyle )
390 {
391 // note that we never want to have the default WS_EX_CLIENTEDGE style
392 // as it looks too ugly for the notebooks
393 *exstyle = 0;
394 }
395
396 return tabStyle;
397 }
398
399 wxNotebook::~wxNotebook()
400 {
401 #if wxUSE_UXTHEME
402 if ( m_hbrBackground )
403 ::DeleteObject((HBRUSH)m_hbrBackground);
404 #endif // wxUSE_UXTHEME
405 }
406
407 // ----------------------------------------------------------------------------
408 // wxNotebook accessors
409 // ----------------------------------------------------------------------------
410
411 size_t wxNotebook::GetPageCount() const
412 {
413 // consistency check
414 wxASSERT( (int)m_pages.Count() == TabCtrl_GetItemCount(GetHwnd()) );
415
416 return m_pages.Count();
417 }
418
419 int wxNotebook::GetRowCount() const
420 {
421 return TabCtrl_GetRowCount(GetHwnd());
422 }
423
424 int wxNotebook::SetSelection(size_t nPage)
425 {
426 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
427
428 if ( int(nPage) != m_nSelection )
429 {
430 wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_windowId);
431 event.SetSelection(nPage);
432 event.SetOldSelection(m_nSelection);
433 event.SetEventObject(this);
434 if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
435 {
436 // program allows the page change
437 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
438 (void)GetEventHandler()->ProcessEvent(event);
439
440 TabCtrl_SetCurSel(GetHwnd(), nPage);
441 }
442 }
443
444 return m_nSelection;
445 }
446
447 bool wxNotebook::SetPageText(size_t nPage, const wxString& strText)
448 {
449 wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
450
451 TC_ITEM tcItem;
452 tcItem.mask = TCIF_TEXT;
453 tcItem.pszText = (wxChar *)strText.c_str();
454
455 return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
456 }
457
458 wxString wxNotebook::GetPageText(size_t nPage) const
459 {
460 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxEmptyString, wxT("notebook page out of range") );
461
462 wxChar buf[256];
463 TC_ITEM tcItem;
464 tcItem.mask = TCIF_TEXT;
465 tcItem.pszText = buf;
466 tcItem.cchTextMax = WXSIZEOF(buf);
467
468 wxString str;
469 if ( TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) )
470 str = tcItem.pszText;
471
472 return str;
473 }
474
475 int wxNotebook::GetPageImage(size_t nPage) const
476 {
477 wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") );
478
479 TC_ITEM tcItem;
480 tcItem.mask = TCIF_IMAGE;
481
482 return TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) ? tcItem.iImage : -1;
483 }
484
485 bool wxNotebook::SetPageImage(size_t nPage, int nImage)
486 {
487 wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
488
489 TC_ITEM tcItem;
490 tcItem.mask = TCIF_IMAGE;
491 tcItem.iImage = nImage;
492
493 return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
494 }
495
496 void wxNotebook::SetImageList(wxImageList* imageList)
497 {
498 wxNotebookBase::SetImageList(imageList);
499
500 if ( imageList )
501 {
502 TabCtrl_SetImageList(GetHwnd(), (HIMAGELIST)imageList->GetHIMAGELIST());
503 }
504 }
505
506 // ----------------------------------------------------------------------------
507 // wxNotebook size settings
508 // ----------------------------------------------------------------------------
509
510 wxRect wxNotebook::GetPageSize() const
511 {
512 wxRect r;
513
514 RECT rc;
515 ::GetClientRect(GetHwnd(), &rc);
516
517 // This check is to work around a bug in TabCtrl_AdjustRect which will
518 // cause a crash on win2k or on XP with themes disabled if either
519 // wxNB_MULTILINE is used or tabs are placed on a side, if the rectangle
520 // is too small.
521 //
522 // The value of 20 is chosen arbitrarily but seems to work
523 if ( rc.right > 20 && rc.bottom > 20 )
524 {
525 TabCtrl_AdjustRect(GetHwnd(), false, &rc);
526
527 wxCopyRECTToRect(rc, r);
528 }
529
530 return r;
531 }
532
533 void wxNotebook::SetPageSize(const wxSize& size)
534 {
535 // transform the page size into the notebook size
536 RECT rc;
537 rc.left =
538 rc.top = 0;
539 rc.right = size.x;
540 rc.bottom = size.y;
541
542 TabCtrl_AdjustRect(GetHwnd(), true, &rc);
543
544 // and now set it
545 SetSize(rc.right - rc.left, rc.bottom - rc.top);
546 }
547
548 void wxNotebook::SetPadding(const wxSize& padding)
549 {
550 TabCtrl_SetPadding(GetHwnd(), padding.x, padding.y);
551 }
552
553 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
554 // style.
555 void wxNotebook::SetTabSize(const wxSize& sz)
556 {
557 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE, 0, MAKELPARAM(sz.x, sz.y));
558 }
559
560 wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
561 {
562 wxSize sizeTotal = sizePage;
563
564 // We need to make getting tab size part of the wxWidgets API.
565 wxSize tabSize;
566 if (GetPageCount() > 0)
567 {
568 RECT rect;
569 TabCtrl_GetItemRect((HWND) GetHWND(), 0, & rect);
570 tabSize.x = rect.right - rect.left;
571 tabSize.y = rect.bottom - rect.top;
572 }
573 if ( HasFlag(wxNB_LEFT) || HasFlag(wxNB_RIGHT) )
574 {
575 sizeTotal.x += tabSize.x + 7;
576 sizeTotal.y += 7;
577 }
578 else
579 {
580 sizeTotal.x += 7;
581 sizeTotal.y += tabSize.y + 7;
582 }
583
584 return sizeTotal;
585 }
586
587 void wxNotebook::AdjustPageSize(wxNotebookPage *page)
588 {
589 wxCHECK_RET( page, _T("NULL page in wxNotebook::AdjustPageSize") );
590
591 const wxRect r = GetPageSize();
592 if ( !r.IsEmpty() )
593 {
594 page->SetSize(r);
595 }
596 }
597
598 // ----------------------------------------------------------------------------
599 // wxNotebook operations
600 // ----------------------------------------------------------------------------
601
602 // remove one page from the notebook, without deleting
603 wxNotebookPage *wxNotebook::DoRemovePage(size_t nPage)
604 {
605 wxNotebookPage *pageRemoved = wxNotebookBase::DoRemovePage(nPage);
606 if ( !pageRemoved )
607 return NULL;
608
609 TabCtrl_DeleteItem(GetHwnd(), nPage);
610
611 if ( m_pages.IsEmpty() )
612 {
613 // no selection any more, the notebook becamse empty
614 m_nSelection = -1;
615 }
616 else // notebook still not empty
617 {
618 int selNew = TabCtrl_GetCurSel(GetHwnd());
619 if (selNew != -1)
620 {
621 // No selection change, just refresh the current selection.
622 // Because it could be that the slection index changed
623 // we need to update it.
624 // Note: this does not mean the selection it self changed.
625 m_nSelection = selNew;
626 m_pages[m_nSelection]->Refresh();
627 }
628 else if (int(nPage) == m_nSelection)
629 {
630 // The selection was deleted.
631
632 // Determine new selection.
633 if (m_nSelection == int(GetPageCount()))
634 selNew = m_nSelection - 1;
635 else
636 selNew = m_nSelection;
637
638 // m_nSelection must be always valid so reset it before calling
639 // SetSelection()
640 m_nSelection = -1;
641 SetSelection(selNew);
642 }
643 else
644 {
645 wxFAIL; // Windows did not behave ok.
646 }
647 }
648
649 return pageRemoved;
650 }
651
652 // remove all pages
653 bool wxNotebook::DeleteAllPages()
654 {
655 size_t nPageCount = GetPageCount();
656 size_t nPage;
657 for ( nPage = 0; nPage < nPageCount; nPage++ )
658 delete m_pages[nPage];
659
660 m_pages.Clear();
661
662 TabCtrl_DeleteAllItems(GetHwnd());
663
664 m_nSelection = -1;
665
666 InvalidateBestSize();
667 return true;
668 }
669
670 // same as AddPage() but does it at given position
671 bool wxNotebook::InsertPage(size_t nPage,
672 wxNotebookPage *pPage,
673 const wxString& strText,
674 bool bSelect,
675 int imageId)
676 {
677 wxCHECK_MSG( pPage != NULL, false, _T("NULL page in wxNotebook::InsertPage") );
678 wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false,
679 _T("invalid index in wxNotebook::InsertPage") );
680
681 wxASSERT_MSG( pPage->GetParent() == this,
682 _T("notebook pages must have notebook as parent") );
683
684 // add a new tab to the control
685 // ----------------------------
686
687 // init all fields to 0
688 TC_ITEM tcItem;
689 wxZeroMemory(tcItem);
690
691 // set the image, if any
692 if ( imageId != -1 )
693 {
694 tcItem.mask |= TCIF_IMAGE;
695 tcItem.iImage = imageId;
696 }
697
698 // and the text
699 if ( !strText.empty() )
700 {
701 tcItem.mask |= TCIF_TEXT;
702 tcItem.pszText = (wxChar *)strText.c_str(); // const_cast
703 }
704
705 // hide the page: unless it is selected, it shouldn't be shown (and if it
706 // is selected it will be shown later)
707 HWND hwnd = GetWinHwnd(pPage);
708 SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);
709
710 // this updates internal flag too -- otherwise it would get out of sync
711 // with the real state
712 pPage->Show(false);
713
714
715 // fit the notebook page to the tab control's display area: this should be
716 // done before adding it to the notebook or TabCtrl_InsertItem() will
717 // change the notebooks size itself!
718 AdjustPageSize(pPage);
719
720 // finally do insert it
721 if ( TabCtrl_InsertItem(GetHwnd(), nPage, &tcItem) == -1 )
722 {
723 wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());
724
725 return false;
726 }
727
728 // succeeded: save the pointer to the page
729 m_pages.Insert(pPage, nPage);
730
731 // we may need to adjust the size again if the notebook size changed:
732 // normally this only happens for the first page we add (the tabs which
733 // hadn't been there before are now shown) but for a multiline notebook it
734 // can happen for any page at all as a new row could have been started
735 if ( m_pages.GetCount() == 1 || HasFlag(wxNB_MULTILINE) )
736 {
737 AdjustPageSize(pPage);
738 }
739
740 // now deal with the selection
741 // ---------------------------
742
743 // if the inserted page is before the selected one, we must update the
744 // index of the selected page
745 if ( int(nPage) <= m_nSelection )
746 {
747 // one extra page added
748 m_nSelection++;
749 }
750
751 // some page should be selected: either this one or the first one if there
752 // is still no selection
753 int selNew = -1;
754 if ( bSelect )
755 selNew = nPage;
756 else if ( m_nSelection == -1 )
757 selNew = 0;
758
759 if ( selNew != -1 )
760 SetSelection(selNew);
761
762 InvalidateBestSize();
763
764 return true;
765 }
766
767 int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
768 {
769 TC_HITTESTINFO hitTestInfo;
770 hitTestInfo.pt.x = pt.x;
771 hitTestInfo.pt.y = pt.y;
772 int item = TabCtrl_HitTest(GetHwnd(), &hitTestInfo);
773
774 if ( flags )
775 {
776 *flags = 0;
777
778 if ((hitTestInfo.flags & TCHT_NOWHERE) == TCHT_NOWHERE)
779 *flags |= wxNB_HITTEST_NOWHERE;
780 if ((hitTestInfo.flags & TCHT_ONITEM) == TCHT_ONITEM)
781 *flags |= wxNB_HITTEST_ONITEM;
782 if ((hitTestInfo.flags & TCHT_ONITEMICON) == TCHT_ONITEMICON)
783 *flags |= wxNB_HITTEST_ONICON;
784 if ((hitTestInfo.flags & TCHT_ONITEMLABEL) == TCHT_ONITEMLABEL)
785 *flags |= wxNB_HITTEST_ONLABEL;
786 }
787
788 return item;
789 }
790
791 // ----------------------------------------------------------------------------
792 // flicker-less notebook redraw
793 // ----------------------------------------------------------------------------
794
795 #if USE_NOTEBOOK_ANTIFLICKER
796
797 // wnd proc for the spin button
798 LRESULT APIENTRY _EXPORT wxNotebookSpinBtnWndProc(HWND hwnd,
799 UINT message,
800 WPARAM wParam,
801 LPARAM lParam)
802 {
803 if ( message == WM_ERASEBKGND )
804 return 0;
805
806 return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebookSpinBtn,
807 hwnd, message, wParam, lParam);
808 }
809
810 LRESULT APIENTRY _EXPORT wxNotebookWndProc(HWND hwnd,
811 UINT message,
812 WPARAM wParam,
813 LPARAM lParam)
814 {
815 return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebook,
816 hwnd, message, wParam, lParam);
817 }
818
819
820
821 void wxNotebook::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
822 {
823 // do nothing here
824 }
825
826 void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event))
827 {
828 wxPaintDC dc(this);
829 wxMemoryDC memdc;
830 RECT rc;
831 ::GetClientRect(GetHwnd(), &rc);
832 wxBitmap bmp(rc.right, rc.bottom);
833 memdc.SelectObject(bmp);
834
835 // if there is no special brush just use the solid background colour
836 HBRUSH hbr = (HBRUSH)m_hbrBackground;
837 wxBrush brush;
838 if ( !hbr )
839 {
840 brush = wxBrush(GetBackgroundColour());
841 hbr = GetHbrushOf(brush);
842 }
843
844 ::FillRect(GetHdcOf(memdc), &rc, hbr);
845
846 MSWDefWindowProc(WM_PAINT, (WPARAM)memdc.GetHDC(), 0);
847
848 dc.Blit(0, 0, rc.right, rc.bottom, &memdc, 0, 0);
849 }
850
851 #endif // USE_NOTEBOOK_ANTIFLICKER
852
853 // ----------------------------------------------------------------------------
854 // wxNotebook callbacks
855 // ----------------------------------------------------------------------------
856
857 void wxNotebook::OnSize(wxSizeEvent& event)
858 {
859 if ( GetPageCount() == 0 )
860 {
861 // Prevents droppings on resize, but does cause some flicker
862 // when there are no pages.
863 Refresh();
864 event.Skip();
865 return;
866 }
867 #ifndef __WXWINCE__
868 else
869 {
870 // Without this, we can sometimes get droppings at the edges
871 // of a notebook, for example a notebook in a splitter window.
872 // This needs to be reconciled with the RefreshRect calls
873 // at the end of this function, which weren't enough to prevent
874 // the droppings.
875
876 wxSize sz = GetClientSize();
877
878 // Refresh right side
879 wxRect rect(sz.x-4, 0, 4, sz.y);
880 RefreshRect(rect);
881
882 // Refresh bottom side
883 rect = wxRect(0, sz.y-4, sz.x, 4);
884 RefreshRect(rect);
885
886 // Refresh left side
887 rect = wxRect(0, 0, 4, sz.y);
888 RefreshRect(rect);
889 }
890 #endif // !__WXWINCE__
891
892 // fit all the notebook pages to the tab control's display area
893
894 RECT rc;
895 rc.left = rc.top = 0;
896 GetSize((int *)&rc.right, (int *)&rc.bottom);
897
898 // save the total size, we'll use it below
899 int widthNbook = rc.right - rc.left,
900 heightNbook = rc.bottom - rc.top;
901
902 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
903 // returns completely false values for multiline tab controls after the tabs
904 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
905 //
906 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
907 //
908 // and the only work around I could find was this ugly hack... without it
909 // simply toggling the "multiline" checkbox in the notebook sample resulted
910 // in a noticeable page displacement
911 if ( HasFlag(wxNB_MULTILINE) )
912 {
913 // avoid an infinite recursion: we get another notification too!
914 static bool s_isInOnSize = false;
915
916 if ( !s_isInOnSize )
917 {
918 s_isInOnSize = true;
919 SendMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED,
920 MAKELPARAM(rc.right, rc.bottom));
921 s_isInOnSize = false;
922 }
923 }
924
925 #if wxUSE_UXTHEME
926 // background bitmap size has changed, update the brush using it too
927 UpdateBgBrush();
928 #endif // wxUSE_UXTHEME
929
930 TabCtrl_AdjustRect(GetHwnd(), false, &rc);
931
932 int width = rc.right - rc.left,
933 height = rc.bottom - rc.top;
934 size_t nCount = m_pages.Count();
935 for ( size_t nPage = 0; nPage < nCount; nPage++ ) {
936 wxNotebookPage *pPage = m_pages[nPage];
937 pPage->SetSize(rc.left, rc.top, width, height);
938 }
939
940
941 // unless we had already repainted everything, we now need to refresh
942 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
943 {
944 // invalidate areas not covered by pages
945 RefreshRect(wxRect(0, 0, widthNbook, rc.top), false);
946 RefreshRect(wxRect(0, rc.top, rc.left, height), false);
947 RefreshRect(wxRect(0, rc.bottom, widthNbook, heightNbook - rc.bottom),
948 false);
949 RefreshRect(wxRect(rc.right, rc.top, widthNbook - rc.right, height),
950 false);
951 }
952
953 #if USE_NOTEBOOK_ANTIFLICKER
954 // subclass the spin control used by the notebook to scroll pages to
955 // prevent it from flickering on resize
956 if ( !m_hasSubclassedUpdown )
957 {
958 // iterate over all child windows to find spin button
959 for ( HWND child = ::GetWindow(GetHwnd(), GW_CHILD);
960 child;
961 child = ::GetWindow(child, GW_HWNDNEXT) )
962 {
963 wxWindow *childWindow = wxFindWinFromHandle((WXHWND)child);
964
965 // see if it exists, if no wxWindow found then assume it's the spin
966 // btn
967 if ( !childWindow )
968 {
969 // subclass the spin button to override WM_ERASEBKGND
970 if ( !gs_wndprocNotebookSpinBtn )
971 gs_wndprocNotebookSpinBtn = (WXFARPROC)wxGetWindowProc(child);
972
973 wxSetWindowProc(child, wxNotebookSpinBtnWndProc);
974 m_hasSubclassedUpdown = true;
975 break;
976 }
977 }
978 }
979 #endif // USE_NOTEBOOK_ANTIFLICKER
980
981 event.Skip();
982 }
983
984 void wxNotebook::OnSelChange(wxNotebookEvent& event)
985 {
986 // is it our tab control?
987 if ( event.GetEventObject() == this )
988 {
989 int sel = event.GetOldSelection();
990 if ( sel != -1 )
991 m_pages[sel]->Show(false);
992
993 sel = event.GetSelection();
994 if ( sel != -1 )
995 {
996 wxNotebookPage *pPage = m_pages[sel];
997 pPage->Show(true);
998
999 // As per bug report:
1000 // http://sourceforge.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863,
1001 // we should not set the page focus (and thereby the focus for
1002 // a child window) since it erroneously selects radio button controls and also
1003 // breaks keyboard handling for a notebook's scroll buttons. So
1004 // we always focus the notebook and not the page.
1005 SetFocus();
1006
1007 }
1008 else // no pages in the notebook, give the focus to itself
1009 {
1010 SetFocus();
1011 }
1012
1013 m_nSelection = sel;
1014 }
1015
1016 // we want to give others a chance to process this message as well
1017 event.Skip();
1018 }
1019
1020 bool wxNotebook::MSWTranslateMessage(WXMSG *wxmsg)
1021 {
1022 const MSG * const msg = (MSG *)wxmsg;
1023
1024 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
1025 // TAB will be passed to the currently selected page, CTRL+TAB and
1026 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
1027 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
1028 // process it.
1029 if ( msg->message == WM_KEYDOWN && msg->wParam == VK_TAB &&
1030 msg->hwnd == GetHwnd() &&
1031 (wxIsCtrlDown() || !wxIsShiftDown()) )
1032 {
1033 return MSWProcessMessage(wxmsg);
1034 }
1035
1036 return false;
1037 }
1038
1039 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
1040 {
1041 if ( event.IsWindowChange() ) {
1042 // change pages
1043 AdvanceSelection(event.GetDirection());
1044 }
1045 else {
1046 // we get this event in 3 cases
1047 //
1048 // a) one of our pages might have generated it because the user TABbed
1049 // out from it in which case we should propagate the event upwards and
1050 // our parent will take care of setting the focus to prev/next sibling
1051 //
1052 // or
1053 //
1054 // b) the parent panel wants to give the focus to us so that we
1055 // forward it to our selected page. We can't deal with this in
1056 // OnSetFocus() because we don't know which direction the focus came
1057 // from in this case and so can't choose between setting the focus to
1058 // first or last panel child
1059 //
1060 // or
1061 //
1062 // c) we ourselves (see MSWTranslateMessage) generated the event
1063 //
1064 wxWindow * const parent = GetParent();
1065
1066 // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
1067 const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
1068 const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
1069
1070 if ( isFromParent || isFromSelf )
1071 {
1072 // no, it doesn't come from child, case (b) or (c): forward to a
1073 // page but only if direction is backwards (TAB) or from ourselves,
1074 if ( m_nSelection != -1 &&
1075 (!event.GetDirection() || isFromSelf) )
1076 {
1077 // so that the page knows that the event comes from it's parent
1078 // and is being propagated downwards
1079 event.SetEventObject(this);
1080
1081 wxWindow *page = m_pages[m_nSelection];
1082 if ( !page->GetEventHandler()->ProcessEvent(event) )
1083 {
1084 page->SetFocus();
1085 }
1086 //else: page manages focus inside it itself
1087 }
1088 else // otherwise set the focus to the notebook itself
1089 {
1090 SetFocus();
1091 }
1092 }
1093 else
1094 {
1095 // it comes from our child, case (a), pass to the parent, but only
1096 // if the direction is forwards. Otherwise set the focus to the
1097 // notebook itself. The notebook is always the 'first' control of a
1098 // page.
1099 if ( !event.GetDirection() )
1100 {
1101 SetFocus();
1102 }
1103 else if ( parent )
1104 {
1105 event.SetCurrentFocus(this);
1106 parent->GetEventHandler()->ProcessEvent(event);
1107 }
1108 }
1109 }
1110 }
1111
1112 #if wxUSE_UXTHEME
1113
1114 bool wxNotebook::DoDrawBackground(WXHDC hDC, wxWindow *child)
1115 {
1116 wxUxThemeHandle theme(child ? child : this, L"TAB");
1117 if ( !theme )
1118 return false;
1119
1120 // get the notebook client rect (we're not interested in drawing tabs
1121 // themselves)
1122 wxRect r = GetPageSize();
1123 if ( r.IsEmpty() )
1124 return false;
1125
1126 RECT rc;
1127 wxCopyRectToRECT(r, rc);
1128
1129 // map rect to the coords of the window we're drawing in
1130 if ( child )
1131 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1132
1133 // we have the content area (page size), but we need to draw all of the
1134 // background for it to be aligned correctly
1135 wxUxThemeEngine::Get()->GetThemeBackgroundExtent
1136 (
1137 theme,
1138 (HDC) hDC,
1139 9 /* TABP_PANE */,
1140 0,
1141 &rc,
1142 &rc
1143 );
1144 wxUxThemeEngine::Get()->DrawThemeBackground
1145 (
1146 theme,
1147 (HDC) hDC,
1148 9 /* TABP_PANE */,
1149 0,
1150 &rc,
1151 NULL
1152 );
1153
1154 return true;
1155 }
1156
1157 WXHBRUSH wxNotebook::QueryBgBitmap()
1158 {
1159 wxRect r = GetPageSize();
1160 if ( r.IsEmpty() )
1161 return 0;
1162
1163 WindowHDC hDC(GetHwnd());
1164 MemoryHDC hDCMem(hDC);
1165 CompatibleBitmap hBmp(hDC, r.x + r.width, r.y + r.height);
1166
1167 SelectInHDC selectBmp(hDCMem, hBmp);
1168
1169 if ( !DoDrawBackground((WXHDC)(HDC)hDCMem) )
1170 return 0;
1171
1172 return (WXHBRUSH)::CreatePatternBrush(hBmp);
1173 }
1174
1175 void wxNotebook::UpdateBgBrush()
1176 {
1177 if ( m_hbrBackground )
1178 ::DeleteObject((HBRUSH)m_hbrBackground);
1179
1180 if ( !m_hasBgCol && wxUxThemeEngine::GetIfActive() )
1181 {
1182 m_hbrBackground = QueryBgBitmap();
1183 }
1184 else // no themes or we've got user-defined solid colour
1185 {
1186 m_hbrBackground = NULL;
1187 }
1188 }
1189
1190 WXHBRUSH wxNotebook::MSWGetBgBrushForChild(WXHDC hDC, WXHWND hWnd)
1191 {
1192 if ( m_hbrBackground )
1193 {
1194 // before drawing with the background brush, we need to position it
1195 // correctly
1196 RECT rc;
1197 ::GetWindowRect((HWND)hWnd, &rc);
1198
1199 ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
1200
1201 if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
1202 {
1203 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
1204 }
1205
1206 return m_hbrBackground;
1207 }
1208
1209 return wxNotebookBase::MSWGetBgBrushForChild(hDC, hWnd);
1210 }
1211
1212 bool wxNotebook::MSWPrintChild(WXHDC hDC, wxWindow *child)
1213 {
1214 // solid background colour overrides themed background drawing
1215 if ( !UseBgCol() && DoDrawBackground(hDC, child) )
1216 return true;
1217
1218 // If we're using a solid colour (for example if we've switched off
1219 // theming for this notebook), paint it
1220 if (UseBgCol())
1221 {
1222 wxRect r = GetPageSize();
1223 if ( r.IsEmpty() )
1224 return false;
1225
1226 RECT rc;
1227 wxCopyRectToRECT(r, rc);
1228
1229 // map rect to the coords of the window we're drawing in
1230 if ( child )
1231 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1232
1233 wxBrush brush(GetBackgroundColour());
1234 HBRUSH hbr = GetHbrushOf(brush);
1235
1236 ::FillRect((HDC) hDC, &rc, hbr);
1237
1238 return true;
1239 }
1240
1241 return wxNotebookBase::MSWPrintChild(hDC, child);
1242 }
1243
1244 #endif // wxUSE_UXTHEME
1245
1246 // Windows only: attempts to get colour for UX theme page background
1247 wxColour wxNotebook::GetThemeBackgroundColour() const
1248 {
1249 #if wxUSE_UXTHEME
1250 if (wxUxThemeEngine::Get())
1251 {
1252 wxUxThemeHandle hTheme((wxNotebook*) this, L"TAB");
1253 if (hTheme)
1254 {
1255 // This is total guesswork.
1256 // See PlatformSDK\Include\Tmschema.h for values
1257 COLORREF themeColor;
1258 wxUxThemeEngine::Get()->GetThemeColor(
1259 hTheme,
1260 10 /* TABP_BODY */,
1261 1 /* NORMAL */,
1262 3821 /* FILLCOLORHINT */,
1263 &themeColor);
1264
1265 /*
1266 [DS] Workaround for WindowBlinds:
1267 Some themes return a near black theme color using FILLCOLORHINT,
1268 this makes notebook pages have an ugly black background and makes
1269 text (usually black) unreadable. Retry again with FILLCOLOR.
1270
1271 This workaround potentially breaks appearance of some themes,
1272 but in practice it already fixes some themes.
1273 */
1274 if (themeColor == 1)
1275 {
1276 wxUxThemeEngine::Get()->GetThemeColor(
1277 hTheme,
1278 10 /* TABP_BODY */,
1279 1 /* NORMAL */,
1280 3802 /* FILLCOLOR */,
1281 &themeColor);
1282 }
1283
1284 return wxRGBToColour(themeColor);
1285 }
1286 }
1287 #endif // wxUSE_UXTHEME
1288
1289 return GetBackgroundColour();
1290 }
1291
1292 // ----------------------------------------------------------------------------
1293 // wxNotebook base class virtuals
1294 // ----------------------------------------------------------------------------
1295
1296 #if wxUSE_CONSTRAINTS
1297
1298 // override these 2 functions to do nothing: everything is done in OnSize
1299
1300 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
1301 {
1302 // don't set the sizes of the pages - their correct size is not yet known
1303 wxControl::SetConstraintSizes(false);
1304 }
1305
1306 bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
1307 {
1308 return true;
1309 }
1310
1311 #endif // wxUSE_CONSTRAINTS
1312
1313 // ----------------------------------------------------------------------------
1314 // wxNotebook Windows message handlers
1315 // ----------------------------------------------------------------------------
1316
1317 bool wxNotebook::MSWOnScroll(int orientation, WXWORD nSBCode,
1318 WXWORD pos, WXHWND control)
1319 {
1320 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1321 // up-down control
1322 if ( control )
1323 return false;
1324
1325 return wxNotebookBase::MSWOnScroll(orientation, nSBCode, pos, control);
1326 }
1327
1328 bool wxNotebook::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
1329 {
1330 wxNotebookEvent event(wxEVT_NULL, m_windowId);
1331
1332 NMHDR* hdr = (NMHDR *)lParam;
1333 switch ( hdr->code ) {
1334 case TCN_SELCHANGE:
1335 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
1336 break;
1337
1338 case TCN_SELCHANGING:
1339 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
1340 break;
1341
1342 default:
1343 return wxControl::MSWOnNotify(idCtrl, lParam, result);
1344 }
1345
1346 event.SetSelection(TabCtrl_GetCurSel(GetHwnd()));
1347 event.SetOldSelection(m_nSelection);
1348 event.SetEventObject(this);
1349 event.SetInt(idCtrl);
1350
1351 bool processed = GetEventHandler()->ProcessEvent(event);
1352 *result = !event.IsAllowed();
1353 return processed;
1354 }
1355
1356 #endif // wxUSE_NOTEBOOK