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