1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: msw/notebook.cpp
3 // Purpose: implementation of wxNotebook
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "notebook.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
27 #include "wx/string.h"
31 #include "wx/imaglist.h"
33 #include "wx/control.h"
34 #include "wx/notebook.h"
37 #include "wx/msw/private.h"
39 // Windows standard headers
41 #error "wxNotebook is only supported Windows 95 and above"
44 #include <windowsx.h> // for SetWindowFont
46 #ifdef __GNUWIN32_OLD__
47 #include "wx/msw/gnuwin32/extra.h"
50 #if defined(__WIN95__) && !(defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__))
54 #include "wx/msw/winundef.h"
57 #include "wx/msw/uxtheme.h"
59 #include "wx/radiobut.h"
60 #include "wx/radiobox.h"
61 #include "wx/checkbox.h"
62 #include "wx/bmpbuttn.h"
63 #include "wx/statline.h"
64 #include "wx/statbox.h"
65 #include "wx/stattext.h"
66 #include "wx/slider.h"
67 #include "wx/scrolwin.h"
71 // ----------------------------------------------------------------------------
73 // ----------------------------------------------------------------------------
75 // check that the page index is valid
76 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount())
79 #define m_hwnd (HWND)GetHWND()
81 // ----------------------------------------------------------------------------
83 // ----------------------------------------------------------------------------
85 // This is a work-around for missing defines in gcc-2.95 headers
87 #define TCS_RIGHT 0x0002
91 #define TCS_VERTICAL 0x0080
95 #define TCS_BOTTOM TCS_RIGHT
98 // ----------------------------------------------------------------------------
100 // ----------------------------------------------------------------------------
102 #include <wx/listimpl.cpp>
104 WX_DEFINE_LIST( wxNotebookPageInfoList
) ;
106 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
)
107 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
)
109 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
)
110 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange
)
112 EVT_SIZE(wxNotebook::OnSize
)
114 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
117 #if wxUSE_EXTENDED_RTTI
118 WX_DEFINE_FLAGS( wxNotebookStyle
)
120 wxBEGIN_FLAGS( wxNotebookStyle
)
121 // new style border flags, we put them first to
122 // use them for streaming out
123 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
124 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
125 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
126 wxFLAGS_MEMBER(wxBORDER_RAISED
)
127 wxFLAGS_MEMBER(wxBORDER_STATIC
)
128 wxFLAGS_MEMBER(wxBORDER_NONE
)
130 // old style border flags
131 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
132 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
133 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
134 wxFLAGS_MEMBER(wxRAISED_BORDER
)
135 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
136 wxFLAGS_MEMBER(wxBORDER
)
138 // standard window styles
139 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
140 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
141 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
142 wxFLAGS_MEMBER(wxWANTS_CHARS
)
143 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
144 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
145 wxFLAGS_MEMBER(wxVSCROLL
)
146 wxFLAGS_MEMBER(wxHSCROLL
)
148 wxFLAGS_MEMBER(wxNB_FIXEDWIDTH
)
149 wxFLAGS_MEMBER(wxNB_LEFT
)
150 wxFLAGS_MEMBER(wxNB_RIGHT
)
151 wxFLAGS_MEMBER(wxNB_BOTTOM
)
153 wxEND_FLAGS( wxNotebookStyle
)
155 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebook
, wxControl
,"wx/notebook.h")
156 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebookPageInfo
, wxObject
, "wx/notebook.h" )
158 wxCOLLECTION_TYPE_INFO( wxNotebookPageInfo
* , wxNotebookPageInfoList
) ;
160 template<> void wxCollectionToVariantArray( wxNotebookPageInfoList
const &theList
, wxxVariantArray
&value
)
162 wxListCollectionToVariantArray
<wxNotebookPageInfoList::compatibility_iterator
>( theList
, value
) ;
165 wxBEGIN_PROPERTIES_TABLE(wxNotebook
)
166 wxEVENT_PROPERTY( PageChanging
, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, wxNotebookEvent
)
167 wxEVENT_PROPERTY( PageChanged
, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
, wxNotebookEvent
)
169 wxPROPERTY_COLLECTION( PageInfos
, wxNotebookPageInfoList
, wxNotebookPageInfo
* , AddPageInfo
, GetPageInfos
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
170 wxPROPERTY_FLAGS( WindowStyle
, wxNotebookStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
171 wxEND_PROPERTIES_TABLE()
173 wxBEGIN_HANDLERS_TABLE(wxNotebook
)
174 wxEND_HANDLERS_TABLE()
176 wxCONSTRUCTOR_5( wxNotebook
, wxWindow
* , Parent
, wxWindowID
, Id
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
179 wxBEGIN_PROPERTIES_TABLE(wxNotebookPageInfo
)
180 wxREADONLY_PROPERTY( Page
, wxNotebookPage
* , GetPage
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
181 wxREADONLY_PROPERTY( Text
, wxString
, GetText
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
182 wxREADONLY_PROPERTY( Selected
, bool , GetSelected
, false, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
183 wxREADONLY_PROPERTY( ImageId
, int , GetImageId
, -1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
184 wxEND_PROPERTIES_TABLE()
186 wxBEGIN_HANDLERS_TABLE(wxNotebookPageInfo
)
187 wxEND_HANDLERS_TABLE()
189 wxCONSTRUCTOR_4( wxNotebookPageInfo
, wxNotebookPage
* , Page
, wxString
, Text
, bool , Selected
, int , ImageId
)
192 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
)
193 IMPLEMENT_DYNAMIC_CLASS(wxNotebookPageInfo
, wxObject
)
195 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxNotifyEvent
)
197 // ============================================================================
199 // ============================================================================
201 // ----------------------------------------------------------------------------
202 // wxNotebook construction
203 // ----------------------------------------------------------------------------
205 const wxNotebookPageInfoList
& wxNotebook::GetPageInfos() const
207 wxNotebookPageInfoList
* list
= const_cast< wxNotebookPageInfoList
* >( &m_pageInfos
) ;
208 WX_CLEAR_LIST( wxNotebookPageInfoList
, *list
) ;
209 for( size_t i
= 0 ; i
< GetPageCount() ; ++i
)
211 wxNotebookPageInfo
*info
= new wxNotebookPageInfo() ;
212 info
->Create( const_cast<wxNotebook
*>(this)->GetPage(i
) , GetPageText(i
) , GetSelection() == int(i
) , GetPageImage(i
) ) ;
213 list
->Append( info
) ;
218 // common part of all ctors
219 void wxNotebook::Init()
225 // default for dynamic class
226 wxNotebook::wxNotebook()
231 // the same arguments as for wxControl
232 wxNotebook::wxNotebook(wxWindow
*parent
,
237 const wxString
& name
)
241 Create(parent
, id
, pos
, size
, style
, name
);
245 bool wxNotebook::Create(wxWindow
*parent
,
250 const wxString
& name
)
252 // Does ComCtl32 support non-top tabs?
253 int verComCtl32
= wxApp::GetComCtl32Version();
254 if ( verComCtl32
< 470 || verComCtl32
>= 600 )
256 if (style
& wxNB_BOTTOM
)
257 style
&= ~wxNB_BOTTOM
;
259 if (style
& wxNB_LEFT
)
262 if (style
& wxNB_RIGHT
)
263 style
&= ~wxNB_RIGHT
;
266 if ( !CreateControl(parent
, id
, pos
, size
, style
| wxTAB_TRAVERSAL
,
267 wxDefaultValidator
, name
) )
270 if ( !MSWCreateControl(WC_TABCONTROL
, wxEmptyString
, pos
, size
) )
273 SetBackgroundColour(wxColour(::GetSysColor(COLOR_BTNFACE
)));
278 WXDWORD
wxNotebook::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
280 WXDWORD tabStyle
= wxControl::MSWGetStyle(style
, exstyle
);
282 tabStyle
|= WS_TABSTOP
| TCS_TABS
;
284 if ( style
& wxNB_MULTILINE
)
285 tabStyle
|= TCS_MULTILINE
;
286 if ( style
& wxNB_FIXEDWIDTH
)
287 tabStyle
|= TCS_FIXEDWIDTH
;
289 if ( style
& wxNB_BOTTOM
)
290 tabStyle
|= TCS_RIGHT
;
291 else if ( style
& wxNB_LEFT
)
292 tabStyle
|= TCS_VERTICAL
;
293 else if ( style
& wxNB_RIGHT
)
294 tabStyle
|= TCS_VERTICAL
| TCS_RIGHT
;
299 // note that we never want to have the default WS_EX_CLIENTEDGE style
300 // as it looks too ugly for the notebooks
307 // ----------------------------------------------------------------------------
308 // wxNotebook accessors
309 // ----------------------------------------------------------------------------
311 size_t wxNotebook::GetPageCount() const
314 wxASSERT( (int)m_pages
.Count() == TabCtrl_GetItemCount(m_hwnd
) );
316 return m_pages
.Count();
319 int wxNotebook::GetRowCount() const
321 return TabCtrl_GetRowCount(m_hwnd
);
324 int wxNotebook::SetSelection(size_t nPage
)
326 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
328 if ( int(nPage
) != m_nSelection
)
330 wxNotebookEvent
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, m_windowId
);
331 event
.SetSelection(nPage
);
332 event
.SetOldSelection(m_nSelection
);
333 event
.SetEventObject(this);
334 if ( !GetEventHandler()->ProcessEvent(event
) || event
.IsAllowed() )
336 // program allows the page change
337 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
338 (void)GetEventHandler()->ProcessEvent(event
);
340 TabCtrl_SetCurSel(m_hwnd
, nPage
);
347 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
)
349 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
352 tcItem
.mask
= TCIF_TEXT
;
353 tcItem
.pszText
= (wxChar
*)strText
.c_str();
355 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
358 wxString
wxNotebook::GetPageText(size_t nPage
) const
360 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") );
364 tcItem
.mask
= TCIF_TEXT
;
365 tcItem
.pszText
= buf
;
366 tcItem
.cchTextMax
= WXSIZEOF(buf
);
369 if ( TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) )
370 str
= tcItem
.pszText
;
375 int wxNotebook::GetPageImage(size_t nPage
) const
377 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
380 tcItem
.mask
= TCIF_IMAGE
;
382 return TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) ? tcItem
.iImage
: -1;
385 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
)
387 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
390 tcItem
.mask
= TCIF_IMAGE
;
391 tcItem
.iImage
= nImage
;
393 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
396 void wxNotebook::SetImageList(wxImageList
* imageList
)
398 wxNotebookBase::SetImageList(imageList
);
402 TabCtrl_SetImageList(m_hwnd
, (HIMAGELIST
)imageList
->GetHIMAGELIST());
406 // ----------------------------------------------------------------------------
407 // wxNotebook size settings
408 // ----------------------------------------------------------------------------
410 void wxNotebook::SetPageSize(const wxSize
& size
)
412 // transform the page size into the notebook size
419 TabCtrl_AdjustRect(GetHwnd(), true, &rc
);
422 SetSize(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
425 void wxNotebook::SetPadding(const wxSize
& padding
)
427 TabCtrl_SetPadding(GetHwnd(), padding
.x
, padding
.y
);
430 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
432 void wxNotebook::SetTabSize(const wxSize
& sz
)
434 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE
, 0, MAKELPARAM(sz
.x
, sz
.y
));
437 wxSize
wxNotebook::CalcSizeFromPage(const wxSize
& sizePage
) const
439 wxSize sizeTotal
= sizePage
;
441 // We need to make getting tab size part of the wxWidgets API.
442 wxSize
tabSize(0, 0);
443 if (GetPageCount() > 0)
446 TabCtrl_GetItemRect((HWND
) GetHWND(), 0, & rect
);
447 tabSize
.x
= rect
.right
- rect
.left
;
448 tabSize
.y
= rect
.bottom
- rect
.top
;
450 if ( HasFlag(wxNB_LEFT
) || HasFlag(wxNB_RIGHT
) )
452 sizeTotal
.x
+= tabSize
.x
+ 7;
458 sizeTotal
.y
+= tabSize
.y
+ 7;
464 void wxNotebook::AdjustPageSize(wxNotebookPage
*page
)
466 wxCHECK_RET( page
, _T("NULL page in wxNotebook::AdjustPageSize") );
472 // get the page size from the notebook size
473 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
475 // This check is to work around a bug in TabCtrl_AdjustRect which will
476 // cause a crash on win2k, or on XP with themes disabled, if the
477 // wxNB_MULTILINE style is used and the rectangle is very small, (such as
478 // when the notebook is first created.) The value of 20 is just
479 // arbitrarily chosen, if there is a better way to determine this value
480 // then please do so. --RD
481 if (rc
.right
> 20 && rc
.bottom
> 20)
483 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
484 page
->SetSize(rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
488 // ----------------------------------------------------------------------------
489 // wxNotebook operations
490 // ----------------------------------------------------------------------------
492 // remove one page from the notebook, without deleting
493 wxNotebookPage
*wxNotebook::DoRemovePage(size_t nPage
)
495 wxNotebookPage
*pageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
499 TabCtrl_DeleteItem(m_hwnd
, nPage
);
501 if ( m_pages
.IsEmpty() )
503 // no selection any more, the notebook becamse empty
506 else // notebook still not empty
508 int selNew
= TabCtrl_GetCurSel(m_hwnd
);
511 // No selection change, just refresh the current selection.
512 // Because it could be that the slection index changed
513 // we need to update it.
514 // Note: this does not mean the selection it self changed.
515 m_nSelection
= selNew
;
516 m_pages
[m_nSelection
]->Refresh();
518 else if (int(nPage
) == m_nSelection
)
520 // The selection was deleted.
522 // Determine new selection.
523 if (m_nSelection
== int(GetPageCount()))
524 selNew
= m_nSelection
- 1;
526 selNew
= m_nSelection
;
528 // m_nSelection must be always valid so reset it before calling
531 SetSelection(selNew
);
535 wxFAIL
; // Windows did not behave ok.
543 bool wxNotebook::DeleteAllPages()
545 size_t nPageCount
= GetPageCount();
547 for ( nPage
= 0; nPage
< nPageCount
; nPage
++ )
548 delete m_pages
[nPage
];
552 TabCtrl_DeleteAllItems(m_hwnd
);
556 InvalidateBestSize();
560 // same as AddPage() but does it at given position
561 bool wxNotebook::InsertPage(size_t nPage
,
562 wxNotebookPage
*pPage
,
563 const wxString
& strText
,
567 wxCHECK_MSG( pPage
!= NULL
, false, _T("NULL page in wxNotebook::InsertPage") );
568 wxCHECK_MSG( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false,
569 _T("invalid index in wxNotebook::InsertPage") );
571 wxASSERT_MSG( pPage
->GetParent() == this,
572 _T("notebook pages must have notebook as parent") );
574 #if wxUSE_UXTHEME && wxUSE_UXTHEME_AUTO
575 static bool g_TestedForTheme
= false;
576 static bool g_UseTheme
= false;
577 if (!g_TestedForTheme
)
579 int commCtrlVersion
= wxTheApp
->GetComCtl32Version() ;
581 g_UseTheme
= (commCtrlVersion
>= 600);
582 g_TestedForTheme
= true;
585 // Automatically apply the theme background,
586 // changing the colour of the panel to match the
587 // tab page colour. This won't work well with all
588 // themes but it's a start.
589 if (g_UseTheme
&& wxUxThemeEngine::Get() && pPage
->IsKindOf(CLASSINFO(wxPanel
)))
591 ApplyThemeBackground(pPage
, GetThemeBackgroundColour());
595 // add a new tab to the control
596 // ----------------------------
598 // init all fields to 0
600 wxZeroMemory(tcItem
);
602 // set the image, if any
605 tcItem
.mask
|= TCIF_IMAGE
;
606 tcItem
.iImage
= imageId
;
610 if ( !strText
.IsEmpty() )
612 tcItem
.mask
|= TCIF_TEXT
;
613 tcItem
.pszText
= (wxChar
*)strText
.c_str(); // const_cast
616 // hide the page: unless it is selected, it shouldn't be shown (and if it
617 // is selected it will be shown later)
618 HWND hwnd
= GetWinHwnd(pPage
);
619 SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~WS_VISIBLE
);
621 // this updates internal flag too -- otherwise it would get out of sync
622 // with the real state
626 // fit the notebook page to the tab control's display area: this should be
627 // done before adding it to the notebook or TabCtrl_InsertItem() will
628 // change the notebooks size itself!
629 AdjustPageSize(pPage
);
631 // finally do insert it
632 if ( TabCtrl_InsertItem(m_hwnd
, nPage
, &tcItem
) == -1 )
634 wxLogError(wxT("Can't create the notebook page '%s'."), strText
.c_str());
639 // succeeded: save the pointer to the page
640 m_pages
.Insert(pPage
, nPage
);
642 // we may need to adjust the size again if the notebook size changed:
643 // normally this only happens for the first page we add (the tabs which
644 // hadn't been there before are now shown) but for a multiline notebook it
645 // can happen for any page at all as a new row could have been started
646 if ( m_pages
.GetCount() == 1 || HasFlag(wxNB_MULTILINE
) )
648 AdjustPageSize(pPage
);
651 // now deal with the selection
652 // ---------------------------
654 // if the inserted page is before the selected one, we must update the
655 // index of the selected page
656 if ( int(nPage
) <= m_nSelection
)
658 // one extra page added
662 // some page should be selected: either this one or the first one if there
663 // is still no selection
667 else if ( m_nSelection
== -1 )
671 SetSelection(selNew
);
673 InvalidateBestSize();
677 int wxNotebook::HitTest(const wxPoint
& pt
, long *flags
) const
679 TC_HITTESTINFO hitTestInfo
;
680 hitTestInfo
.pt
.x
= pt
.x
;
681 hitTestInfo
.pt
.y
= pt
.y
;
682 int item
= TabCtrl_HitTest(GetHwnd(), &hitTestInfo
);
688 if ((hitTestInfo
.flags
& TCHT_NOWHERE
) == TCHT_NOWHERE
)
689 *flags
|= wxNB_HITTEST_NOWHERE
;
690 if ((hitTestInfo
.flags
& TCHT_ONITEM
) == TCHT_ONITEM
)
691 *flags
|= wxNB_HITTEST_ONITEM
;
692 if ((hitTestInfo
.flags
& TCHT_ONITEMICON
) == TCHT_ONITEMICON
)
693 *flags
|= wxNB_HITTEST_ONICON
;
694 if ((hitTestInfo
.flags
& TCHT_ONITEMLABEL
) == TCHT_ONITEMLABEL
)
695 *flags
|= wxNB_HITTEST_ONLABEL
;
702 // ----------------------------------------------------------------------------
703 // wxNotebook callbacks
704 // ----------------------------------------------------------------------------
706 void wxNotebook::OnSize(wxSizeEvent
& event
)
708 // fit the notebook page to the tab control's display area
710 rc
.left
= rc
.top
= 0;
711 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
713 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
714 // returns completely false values for multiline tab controls after the tabs
715 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
717 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
719 // and the only work around I could find was this ugly hack... without it
720 // simply toggling the "multiline" checkbox in the notebook sample resulted
721 // in a noticeable page displacement
722 if ( HasFlag(wxNB_MULTILINE
) )
724 // avoid an infinite recursion: we get another notification too!
725 static bool s_isInOnSize
= false;
730 SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
,
731 MAKELPARAM(rc
.right
, rc
.bottom
));
732 s_isInOnSize
= false;
736 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
738 int width
= rc
.right
- rc
.left
,
739 height
= rc
.bottom
- rc
.top
;
740 size_t nCount
= m_pages
.Count();
741 for ( size_t nPage
= 0; nPage
< nCount
; nPage
++ ) {
742 wxNotebookPage
*pPage
= m_pages
[nPage
];
743 pPage
->SetSize(rc
.left
, rc
.top
, width
, height
);
749 void wxNotebook::OnSelChange(wxNotebookEvent
& event
)
751 // is it our tab control?
752 if ( event
.GetEventObject() == this )
754 int sel
= event
.GetOldSelection();
756 m_pages
[sel
]->Show(false);
758 sel
= event
.GetSelection();
761 wxNotebookPage
*pPage
= m_pages
[sel
];
765 // If the newly focused window is not a child of the new page,
766 // SetFocus was not successful and the notebook itself should be
768 wxWindow
*currentFocus
= FindFocus();
769 wxWindow
*startFocus
= currentFocus
;
770 while ( currentFocus
&& currentFocus
!= pPage
&& currentFocus
!= this )
771 currentFocus
= currentFocus
->GetParent();
773 if ( startFocus
== pPage
|| currentFocus
!= pPage
)
777 else // no pages in the notebook, give the focus to itself
785 // we want to give others a chance to process this message as well
789 bool wxNotebook::MSWTranslateMessage(WXMSG
*wxmsg
)
791 const MSG
* const msg
= (MSG
*)wxmsg
;
793 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
794 // TAB will be passed to the currently selected page, CTRL+TAB and
795 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
796 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
798 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_TAB
&&
799 msg
->hwnd
== m_hwnd
&&
800 (wxIsCtrlDown() || !wxIsShiftDown()) )
802 return MSWProcessMessage(wxmsg
);
808 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
)
810 if ( event
.IsWindowChange() ) {
812 AdvanceSelection(event
.GetDirection());
815 // we get this event in 3 cases
817 // a) one of our pages might have generated it because the user TABbed
818 // out from it in which case we should propagate the event upwards and
819 // our parent will take care of setting the focus to prev/next sibling
823 // b) the parent panel wants to give the focus to us so that we
824 // forward it to our selected page. We can't deal with this in
825 // OnSetFocus() because we don't know which direction the focus came
826 // from in this case and so can't choose between setting the focus to
827 // first or last panel child
831 // c) we ourselves (see MSWTranslateMessage) generated the event
833 wxWindow
* const parent
= GetParent();
835 const bool isFromParent
= event
.GetEventObject() == parent
;
836 const bool isFromSelf
= event
.GetEventObject() == this;
838 if ( isFromParent
|| isFromSelf
)
840 // no, it doesn't come from child, case (b) or (c): forward to a
841 // page but only if direction is backwards (TAB) or from ourselves,
842 if ( m_nSelection
!= -1 &&
843 (!event
.GetDirection() || isFromSelf
) )
845 // so that the page knows that the event comes from it's parent
846 // and is being propagated downwards
847 event
.SetEventObject(this);
849 wxWindow
*page
= m_pages
[m_nSelection
];
850 if ( !page
->GetEventHandler()->ProcessEvent(event
) )
854 //else: page manages focus inside it itself
856 else // otherwise set the focus to the notebook itself
863 // it comes from our child, case (a), pass to the parent, but only
864 // if the direction is forwards. Otherwise set the focus to the
865 // notebook itself. The notebook is always the 'first' control of a
867 if ( !event
.GetDirection() )
873 event
.SetCurrentFocus(this);
874 parent
->GetEventHandler()->ProcessEvent(event
);
880 // ----------------------------------------------------------------------------
881 // wxNotebook base class virtuals
882 // ----------------------------------------------------------------------------
884 #if wxUSE_CONSTRAINTS
886 // override these 2 functions to do nothing: everything is done in OnSize
888 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
))
890 // don't set the sizes of the pages - their correct size is not yet known
891 wxControl::SetConstraintSizes(false);
894 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
))
899 #endif // wxUSE_CONSTRAINTS
901 // ----------------------------------------------------------------------------
902 // wxNotebook Windows message handlers
903 // ----------------------------------------------------------------------------
905 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
,
906 WXWORD pos
, WXHWND control
)
908 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
913 return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
);
916 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
)
918 wxNotebookEvent
event(wxEVT_NULL
, m_windowId
);
920 NMHDR
* hdr
= (NMHDR
*)lParam
;
921 switch ( hdr
->code
) {
923 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
926 case TCN_SELCHANGING
:
927 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
);
931 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
934 event
.SetSelection(TabCtrl_GetCurSel(m_hwnd
));
935 event
.SetOldSelection(m_nSelection
);
936 event
.SetEventObject(this);
937 event
.SetInt(idCtrl
);
939 bool processed
= GetEventHandler()->ProcessEvent(event
);
940 *result
= !event
.IsAllowed();
944 // Windows only: attempts to get colour for UX theme page background
945 wxColour
wxNotebook::GetThemeBackgroundColour()
948 if (wxUxThemeEngine::Get())
950 wxUxThemeHandle
hTheme(this, L
"TAB");
953 // This is total guesswork.
954 // See PlatformSDK\Include\Tmschema.h for values
956 wxUxThemeEngine::Get()->GetThemeColor(
960 3821 /* FILLCOLORHINT */,
964 [DS] Workaround for WindowBlinds:
965 Some themes return a near black theme color using FILLCOLORHINT,
966 this makes notebook pages have an ugly black background and makes
967 text (usually black) unreadable. Retry again with FILLCOLOR.
969 This workaround potentially breaks appearance of some themes,
970 but in practice it already fixes some themes.
974 wxUxThemeEngine::Get()->GetThemeColor(
978 3802 /* FILLCOLOR */,
982 wxColour
colour(GetRValue(themeColor
), GetGValue(themeColor
), GetBValue(themeColor
));
986 #endif // wxUSE_UXTHEME
988 return GetBackgroundColour();
991 // Windows only: attempts to apply the UX theme page background to this page
993 void wxNotebook::ApplyThemeBackground(wxWindow
* window
, const wxColour
& colour
)
995 void wxNotebook::ApplyThemeBackground(wxWindow
*, const wxColour
&)
1000 window
->ApplyParentThemeBackground(colour
);
1002 for ( wxWindowList::compatibility_iterator node
= window
->GetChildren().GetFirst(); node
; node
= node
->GetNext() )
1004 wxWindow
*child
= node
->GetData();
1005 ApplyThemeBackground(child
, colour
);
1011 WXLRESULT
wxNotebook::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
1013 static bool g_TestedForTheme
= false;
1014 static bool g_supportsThemes
= false;
1019 if (!g_TestedForTheme
)
1021 int commCtrlVersion
= wxTheApp
->GetComCtl32Version() ;
1023 g_supportsThemes
= (commCtrlVersion
>= 600);
1024 g_TestedForTheme
= true;
1027 // If currently an XP theme is active, it seems we can get away
1028 // with not drawing a background, which reduces flicker.
1029 if (g_supportsThemes
)
1031 wxUxThemeEngine
*p
= wxUxThemeEngine::Get();
1032 if (p
&& p
->IsThemeActive() )
1040 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);
1042 #endif // #if wxUSE_UXTHEME
1044 #endif // wxUSE_NOTEBOOK