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