]> git.saurik.com Git - wxWidgets.git/blob - src/msw/notebook.cpp
use wxIsNullDouble instead of comparing m_ration with 0
[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 void wxNotebook::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
816 {
817 // do nothing here
818 }
819
820 void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event))
821 {
822 wxPaintDC dc(this);
823 wxMemoryDC memdc;
824 RECT rc;
825 ::GetClientRect(GetHwnd(), &rc);
826 wxBitmap bmp(rc.right, rc.bottom);
827 memdc.SelectObject(bmp);
828
829 // if there is no special brush just use the solid background colour
830 HBRUSH hbr = (HBRUSH)m_hbrBackground;
831 wxBrush brush;
832 if ( !hbr )
833 {
834 brush = wxBrush(GetBackgroundColour());
835 hbr = GetHbrushOf(brush);
836 }
837
838 ::FillRect(GetHdcOf(memdc), &rc, hbr);
839
840 MSWDefWindowProc(WM_PAINT, (WPARAM)memdc.GetHDC(), 0);
841
842 dc.Blit(0, 0, rc.right, rc.bottom, &memdc, 0, 0);
843 }
844
845 #endif // USE_NOTEBOOK_ANTIFLICKER
846
847 // ----------------------------------------------------------------------------
848 // wxNotebook callbacks
849 // ----------------------------------------------------------------------------
850
851 void wxNotebook::OnSize(wxSizeEvent& event)
852 {
853 if ( GetPageCount() == 0 )
854 {
855 // Prevents droppings on resize, but does cause some flicker
856 // when there are no pages.
857 Refresh();
858 event.Skip();
859 return;
860 }
861 #ifndef __WXWINCE__
862 else
863 {
864 // Without this, we can sometimes get droppings at the edges
865 // of a notebook, for example a notebook in a splitter window.
866 // This needs to be reconciled with the RefreshRect calls
867 // at the end of this function, which weren't enough to prevent
868 // the droppings.
869
870 wxSize sz = GetClientSize();
871
872 // Refresh right side
873 wxRect rect(sz.x-4, 0, 4, sz.y);
874 RefreshRect(rect);
875
876 // Refresh bottom side
877 rect = wxRect(0, sz.y-4, sz.x, 4);
878 RefreshRect(rect);
879
880 // Refresh left side
881 rect = wxRect(0, 0, 4, sz.y);
882 RefreshRect(rect);
883 }
884 #endif // !__WXWINCE__
885
886 // fit all the notebook pages to the tab control's display area
887
888 RECT rc;
889 rc.left = rc.top = 0;
890 GetSize((int *)&rc.right, (int *)&rc.bottom);
891
892 // save the total size, we'll use it below
893 int widthNbook = rc.right - rc.left,
894 heightNbook = rc.bottom - rc.top;
895
896 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
897 // returns completely false values for multiline tab controls after the tabs
898 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
899 //
900 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
901 //
902 // and the only work around I could find was this ugly hack... without it
903 // simply toggling the "multiline" checkbox in the notebook sample resulted
904 // in a noticeable page displacement
905 if ( HasFlag(wxNB_MULTILINE) )
906 {
907 // avoid an infinite recursion: we get another notification too!
908 static bool s_isInOnSize = false;
909
910 if ( !s_isInOnSize )
911 {
912 s_isInOnSize = true;
913 SendMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED,
914 MAKELPARAM(rc.right, rc.bottom));
915 s_isInOnSize = false;
916 }
917 }
918
919 #if wxUSE_UXTHEME
920 // background bitmap size has changed, update the brush using it too
921 UpdateBgBrush();
922 #endif // wxUSE_UXTHEME
923
924 TabCtrl_AdjustRect(GetHwnd(), false, &rc);
925
926 int width = rc.right - rc.left,
927 height = rc.bottom - rc.top;
928 size_t nCount = m_pages.Count();
929 for ( size_t nPage = 0; nPage < nCount; nPage++ ) {
930 wxNotebookPage *pPage = m_pages[nPage];
931 pPage->SetSize(rc.left, rc.top, width, height);
932 }
933
934
935 // unless we had already repainted everything, we now need to refresh
936 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
937 {
938 // invalidate areas not covered by pages
939 RefreshRect(wxRect(0, 0, widthNbook, rc.top), false);
940 RefreshRect(wxRect(0, rc.top, rc.left, height), false);
941 RefreshRect(wxRect(0, rc.bottom, widthNbook, heightNbook - rc.bottom),
942 false);
943 RefreshRect(wxRect(rc.right, rc.top, widthNbook - rc.right, height),
944 false);
945 }
946
947 #if USE_NOTEBOOK_ANTIFLICKER
948 // subclass the spin control used by the notebook to scroll pages to
949 // prevent it from flickering on resize
950 if ( !m_hasSubclassedUpdown )
951 {
952 // iterate over all child windows to find spin button
953 for ( HWND child = ::GetWindow(GetHwnd(), GW_CHILD);
954 child;
955 child = ::GetWindow(child, GW_HWNDNEXT) )
956 {
957 wxWindow *childWindow = wxFindWinFromHandle((WXHWND)child);
958
959 // see if it exists, if no wxWindow found then assume it's the spin
960 // btn
961 if ( !childWindow )
962 {
963 // subclass the spin button to override WM_ERASEBKGND
964 if ( !gs_wndprocNotebookSpinBtn )
965 gs_wndprocNotebookSpinBtn = (WXFARPROC)wxGetWindowProc(child);
966
967 wxSetWindowProc(child, wxNotebookSpinBtnWndProc);
968 m_hasSubclassedUpdown = true;
969 break;
970 }
971 }
972 }
973 #endif // USE_NOTEBOOK_ANTIFLICKER
974
975 event.Skip();
976 }
977
978 void wxNotebook::OnSelChange(wxNotebookEvent& event)
979 {
980 // is it our tab control?
981 if ( event.GetEventObject() == this )
982 {
983 int sel = event.GetOldSelection();
984 if ( sel != -1 )
985 m_pages[sel]->Show(false);
986
987 sel = event.GetSelection();
988 if ( sel != -1 )
989 {
990 wxNotebookPage *pPage = m_pages[sel];
991 pPage->Show(true);
992 }
993
994 // Changing the page should give the focus to it but, as per bug report
995 // http://sf.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863,
996 // we should not set the focus to it directly since it erroneously
997 // selects radio buttons and breaks keyboard handling for a notebook's
998 // scroll buttons. So give focus to the notebook and not the page.
999
1000 // but don't do this is the notebook is hidden
1001 if ( ::IsWindowVisible(GetHwnd()) )
1002 SetFocus();
1003
1004 m_nSelection = sel;
1005 }
1006
1007 // we want to give others a chance to process this message as well
1008 event.Skip();
1009 }
1010
1011 bool wxNotebook::MSWTranslateMessage(WXMSG *wxmsg)
1012 {
1013 const MSG * const msg = (MSG *)wxmsg;
1014
1015 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
1016 // TAB will be passed to the currently selected page, CTRL+TAB and
1017 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
1018 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
1019 // process it.
1020 if ( msg->message == WM_KEYDOWN && msg->wParam == VK_TAB &&
1021 msg->hwnd == GetHwnd() &&
1022 (wxIsCtrlDown() || !wxIsShiftDown()) )
1023 {
1024 return MSWProcessMessage(wxmsg);
1025 }
1026
1027 return false;
1028 }
1029
1030 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
1031 {
1032 if ( event.IsWindowChange() ) {
1033 // change pages
1034 AdvanceSelection(event.GetDirection());
1035 }
1036 else {
1037 // we get this event in 3 cases
1038 //
1039 // a) one of our pages might have generated it because the user TABbed
1040 // out from it in which case we should propagate the event upwards and
1041 // our parent will take care of setting the focus to prev/next sibling
1042 //
1043 // or
1044 //
1045 // b) the parent panel wants to give the focus to us so that we
1046 // forward it to our selected page. We can't deal with this in
1047 // OnSetFocus() because we don't know which direction the focus came
1048 // from in this case and so can't choose between setting the focus to
1049 // first or last panel child
1050 //
1051 // or
1052 //
1053 // c) we ourselves (see MSWTranslateMessage) generated the event
1054 //
1055 wxWindow * const parent = GetParent();
1056
1057 // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
1058 const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
1059 const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
1060
1061 if ( isFromParent || isFromSelf )
1062 {
1063 // no, it doesn't come from child, case (b) or (c): forward to a
1064 // page but only if direction is backwards (TAB) or from ourselves,
1065 if ( m_nSelection != -1 &&
1066 (!event.GetDirection() || isFromSelf) )
1067 {
1068 // so that the page knows that the event comes from it's parent
1069 // and is being propagated downwards
1070 event.SetEventObject(this);
1071
1072 wxWindow *page = m_pages[m_nSelection];
1073 if ( !page->GetEventHandler()->ProcessEvent(event) )
1074 {
1075 page->SetFocus();
1076 }
1077 //else: page manages focus inside it itself
1078 }
1079 else // otherwise set the focus to the notebook itself
1080 {
1081 SetFocus();
1082 }
1083 }
1084 else
1085 {
1086 // it comes from our child, case (a), pass to the parent, but only
1087 // if the direction is forwards. Otherwise set the focus to the
1088 // notebook itself. The notebook is always the 'first' control of a
1089 // page.
1090 if ( !event.GetDirection() )
1091 {
1092 SetFocus();
1093 }
1094 else if ( parent )
1095 {
1096 event.SetCurrentFocus(this);
1097 parent->GetEventHandler()->ProcessEvent(event);
1098 }
1099 }
1100 }
1101 }
1102
1103 #if wxUSE_UXTHEME
1104
1105 bool wxNotebook::DoDrawBackground(WXHDC hDC, wxWindow *child)
1106 {
1107 wxUxThemeHandle theme(child ? child : this, L"TAB");
1108 if ( !theme )
1109 return false;
1110
1111 // get the notebook client rect (we're not interested in drawing tabs
1112 // themselves)
1113 wxRect r = GetPageSize();
1114 if ( r.IsEmpty() )
1115 return false;
1116
1117 RECT rc;
1118 wxCopyRectToRECT(r, rc);
1119
1120 // map rect to the coords of the window we're drawing in
1121 if ( child )
1122 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1123
1124 // we have the content area (page size), but we need to draw all of the
1125 // background for it to be aligned correctly
1126 wxUxThemeEngine::Get()->GetThemeBackgroundExtent
1127 (
1128 theme,
1129 (HDC) hDC,
1130 9 /* TABP_PANE */,
1131 0,
1132 &rc,
1133 &rc
1134 );
1135 wxUxThemeEngine::Get()->DrawThemeBackground
1136 (
1137 theme,
1138 (HDC) hDC,
1139 9 /* TABP_PANE */,
1140 0,
1141 &rc,
1142 NULL
1143 );
1144
1145 return true;
1146 }
1147
1148 WXHBRUSH wxNotebook::QueryBgBitmap()
1149 {
1150 wxRect r = GetPageSize();
1151 if ( r.IsEmpty() )
1152 return 0;
1153
1154 WindowHDC hDC(GetHwnd());
1155 MemoryHDC hDCMem(hDC);
1156 CompatibleBitmap hBmp(hDC, r.x + r.width, r.y + r.height);
1157
1158 SelectInHDC selectBmp(hDCMem, hBmp);
1159
1160 if ( !DoDrawBackground((WXHDC)(HDC)hDCMem) )
1161 return 0;
1162
1163 return (WXHBRUSH)::CreatePatternBrush(hBmp);
1164 }
1165
1166 void wxNotebook::UpdateBgBrush()
1167 {
1168 if ( m_hbrBackground )
1169 ::DeleteObject((HBRUSH)m_hbrBackground);
1170
1171 if ( !m_hasBgCol && wxUxThemeEngine::GetIfActive() )
1172 {
1173 m_hbrBackground = QueryBgBitmap();
1174 }
1175 else // no themes or we've got user-defined solid colour
1176 {
1177 m_hbrBackground = NULL;
1178 }
1179 }
1180
1181 WXHBRUSH wxNotebook::MSWGetBgBrushForChild(WXHDC hDC, WXHWND hWnd)
1182 {
1183 if ( m_hbrBackground )
1184 {
1185 // before drawing with the background brush, we need to position it
1186 // correctly
1187 RECT rc;
1188 ::GetWindowRect((HWND)hWnd, &rc);
1189
1190 ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
1191
1192 if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
1193 {
1194 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
1195 }
1196
1197 return m_hbrBackground;
1198 }
1199
1200 return wxNotebookBase::MSWGetBgBrushForChild(hDC, hWnd);
1201 }
1202
1203 bool wxNotebook::MSWPrintChild(WXHDC hDC, wxWindow *child)
1204 {
1205 // solid background colour overrides themed background drawing
1206 if ( !UseBgCol() && DoDrawBackground(hDC, child) )
1207 return true;
1208
1209 // If we're using a solid colour (for example if we've switched off
1210 // theming for this notebook), paint it
1211 if (UseBgCol())
1212 {
1213 wxRect r = GetPageSize();
1214 if ( r.IsEmpty() )
1215 return false;
1216
1217 RECT rc;
1218 wxCopyRectToRECT(r, rc);
1219
1220 // map rect to the coords of the window we're drawing in
1221 if ( child )
1222 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1223
1224 wxBrush brush(GetBackgroundColour());
1225 HBRUSH hbr = GetHbrushOf(brush);
1226
1227 ::FillRect((HDC) hDC, &rc, hbr);
1228
1229 return true;
1230 }
1231
1232 return wxNotebookBase::MSWPrintChild(hDC, child);
1233 }
1234
1235 #endif // wxUSE_UXTHEME
1236
1237 // Windows only: attempts to get colour for UX theme page background
1238 wxColour wxNotebook::GetThemeBackgroundColour() const
1239 {
1240 #if wxUSE_UXTHEME
1241 if (wxUxThemeEngine::Get())
1242 {
1243 wxUxThemeHandle hTheme((wxNotebook*) this, L"TAB");
1244 if (hTheme)
1245 {
1246 // This is total guesswork.
1247 // See PlatformSDK\Include\Tmschema.h for values
1248 COLORREF themeColor;
1249 wxUxThemeEngine::Get()->GetThemeColor(
1250 hTheme,
1251 10 /* TABP_BODY */,
1252 1 /* NORMAL */,
1253 3821 /* FILLCOLORHINT */,
1254 &themeColor);
1255
1256 /*
1257 [DS] Workaround for WindowBlinds:
1258 Some themes return a near black theme color using FILLCOLORHINT,
1259 this makes notebook pages have an ugly black background and makes
1260 text (usually black) unreadable. Retry again with FILLCOLOR.
1261
1262 This workaround potentially breaks appearance of some themes,
1263 but in practice it already fixes some themes.
1264 */
1265 if (themeColor == 1)
1266 {
1267 wxUxThemeEngine::Get()->GetThemeColor(
1268 hTheme,
1269 10 /* TABP_BODY */,
1270 1 /* NORMAL */,
1271 3802 /* FILLCOLOR */,
1272 &themeColor);
1273 }
1274
1275 return wxRGBToColour(themeColor);
1276 }
1277 }
1278 #endif // wxUSE_UXTHEME
1279
1280 return GetBackgroundColour();
1281 }
1282
1283 // ----------------------------------------------------------------------------
1284 // wxNotebook base class virtuals
1285 // ----------------------------------------------------------------------------
1286
1287 #if wxUSE_CONSTRAINTS
1288
1289 // override these 2 functions to do nothing: everything is done in OnSize
1290
1291 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
1292 {
1293 // don't set the sizes of the pages - their correct size is not yet known
1294 wxControl::SetConstraintSizes(false);
1295 }
1296
1297 bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
1298 {
1299 return true;
1300 }
1301
1302 #endif // wxUSE_CONSTRAINTS
1303
1304 // ----------------------------------------------------------------------------
1305 // wxNotebook Windows message handlers
1306 // ----------------------------------------------------------------------------
1307
1308 bool wxNotebook::MSWOnScroll(int orientation, WXWORD nSBCode,
1309 WXWORD pos, WXHWND control)
1310 {
1311 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1312 // up-down control
1313 if ( control )
1314 return false;
1315
1316 return wxNotebookBase::MSWOnScroll(orientation, nSBCode, pos, control);
1317 }
1318
1319 bool wxNotebook::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
1320 {
1321 wxNotebookEvent event(wxEVT_NULL, m_windowId);
1322
1323 NMHDR* hdr = (NMHDR *)lParam;
1324 switch ( hdr->code ) {
1325 case TCN_SELCHANGE:
1326 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
1327 break;
1328
1329 case TCN_SELCHANGING:
1330 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
1331 break;
1332
1333 default:
1334 return wxControl::MSWOnNotify(idCtrl, lParam, result);
1335 }
1336
1337 event.SetSelection(TabCtrl_GetCurSel(GetHwnd()));
1338 event.SetOldSelection(m_nSelection);
1339 event.SetEventObject(this);
1340 event.SetInt(idCtrl);
1341
1342 bool processed = GetEventHandler()->ProcessEvent(event);
1343 *result = !event.IsAllowed();
1344 return processed;
1345 }
1346
1347 #endif // wxUSE_NOTEBOOK