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