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