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"
32 #include "wx/imaglist.h"
34 #include "wx/control.h"
35 #include "wx/notebook.h"
37 #include "wx/sysopt.h"
39 #include "wx/msw/private.h"
43 #ifdef __GNUWIN32_OLD__
44 #include "wx/msw/gnuwin32/extra.h"
47 #if !(defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__))
51 #include "wx/msw/winundef.h"
54 #include "wx/msw/uxtheme.h"
57 // ----------------------------------------------------------------------------
59 // ----------------------------------------------------------------------------
61 // check that the page index is valid
62 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount())
65 #define m_hwnd (HWND)GetHWND()
67 // ----------------------------------------------------------------------------
69 // ----------------------------------------------------------------------------
71 // This is a work-around for missing defines in gcc-2.95 headers
73 #define TCS_RIGHT 0x0002
77 #define TCS_VERTICAL 0x0080
81 #define TCS_BOTTOM TCS_RIGHT
84 // ----------------------------------------------------------------------------
86 // ----------------------------------------------------------------------------
88 #include <wx/listimpl.cpp>
90 WX_DEFINE_LIST( wxNotebookPageInfoList
) ;
92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
)
93 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
)
95 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
)
96 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange
)
97 EVT_SIZE(wxNotebook::OnSize
)
98 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
101 #if wxUSE_EXTENDED_RTTI
102 WX_DEFINE_FLAGS( wxNotebookStyle
)
104 wxBEGIN_FLAGS( wxNotebookStyle
)
105 // new style border flags, we put them first to
106 // use them for streaming out
107 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
108 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
109 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
110 wxFLAGS_MEMBER(wxBORDER_RAISED
)
111 wxFLAGS_MEMBER(wxBORDER_STATIC
)
112 wxFLAGS_MEMBER(wxBORDER_NONE
)
114 // old style border flags
115 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
116 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
117 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
118 wxFLAGS_MEMBER(wxRAISED_BORDER
)
119 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
120 wxFLAGS_MEMBER(wxBORDER
)
122 // standard window styles
123 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
124 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
125 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
126 wxFLAGS_MEMBER(wxWANTS_CHARS
)
127 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
128 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
129 wxFLAGS_MEMBER(wxVSCROLL
)
130 wxFLAGS_MEMBER(wxHSCROLL
)
132 wxFLAGS_MEMBER(wxNB_FIXEDWIDTH
)
133 wxFLAGS_MEMBER(wxNB_LEFT
)
134 wxFLAGS_MEMBER(wxNB_RIGHT
)
135 wxFLAGS_MEMBER(wxNB_BOTTOM
)
136 wxFLAGS_MEMBER(wxNB_NOPAGETHEME
)
137 wxFLAGS_MEMBER(wxNB_FLAT
)
139 wxEND_FLAGS( wxNotebookStyle
)
141 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebook
, wxControl
,"wx/notebook.h")
142 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebookPageInfo
, wxObject
, "wx/notebook.h" )
144 wxCOLLECTION_TYPE_INFO( wxNotebookPageInfo
* , wxNotebookPageInfoList
) ;
146 template<> void wxCollectionToVariantArray( wxNotebookPageInfoList
const &theList
, wxxVariantArray
&value
)
148 wxListCollectionToVariantArray
<wxNotebookPageInfoList::compatibility_iterator
>( theList
, value
) ;
151 wxBEGIN_PROPERTIES_TABLE(wxNotebook
)
152 wxEVENT_PROPERTY( PageChanging
, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, wxNotebookEvent
)
153 wxEVENT_PROPERTY( PageChanged
, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
, wxNotebookEvent
)
155 wxPROPERTY_COLLECTION( PageInfos
, wxNotebookPageInfoList
, wxNotebookPageInfo
* , AddPageInfo
, GetPageInfos
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
156 wxPROPERTY_FLAGS( WindowStyle
, wxNotebookStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
157 wxEND_PROPERTIES_TABLE()
159 wxBEGIN_HANDLERS_TABLE(wxNotebook
)
160 wxEND_HANDLERS_TABLE()
162 wxCONSTRUCTOR_5( wxNotebook
, wxWindow
* , Parent
, wxWindowID
, Id
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
165 wxBEGIN_PROPERTIES_TABLE(wxNotebookPageInfo
)
166 wxREADONLY_PROPERTY( Page
, wxNotebookPage
* , GetPage
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
167 wxREADONLY_PROPERTY( Text
, wxString
, GetText
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
168 wxREADONLY_PROPERTY( Selected
, bool , GetSelected
, false, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
169 wxREADONLY_PROPERTY( ImageId
, int , GetImageId
, -1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
170 wxEND_PROPERTIES_TABLE()
172 wxBEGIN_HANDLERS_TABLE(wxNotebookPageInfo
)
173 wxEND_HANDLERS_TABLE()
175 wxCONSTRUCTOR_4( wxNotebookPageInfo
, wxNotebookPage
* , Page
, wxString
, Text
, bool , Selected
, int , ImageId
)
178 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
)
179 IMPLEMENT_DYNAMIC_CLASS(wxNotebookPageInfo
, wxObject
)
181 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxNotifyEvent
)
183 // ============================================================================
185 // ============================================================================
187 // ----------------------------------------------------------------------------
188 // wxNotebook construction
189 // ----------------------------------------------------------------------------
191 const wxNotebookPageInfoList
& wxNotebook::GetPageInfos() const
193 wxNotebookPageInfoList
* list
= const_cast< wxNotebookPageInfoList
* >( &m_pageInfos
) ;
194 WX_CLEAR_LIST( wxNotebookPageInfoList
, *list
) ;
195 for( size_t i
= 0 ; i
< GetPageCount() ; ++i
)
197 wxNotebookPageInfo
*info
= new wxNotebookPageInfo() ;
198 info
->Create( const_cast<wxNotebook
*>(this)->GetPage(i
) , GetPageText(i
) , GetSelection() == int(i
) , GetPageImage(i
) ) ;
199 list
->Append( info
) ;
204 // common part of all ctors
205 void wxNotebook::Init()
211 m_hbrBackground
= NULL
;
212 #endif // wxUSE_UXTHEME
215 // default for dynamic class
216 wxNotebook::wxNotebook()
221 // the same arguments as for wxControl
222 wxNotebook::wxNotebook(wxWindow
*parent
,
227 const wxString
& name
)
231 Create(parent
, id
, pos
, size
, style
, name
);
235 bool wxNotebook::Create(wxWindow
*parent
,
240 const wxString
& name
)
242 // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the
243 // control is simply not rendered correctly), so disable them in this case
244 const int verComCtl32
= wxApp::GetComCtl32Version();
245 if ( verComCtl32
== 600 )
247 // check if we use themes at all -- if we don't, we're still ok
249 if ( wxUxThemeEngine::GetIfActive() )
252 style
&= ~(wxNB_BOTTOM
| wxNB_LEFT
| wxNB_RIGHT
);
256 LPCTSTR className
= WC_TABCONTROL
;
258 // SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it
259 // causes horrible flicker when resizing notebook, so get rid of it by
260 // using a class without these styles (but otherwise identical to it)
261 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
263 static ClassRegistrar s_clsNotebook
;
264 if ( !s_clsNotebook
.IsInitialized() )
266 // get a copy of standard class and modify it
269 if ( ::GetClassInfo(::GetModuleHandle(NULL
), WC_TABCONTROL
, &wc
) )
271 wc
.lpszClassName
= wxT("_wx_SysTabCtl32");
272 wc
.style
&= ~(CS_HREDRAW
| CS_VREDRAW
);
274 s_clsNotebook
.Register(wc
);
278 wxLogLastError(_T("GetClassInfoEx(SysTabCtl32)"));
282 // use our custom class if available but fall back to the standard
283 // notebook if we failed to register it
284 if ( s_clsNotebook
.IsRegistered() )
286 // it's ok to use c_str() here as the static s_clsNotebook object
287 // has sufficiently long lifetime
288 className
= s_clsNotebook
.GetName().c_str();
292 if ( !CreateControl(parent
, id
, pos
, size
, style
| wxTAB_TRAVERSAL
,
293 wxDefaultValidator
, name
) )
296 if ( !MSWCreateControl(className
, wxEmptyString
, pos
, size
) )
299 if (HasFlag(wxNB_NOPAGETHEME
) || (wxSystemOptions::HasOption(wxT("msw.notebook.themed-background")) &&
300 wxSystemOptions::GetOptionInt(wxT("msw.notebook.themed-background")) == 0))
302 wxColour col
= GetThemeBackgroundColour();
305 SetBackgroundColour(col
);
309 // Undocumented hack to get flat notebook style
310 // In fact, we should probably only do this in some
311 // curcumstances, i.e. if we know we will have a border
312 // at the bottom (the tab control doesn't draw it itself)
313 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
314 if (HasFlag(wxNB_FLAT
))
316 SendMessage(m_hwnd
, CCM_SETVERSION
, COMCTL32_VERSION
, 0);
318 SetBackgroundColour(*wxWHITE
);
324 WXDWORD
wxNotebook::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
326 WXDWORD tabStyle
= wxControl::MSWGetStyle(style
, exstyle
);
328 tabStyle
|= WS_TABSTOP
| TCS_TABS
;
330 if ( style
& wxNB_MULTILINE
)
331 tabStyle
|= TCS_MULTILINE
;
332 if ( style
& wxNB_FIXEDWIDTH
)
333 tabStyle
|= TCS_FIXEDWIDTH
;
335 if ( style
& wxNB_BOTTOM
)
336 tabStyle
|= TCS_RIGHT
;
337 else if ( style
& wxNB_LEFT
)
338 tabStyle
|= TCS_VERTICAL
;
339 else if ( style
& wxNB_RIGHT
)
340 tabStyle
|= TCS_VERTICAL
| TCS_RIGHT
;
345 // note that we never want to have the default WS_EX_CLIENTEDGE style
346 // as it looks too ugly for the notebooks
353 wxNotebook::~wxNotebook()
356 if ( m_hbrBackground
)
357 ::DeleteObject((HBRUSH
)m_hbrBackground
);
358 #endif // wxUSE_UXTHEME
361 // ----------------------------------------------------------------------------
362 // wxNotebook accessors
363 // ----------------------------------------------------------------------------
365 size_t wxNotebook::GetPageCount() const
368 wxASSERT( (int)m_pages
.Count() == TabCtrl_GetItemCount(m_hwnd
) );
370 return m_pages
.Count();
373 int wxNotebook::GetRowCount() const
375 return TabCtrl_GetRowCount(m_hwnd
);
378 int wxNotebook::SetSelection(size_t nPage
)
380 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
382 if ( int(nPage
) != m_nSelection
)
384 wxNotebookEvent
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, m_windowId
);
385 event
.SetSelection(nPage
);
386 event
.SetOldSelection(m_nSelection
);
387 event
.SetEventObject(this);
388 if ( !GetEventHandler()->ProcessEvent(event
) || event
.IsAllowed() )
390 // program allows the page change
391 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
392 (void)GetEventHandler()->ProcessEvent(event
);
394 TabCtrl_SetCurSel(m_hwnd
, nPage
);
401 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
)
403 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
406 tcItem
.mask
= TCIF_TEXT
;
407 tcItem
.pszText
= (wxChar
*)strText
.c_str();
409 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
412 wxString
wxNotebook::GetPageText(size_t nPage
) const
414 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") );
418 tcItem
.mask
= TCIF_TEXT
;
419 tcItem
.pszText
= buf
;
420 tcItem
.cchTextMax
= WXSIZEOF(buf
);
423 if ( TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) )
424 str
= tcItem
.pszText
;
429 int wxNotebook::GetPageImage(size_t nPage
) const
431 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
434 tcItem
.mask
= TCIF_IMAGE
;
436 return TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) ? tcItem
.iImage
: -1;
439 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
)
441 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
444 tcItem
.mask
= TCIF_IMAGE
;
445 tcItem
.iImage
= nImage
;
447 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
450 void wxNotebook::SetImageList(wxImageList
* imageList
)
452 wxNotebookBase::SetImageList(imageList
);
456 TabCtrl_SetImageList(m_hwnd
, (HIMAGELIST
)imageList
->GetHIMAGELIST());
460 // ----------------------------------------------------------------------------
461 // wxNotebook size settings
462 // ----------------------------------------------------------------------------
464 void wxNotebook::SetPageSize(const wxSize
& size
)
466 // transform the page size into the notebook size
473 TabCtrl_AdjustRect(GetHwnd(), true, &rc
);
476 SetSize(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
479 void wxNotebook::SetPadding(const wxSize
& padding
)
481 TabCtrl_SetPadding(GetHwnd(), padding
.x
, padding
.y
);
484 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
486 void wxNotebook::SetTabSize(const wxSize
& sz
)
488 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE
, 0, MAKELPARAM(sz
.x
, sz
.y
));
491 wxSize
wxNotebook::CalcSizeFromPage(const wxSize
& sizePage
) const
493 wxSize sizeTotal
= sizePage
;
495 // We need to make getting tab size part of the wxWidgets API.
497 if (GetPageCount() > 0)
500 TabCtrl_GetItemRect((HWND
) GetHWND(), 0, & rect
);
501 tabSize
.x
= rect
.right
- rect
.left
;
502 tabSize
.y
= rect
.bottom
- rect
.top
;
504 if ( HasFlag(wxNB_LEFT
) || HasFlag(wxNB_RIGHT
) )
506 sizeTotal
.x
+= tabSize
.x
+ 7;
512 sizeTotal
.y
+= tabSize
.y
+ 7;
518 void wxNotebook::AdjustPageSize(wxNotebookPage
*page
)
520 wxCHECK_RET( page
, _T("NULL page in wxNotebook::AdjustPageSize") );
526 // get the page size from the notebook size
527 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
529 // This check is to work around a bug in TabCtrl_AdjustRect which will
530 // cause a crash on win2k, or on XP with themes disabled, if the
531 // wxNB_MULTILINE style is used and the rectangle is very small, (such as
532 // when the notebook is first created.) The value of 20 is just
533 // arbitrarily chosen, if there is a better way to determine this value
534 // then please do so. --RD
535 if (rc
.right
> 20 && rc
.bottom
> 20)
537 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
538 page
->SetSize(rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
542 // ----------------------------------------------------------------------------
543 // wxNotebook operations
544 // ----------------------------------------------------------------------------
546 // remove one page from the notebook, without deleting
547 wxNotebookPage
*wxNotebook::DoRemovePage(size_t nPage
)
549 wxNotebookPage
*pageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
553 TabCtrl_DeleteItem(m_hwnd
, nPage
);
555 if ( m_pages
.IsEmpty() )
557 // no selection any more, the notebook becamse empty
560 else // notebook still not empty
562 int selNew
= TabCtrl_GetCurSel(m_hwnd
);
565 // No selection change, just refresh the current selection.
566 // Because it could be that the slection index changed
567 // we need to update it.
568 // Note: this does not mean the selection it self changed.
569 m_nSelection
= selNew
;
570 m_pages
[m_nSelection
]->Refresh();
572 else if (int(nPage
) == m_nSelection
)
574 // The selection was deleted.
576 // Determine new selection.
577 if (m_nSelection
== int(GetPageCount()))
578 selNew
= m_nSelection
- 1;
580 selNew
= m_nSelection
;
582 // m_nSelection must be always valid so reset it before calling
585 SetSelection(selNew
);
589 wxFAIL
; // Windows did not behave ok.
597 bool wxNotebook::DeleteAllPages()
599 size_t nPageCount
= GetPageCount();
601 for ( nPage
= 0; nPage
< nPageCount
; nPage
++ )
602 delete m_pages
[nPage
];
606 TabCtrl_DeleteAllItems(m_hwnd
);
610 InvalidateBestSize();
614 // same as AddPage() but does it at given position
615 bool wxNotebook::InsertPage(size_t nPage
,
616 wxNotebookPage
*pPage
,
617 const wxString
& strText
,
621 wxCHECK_MSG( pPage
!= NULL
, false, _T("NULL page in wxNotebook::InsertPage") );
622 wxCHECK_MSG( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false,
623 _T("invalid index in wxNotebook::InsertPage") );
625 wxASSERT_MSG( pPage
->GetParent() == this,
626 _T("notebook pages must have notebook as parent") );
628 // add a new tab to the control
629 // ----------------------------
631 // init all fields to 0
633 wxZeroMemory(tcItem
);
635 // set the image, if any
638 tcItem
.mask
|= TCIF_IMAGE
;
639 tcItem
.iImage
= imageId
;
643 if ( !strText
.empty() )
645 tcItem
.mask
|= TCIF_TEXT
;
646 tcItem
.pszText
= (wxChar
*)strText
.c_str(); // const_cast
649 // hide the page: unless it is selected, it shouldn't be shown (and if it
650 // is selected it will be shown later)
651 HWND hwnd
= GetWinHwnd(pPage
);
652 SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~WS_VISIBLE
);
654 // this updates internal flag too -- otherwise it would get out of sync
655 // with the real state
659 // fit the notebook page to the tab control's display area: this should be
660 // done before adding it to the notebook or TabCtrl_InsertItem() will
661 // change the notebooks size itself!
662 AdjustPageSize(pPage
);
664 // finally do insert it
665 if ( TabCtrl_InsertItem(m_hwnd
, nPage
, &tcItem
) == -1 )
667 wxLogError(wxT("Can't create the notebook page '%s'."), strText
.c_str());
672 // succeeded: save the pointer to the page
673 m_pages
.Insert(pPage
, nPage
);
675 // we may need to adjust the size again if the notebook size changed:
676 // normally this only happens for the first page we add (the tabs which
677 // hadn't been there before are now shown) but for a multiline notebook it
678 // can happen for any page at all as a new row could have been started
679 if ( m_pages
.GetCount() == 1 || HasFlag(wxNB_MULTILINE
) )
681 AdjustPageSize(pPage
);
684 // now deal with the selection
685 // ---------------------------
687 // if the inserted page is before the selected one, we must update the
688 // index of the selected page
689 if ( int(nPage
) <= m_nSelection
)
691 // one extra page added
695 // some page should be selected: either this one or the first one if there
696 // is still no selection
700 else if ( m_nSelection
== -1 )
704 SetSelection(selNew
);
706 InvalidateBestSize();
711 int wxNotebook::HitTest(const wxPoint
& pt
, long *flags
) const
713 TC_HITTESTINFO hitTestInfo
;
714 hitTestInfo
.pt
.x
= pt
.x
;
715 hitTestInfo
.pt
.y
= pt
.y
;
716 int item
= TabCtrl_HitTest(GetHwnd(), &hitTestInfo
);
722 if ((hitTestInfo
.flags
& TCHT_NOWHERE
) == TCHT_NOWHERE
)
723 *flags
|= wxNB_HITTEST_NOWHERE
;
724 if ((hitTestInfo
.flags
& TCHT_ONITEM
) == TCHT_ONITEM
)
725 *flags
|= wxNB_HITTEST_ONITEM
;
726 if ((hitTestInfo
.flags
& TCHT_ONITEMICON
) == TCHT_ONITEMICON
)
727 *flags
|= wxNB_HITTEST_ONICON
;
728 if ((hitTestInfo
.flags
& TCHT_ONITEMLABEL
) == TCHT_ONITEMLABEL
)
729 *flags
|= wxNB_HITTEST_ONLABEL
;
736 // ----------------------------------------------------------------------------
737 // wxNotebook callbacks
738 // ----------------------------------------------------------------------------
740 void wxNotebook::OnSize(wxSizeEvent
& event
)
742 // update the background brush
745 #endif // wxUSE_UXTHEME
747 if (GetPageCount() == 0)
749 // Prevents droppings on resize, but does cause some flicker
750 // when there are no pages.
756 // fit all the notebook pages to the tab control's display area
759 rc
.left
= rc
.top
= 0;
760 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
762 // save the total size, we'll use it below
763 int widthNbook
= rc
.right
- rc
.left
,
764 heightNbook
= rc
.bottom
- rc
.top
;
766 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
767 // returns completely false values for multiline tab controls after the tabs
768 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
770 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
772 // and the only work around I could find was this ugly hack... without it
773 // simply toggling the "multiline" checkbox in the notebook sample resulted
774 // in a noticeable page displacement
775 if ( HasFlag(wxNB_MULTILINE
) )
777 // avoid an infinite recursion: we get another notification too!
778 static bool s_isInOnSize
= false;
783 SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
,
784 MAKELPARAM(rc
.right
, rc
.bottom
));
785 s_isInOnSize
= false;
789 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
791 int width
= rc
.right
- rc
.left
,
792 height
= rc
.bottom
- rc
.top
;
793 size_t nCount
= m_pages
.Count();
794 for ( size_t nPage
= 0; nPage
< nCount
; nPage
++ ) {
795 wxNotebookPage
*pPage
= m_pages
[nPage
];
796 pPage
->SetSize(rc
.left
, rc
.top
, width
, height
);
800 // unless we had already repainted everything, we now need to refresh
801 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
803 // invalidate areas not covered by pages
804 RefreshRect(wxRect(0, 0, widthNbook
, rc
.top
), false);
805 RefreshRect(wxRect(0, rc
.top
, rc
.left
, height
), false);
806 RefreshRect(wxRect(0, rc
.bottom
, widthNbook
, heightNbook
- rc
.bottom
),
808 RefreshRect(wxRect(rc
.right
, rc
.top
, widthNbook
- rc
.bottom
, height
),
815 void wxNotebook::OnSelChange(wxNotebookEvent
& event
)
817 // is it our tab control?
818 if ( event
.GetEventObject() == this )
820 int sel
= event
.GetOldSelection();
822 m_pages
[sel
]->Show(false);
824 sel
= event
.GetSelection();
827 wxNotebookPage
*pPage
= m_pages
[sel
];
831 // If the newly focused window is not a child of the new page,
832 // SetFocus was not successful and the notebook itself should be
834 wxWindow
*currentFocus
= FindFocus();
835 wxWindow
*startFocus
= currentFocus
;
836 while ( currentFocus
&& currentFocus
!= pPage
&& currentFocus
!= this )
837 currentFocus
= currentFocus
->GetParent();
839 if ( startFocus
== pPage
|| currentFocus
!= pPage
)
843 else // no pages in the notebook, give the focus to itself
851 // we want to give others a chance to process this message as well
855 bool wxNotebook::MSWTranslateMessage(WXMSG
*wxmsg
)
857 const MSG
* const msg
= (MSG
*)wxmsg
;
859 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
860 // TAB will be passed to the currently selected page, CTRL+TAB and
861 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
862 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
864 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_TAB
&&
865 msg
->hwnd
== m_hwnd
&&
866 (wxIsCtrlDown() || !wxIsShiftDown()) )
868 return MSWProcessMessage(wxmsg
);
874 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
)
876 if ( event
.IsWindowChange() ) {
878 AdvanceSelection(event
.GetDirection());
881 // we get this event in 3 cases
883 // a) one of our pages might have generated it because the user TABbed
884 // out from it in which case we should propagate the event upwards and
885 // our parent will take care of setting the focus to prev/next sibling
889 // b) the parent panel wants to give the focus to us so that we
890 // forward it to our selected page. We can't deal with this in
891 // OnSetFocus() because we don't know which direction the focus came
892 // from in this case and so can't choose between setting the focus to
893 // first or last panel child
897 // c) we ourselves (see MSWTranslateMessage) generated the event
899 wxWindow
* const parent
= GetParent();
901 const bool isFromParent
= event
.GetEventObject() == parent
;
902 const bool isFromSelf
= event
.GetEventObject() == this;
904 if ( isFromParent
|| isFromSelf
)
906 // no, it doesn't come from child, case (b) or (c): forward to a
907 // page but only if direction is backwards (TAB) or from ourselves,
908 if ( m_nSelection
!= -1 &&
909 (!event
.GetDirection() || isFromSelf
) )
911 // so that the page knows that the event comes from it's parent
912 // and is being propagated downwards
913 event
.SetEventObject(this);
915 wxWindow
*page
= m_pages
[m_nSelection
];
916 if ( !page
->GetEventHandler()->ProcessEvent(event
) )
920 //else: page manages focus inside it itself
922 else // otherwise set the focus to the notebook itself
929 // it comes from our child, case (a), pass to the parent, but only
930 // if the direction is forwards. Otherwise set the focus to the
931 // notebook itself. The notebook is always the 'first' control of a
933 if ( !event
.GetDirection() )
939 event
.SetCurrentFocus(this);
940 parent
->GetEventHandler()->ProcessEvent(event
);
948 WXHANDLE
wxNotebook::QueryBgBitmap(wxWindow
*win
)
951 GetWindowRect(GetHwnd(), &rc
);
953 WindowHDC
hDC(GetHwnd());
954 MemoryHDC
hDCMem(hDC
);
955 CompatibleBitmap
hBmp(hDC
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
957 SelectInHDC
selectBmp(hDCMem
, hBmp
);
959 ::SendMessage(GetHwnd(), WM_PRINTCLIENT
,
961 PRF_ERASEBKGND
| PRF_CLIENT
| PRF_NONCLIENT
);
966 ::GetWindowRect(GetHwndOf(win
), &rc2
);
968 COLORREF c
= ::GetPixel(hDCMem
, rc2
.left
- rc
.left
, rc2
.top
- rc
.top
);
972 //else: we are asked to create the brush
974 return (WXHANDLE
)::CreatePatternBrush(hBmp
);
977 void wxNotebook::UpdateBgBrush()
979 if ( m_hbrBackground
)
980 ::DeleteObject((HBRUSH
)m_hbrBackground
);
982 if ( !m_hasBgCol
&& wxUxThemeEngine::GetIfActive() )
984 m_hbrBackground
= (WXHBRUSH
)QueryBgBitmap();
988 m_hbrBackground
= NULL
;
992 WXHBRUSH
wxNotebook::MSWGetBgBrushForChild(WXHDC hDC
, wxWindow
*win
)
994 if ( m_hbrBackground
)
996 // before drawing with the background brush, we need to position it
999 ::GetWindowRect(GetHwndOf(win
), &rc
);
1001 ::MapWindowPoints(NULL
, GetHwnd(), (POINT
*)&rc
, 1);
1003 if ( !::SetBrushOrgEx((HDC
)hDC
, -rc
.left
, -rc
.top
, NULL
) )
1005 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
1008 return m_hbrBackground
;
1011 return wxNotebookBase::MSWGetBgBrushForChild(hDC
, win
);
1014 wxColour
wxNotebook::MSWGetBgColourForChild(wxWindow
*win
)
1017 return GetBackgroundColour();
1019 // Experimental: don't do this since we're doing it in wxPanel
1020 #if 0 // defined(__POCKETPC__) || defined(__SMARTPHONE__)
1021 // For some reason, the pages will be grey by default.
1022 // Normally they should be white on these platforms.
1023 // (However the static control backgrounds are painted
1024 // in the correct colour, just not the rest of it.)
1025 // So let's give WinCE a hint.
1026 else if (!win
->m_hasBgCol
)
1030 if ( !wxUxThemeEngine::GetIfActive() )
1031 return wxNullColour
;
1033 COLORREF c
= (COLORREF
)QueryBgBitmap(win
);
1035 return c
== CLR_INVALID
? wxNullColour
: wxRGBToColour(c
);
1039 wxNotebook::MSWPrintChild(wxWindow
*win
,
1041 WXLPARAM
WXUNUSED(lParam
))
1043 // Don't paint the theme for the child if we have a solid
1045 if (m_hasBgCol
|| HasFlag(wxNB_NOPAGETHEME
) || (wxSystemOptions::HasOption(wxT("msw.notebook.themed-background")) &&
1046 wxSystemOptions::GetOptionInt(wxT("msw.notebook.themed-background")) == 0))
1050 ::GetClientRect(GetHwnd(), &rc
);
1051 TabCtrl_AdjustRect(GetHwnd(), true, &rc
);
1052 ::MapWindowPoints(GetHwnd(), GetHwndOf(win
), (POINT
*)&rc
, 2);
1054 wxUxThemeHandle
theme(win
, L
"TAB");
1057 wxUxThemeEngine::Get()->DrawThemeBackground
1071 #endif // wxUSE_UXTHEME
1073 // Windows only: attempts to get colour for UX theme page background
1074 wxColour
wxNotebook::GetThemeBackgroundColour() const
1077 if (wxUxThemeEngine::Get())
1079 wxUxThemeHandle
hTheme((wxNotebook
*) this, L
"TAB");
1082 // This is total guesswork.
1083 // See PlatformSDK\Include\Tmschema.h for values
1084 COLORREF themeColor
;
1085 wxUxThemeEngine::Get()->GetThemeColor(
1089 3821 /* FILLCOLORHINT */,
1093 [DS] Workaround for WindowBlinds:
1094 Some themes return a near black theme color using FILLCOLORHINT,
1095 this makes notebook pages have an ugly black background and makes
1096 text (usually black) unreadable. Retry again with FILLCOLOR.
1098 This workaround potentially breaks appearance of some themes,
1099 but in practice it already fixes some themes.
1101 if (themeColor
== 1)
1103 wxUxThemeEngine::Get()->GetThemeColor(
1107 3802 /* FILLCOLOR */,
1111 wxColour
colour(GetRValue(themeColor
), GetGValue(themeColor
), GetBValue(themeColor
));
1115 #endif // wxUSE_UXTHEME
1117 return GetBackgroundColour();
1120 // ----------------------------------------------------------------------------
1121 // wxNotebook base class virtuals
1122 // ----------------------------------------------------------------------------
1124 #if wxUSE_CONSTRAINTS
1126 // override these 2 functions to do nothing: everything is done in OnSize
1128 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
))
1130 // don't set the sizes of the pages - their correct size is not yet known
1131 wxControl::SetConstraintSizes(false);
1134 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
))
1139 #endif // wxUSE_CONSTRAINTS
1141 // ----------------------------------------------------------------------------
1142 // wxNotebook Windows message handlers
1143 // ----------------------------------------------------------------------------
1145 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
,
1146 WXWORD pos
, WXHWND control
)
1148 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1153 return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
);
1156 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
)
1158 wxNotebookEvent
event(wxEVT_NULL
, m_windowId
);
1160 NMHDR
* hdr
= (NMHDR
*)lParam
;
1161 switch ( hdr
->code
) {
1163 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
1166 case TCN_SELCHANGING
:
1167 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
);
1171 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1174 event
.SetSelection(TabCtrl_GetCurSel(m_hwnd
));
1175 event
.SetOldSelection(m_nSelection
);
1176 event
.SetEventObject(this);
1177 event
.SetInt(idCtrl
);
1179 bool processed
= GetEventHandler()->ProcessEvent(event
);
1180 *result
= !event
.IsAllowed();
1184 #endif // wxUSE_NOTEBOOK