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
, , 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
, , 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
), -1, 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 wxWindows 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
);
474 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
476 page
->SetSize(rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
479 // ----------------------------------------------------------------------------
480 // wxNotebook operations
481 // ----------------------------------------------------------------------------
483 // remove one page from the notebook, without deleting
484 wxNotebookPage
*wxNotebook::DoRemovePage(size_t nPage
)
486 wxNotebookPage
*pageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
490 TabCtrl_DeleteItem(m_hwnd
, nPage
);
492 if ( m_pages
.IsEmpty() )
494 // no selection any more, the notebook becamse empty
497 else // notebook still not empty
499 int selNew
= TabCtrl_GetCurSel(m_hwnd
);
502 // No selection change, just refresh the current selection.
503 // Because it could be that the slection index changed
504 // we need to update it.
505 // Note: this does not mean the selection it self changed.
506 m_nSelection
= selNew
;
507 m_pages
[m_nSelection
]->Refresh();
509 else if (int(nPage
) == m_nSelection
)
511 // The selection was deleted.
513 // Determine new selection.
514 if (m_nSelection
== int(GetPageCount()))
515 selNew
= m_nSelection
- 1;
517 selNew
= m_nSelection
;
519 // m_nSelection must be always valid so reset it before calling
522 SetSelection(selNew
);
526 wxFAIL
; // Windows did not behave ok.
534 bool wxNotebook::DeleteAllPages()
536 size_t nPageCount
= GetPageCount();
538 for ( nPage
= 0; nPage
< nPageCount
; nPage
++ )
539 delete m_pages
[nPage
];
543 TabCtrl_DeleteAllItems(m_hwnd
);
550 // same as AddPage() but does it at given position
551 bool wxNotebook::InsertPage(size_t nPage
,
552 wxNotebookPage
*pPage
,
553 const wxString
& strText
,
557 wxCHECK_MSG( pPage
!= NULL
, false, _T("NULL page in wxNotebook::InsertPage") );
558 wxCHECK_MSG( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false,
559 _T("invalid index in wxNotebook::InsertPage") );
561 wxASSERT_MSG( pPage
->GetParent() == this,
562 _T("notebook pages must have notebook as parent") );
564 #if wxUSE_UXTHEME && wxUSE_UXTHEME_AUTO
565 static bool g_TestedForTheme
= false;
566 static bool g_UseTheme
= false;
567 if (!g_TestedForTheme
)
569 int commCtrlVersion
= wxTheApp
->GetComCtl32Version() ;
571 g_UseTheme
= (commCtrlVersion
>= 600);
572 g_TestedForTheme
= true;
575 // Automatically apply the theme background,
576 // changing the colour of the panel to match the
577 // tab page colour. This won't work well with all
578 // themes but it's a start.
579 if (g_UseTheme
&& wxUxThemeEngine::Get() && pPage
->IsKindOf(CLASSINFO(wxPanel
)))
581 ApplyThemeBackground(pPage
, GetThemeBackgroundColour());
585 // add a new tab to the control
586 // ----------------------------
588 // init all fields to 0
590 wxZeroMemory(tcItem
);
592 // set the image, if any
595 tcItem
.mask
|= TCIF_IMAGE
;
596 tcItem
.iImage
= imageId
;
600 if ( !strText
.IsEmpty() )
602 tcItem
.mask
|= TCIF_TEXT
;
603 tcItem
.pszText
= (wxChar
*)strText
.c_str(); // const_cast
606 // fit the notebook page to the tab control's display area: this should be
607 // done before adding it to the notebook or TabCtrl_InsertItem() will
608 // change the notebooks size itself!
609 AdjustPageSize(pPage
);
611 // finally do insert it
612 if ( TabCtrl_InsertItem(m_hwnd
, nPage
, &tcItem
) == -1 )
614 wxLogError(wxT("Can't create the notebook page '%s'."), strText
.c_str());
619 // succeeded: save the pointer to the page
620 m_pages
.Insert(pPage
, nPage
);
622 // we may need to adjust the size again if the notebook size changed:
623 // normally this only happens for the first page we add (the tabs which
624 // hadn't been there before are now shown) but for a multiline notebook it
625 // can happen for any page at all as a new row could have been started
626 if ( m_pages
.GetCount() == 1 || HasFlag(wxNB_MULTILINE
) )
628 AdjustPageSize(pPage
);
631 // hide the page: unless it is selected, it shouldn't be shown (and if it
632 // is selected it will be shown later)
633 HWND hwnd
= GetWinHwnd(pPage
);
634 SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~WS_VISIBLE
);
636 // this updates internal flag too -- otherwise it would get out of sync
637 // with the real state
641 // now deal with the selection
642 // ---------------------------
644 // if the inserted page is before the selected one, we must update the
645 // index of the selected page
646 if ( int(nPage
) <= m_nSelection
)
648 // one extra page added
652 // some page should be selected: either this one or the first one if there
653 // is still no selection
657 else if ( m_nSelection
== -1 )
661 SetSelection(selNew
);
666 int wxNotebook::HitTest(const wxPoint
& pt
, long *flags
) const
668 TC_HITTESTINFO hitTestInfo
;
669 hitTestInfo
.pt
.x
= pt
.x
;
670 hitTestInfo
.pt
.y
= pt
.y
;
671 int item
= TabCtrl_HitTest(GetHwnd(), &hitTestInfo
);
677 if ((hitTestInfo
.flags
& TCHT_NOWHERE
) == TCHT_NOWHERE
)
678 *flags
|= wxNB_HITTEST_NOWHERE
;
679 if ((hitTestInfo
.flags
& TCHT_ONITEM
) == TCHT_ONITEM
)
680 *flags
|= wxNB_HITTEST_ONITEM
;
681 if ((hitTestInfo
.flags
& TCHT_ONITEMICON
) == TCHT_ONITEMICON
)
682 *flags
|= wxNB_HITTEST_ONICON
;
683 if ((hitTestInfo
.flags
& TCHT_ONITEMLABEL
) == TCHT_ONITEMLABEL
)
684 *flags
|= wxNB_HITTEST_ONLABEL
;
691 // ----------------------------------------------------------------------------
692 // wxNotebook callbacks
693 // ----------------------------------------------------------------------------
695 void wxNotebook::OnSize(wxSizeEvent
& event
)
697 // fit the notebook page to the tab control's display area
699 rc
.left
= rc
.top
= 0;
700 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
702 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
703 // returns completely false values for multiline tab controls after the tabs
704 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
706 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
708 // and the only work around I could find was this ugly hack... without it
709 // simply toggling the "multiline" checkbox in the notebook sample resulted
710 // in a noticeable page displacement
711 if ( HasFlag(wxNB_MULTILINE
) )
713 // avoid an infinite recursion: we get another notification too!
714 static bool s_isInOnSize
= false;
719 SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
,
720 MAKELPARAM(rc
.right
, rc
.bottom
));
721 s_isInOnSize
= false;
725 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
727 int width
= rc
.right
- rc
.left
,
728 height
= rc
.bottom
- rc
.top
;
729 size_t nCount
= m_pages
.Count();
730 for ( size_t nPage
= 0; nPage
< nCount
; nPage
++ ) {
731 wxNotebookPage
*pPage
= m_pages
[nPage
];
732 pPage
->SetSize(rc
.left
, rc
.top
, width
, height
);
738 void wxNotebook::OnSelChange(wxNotebookEvent
& event
)
740 // is it our tab control?
741 if ( event
.GetEventObject() == this )
743 int sel
= event
.GetOldSelection();
745 m_pages
[sel
]->Show(false);
747 sel
= event
.GetSelection();
750 wxNotebookPage
*pPage
= m_pages
[sel
];
754 // If the newly focused window is not a child of the new page,
755 // SetFocus was not successful and the notebook itself should be
757 wxWindow
*currentFocus
= FindFocus();
758 wxWindow
*startFocus
= currentFocus
;
759 while ( currentFocus
&& currentFocus
!= pPage
&& currentFocus
!= this )
760 currentFocus
= currentFocus
->GetParent();
762 if ( startFocus
== pPage
|| currentFocus
!= pPage
)
766 else // no pages in the notebook, give the focus to itself
774 // we want to give others a chance to process this message as well
778 bool wxNotebook::MSWTranslateMessage(WXMSG
*wxmsg
)
780 const MSG
* const msg
= (MSG
*)wxmsg
;
782 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
783 // TAB will be passed to the currently selected page, CTRL+TAB and
784 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
785 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
787 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_TAB
&&
788 msg
->hwnd
== m_hwnd
&&
789 (wxIsCtrlDown() || !wxIsShiftDown()) )
791 return MSWProcessMessage(wxmsg
);
797 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
)
799 if ( event
.IsWindowChange() ) {
801 AdvanceSelection(event
.GetDirection());
804 // we get this event in 3 cases
806 // a) one of our pages might have generated it because the user TABbed
807 // out from it in which case we should propagate the event upwards and
808 // our parent will take care of setting the focus to prev/next sibling
812 // b) the parent panel wants to give the focus to us so that we
813 // forward it to our selected page. We can't deal with this in
814 // OnSetFocus() because we don't know which direction the focus came
815 // from in this case and so can't choose between setting the focus to
816 // first or last panel child
820 // c) we ourselves (see MSWTranslateMessage) generated the event
822 wxWindow
* const parent
= GetParent();
824 const bool isFromParent
= event
.GetEventObject() == parent
;
825 const bool isFromSelf
= event
.GetEventObject() == this;
827 if ( isFromParent
|| isFromSelf
)
829 // no, it doesn't come from child, case (b) or (c): forward to a
830 // page but only if direction is backwards (TAB) or from ourselves,
831 if ( m_nSelection
!= -1 &&
832 (!event
.GetDirection() || isFromSelf
) )
834 // so that the page knows that the event comes from it's parent
835 // and is being propagated downwards
836 event
.SetEventObject(this);
838 wxWindow
*page
= m_pages
[m_nSelection
];
839 if ( !page
->GetEventHandler()->ProcessEvent(event
) )
843 //else: page manages focus inside it itself
845 else // otherwise set the focus to the notebook itself
852 // it comes from our child, case (a), pass to the parent, but only
853 // if the direction is forwards. Otherwise set the focus to the
854 // notebook itself. The notebook is always the 'first' control of a
856 if ( !event
.GetDirection() )
862 event
.SetCurrentFocus(this);
863 parent
->GetEventHandler()->ProcessEvent(event
);
869 // ----------------------------------------------------------------------------
870 // wxNotebook base class virtuals
871 // ----------------------------------------------------------------------------
873 #if wxUSE_CONSTRAINTS
875 // override these 2 functions to do nothing: everything is done in OnSize
877 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
))
879 // don't set the sizes of the pages - their correct size is not yet known
880 wxControl::SetConstraintSizes(false);
883 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
))
888 #endif // wxUSE_CONSTRAINTS
890 // ----------------------------------------------------------------------------
891 // wxNotebook Windows message handlers
892 // ----------------------------------------------------------------------------
894 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
,
895 WXWORD pos
, WXHWND control
)
897 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
902 return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
);
905 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
)
907 wxNotebookEvent
event(wxEVT_NULL
, m_windowId
);
909 NMHDR
* hdr
= (NMHDR
*)lParam
;
910 switch ( hdr
->code
) {
912 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
915 case TCN_SELCHANGING
:
916 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
);
920 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
923 event
.SetSelection(TabCtrl_GetCurSel(m_hwnd
));
924 event
.SetOldSelection(m_nSelection
);
925 event
.SetEventObject(this);
926 event
.SetInt(idCtrl
);
928 bool processed
= GetEventHandler()->ProcessEvent(event
);
929 *result
= !event
.IsAllowed();
933 // Windows only: attempts to get colour for UX theme page background
934 wxColour
wxNotebook::GetThemeBackgroundColour()
937 if (wxUxThemeEngine::Get())
939 wxUxThemeHandle
hTheme(this, L
"TAB");
942 // This is total guesswork.
943 // See PlatformSDK\Include\Tmschema.h for values
945 wxUxThemeEngine::Get()->GetThemeColor(
949 3821 /* FILLCOLORHINT */,
953 [DS] Workaround for WindowBlinds:
954 Some themes return a near black theme color using FILLCOLORHINT,
955 this makes notebook pages have an ugly black background and makes
956 text (usually black) unreadable. Retry again with FILLCOLOR.
958 This workaround potentially breaks appearance of some themes,
959 but in practice it already fixes some themes.
963 wxUxThemeEngine::Get()->GetThemeColor(
967 3802 /* FILLCOLOR */,
971 wxColour
colour(GetRValue(themeColor
), GetGValue(themeColor
), GetBValue(themeColor
));
975 #endif // wxUSE_UXTHEME
977 return GetBackgroundColour();
980 // Windows only: attempts to apply the UX theme page background to this page
982 void wxNotebook::ApplyThemeBackground(wxWindow
* window
, const wxColour
& colour
)
984 void wxNotebook::ApplyThemeBackground(wxWindow
*, const wxColour
&)
989 window
->ApplyParentThemeBackground(colour
);
991 for ( wxWindowList::compatibility_iterator node
= window
->GetChildren().GetFirst(); node
; node
= node
->GetNext() )
993 wxWindow
*child
= node
->GetData();
994 ApplyThemeBackground(child
, colour
);
1000 WXLRESULT
wxNotebook::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
1002 static bool g_TestedForTheme
= false;
1003 static bool g_supportsThemes
= false;
1008 if (!g_TestedForTheme
)
1010 int commCtrlVersion
= wxTheApp
->GetComCtl32Version() ;
1012 g_supportsThemes
= (commCtrlVersion
>= 600);
1013 g_TestedForTheme
= true;
1016 // If currently an XP theme is active, it seems we can get away
1017 // with not drawing a background, which reduces flicker.
1018 if (g_supportsThemes
)
1020 wxUxThemeEngine
*p
= wxUxThemeEngine::Get();
1021 if (p
&& p
->IsThemeActive() )
1029 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);
1031 #endif // #if wxUSE_UXTHEME
1033 #endif // wxUSE_NOTEBOOK