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 // apparently DrawThemeBackground() modifies the rect passed to it and if we
188 // don't call this function there are some drawing artifacts which are only
189 // visible with some non default themes; so modify the rect here so that it
190 // still paints the correct area
191 static void AdjustRectForThemeBg(RECT
& rc
)
193 // magic numbers needed to compensate for DrawThemeBackground()
200 // ============================================================================
202 // ============================================================================
204 // ----------------------------------------------------------------------------
205 // wxNotebook construction
206 // ----------------------------------------------------------------------------
208 const wxNotebookPageInfoList
& wxNotebook::GetPageInfos() const
210 wxNotebookPageInfoList
* list
= const_cast< wxNotebookPageInfoList
* >( &m_pageInfos
) ;
211 WX_CLEAR_LIST( wxNotebookPageInfoList
, *list
) ;
212 for( size_t i
= 0 ; i
< GetPageCount() ; ++i
)
214 wxNotebookPageInfo
*info
= new wxNotebookPageInfo() ;
215 info
->Create( const_cast<wxNotebook
*>(this)->GetPage(i
) , GetPageText(i
) , GetSelection() == int(i
) , GetPageImage(i
) ) ;
216 list
->Append( info
) ;
221 // common part of all ctors
222 void wxNotebook::Init()
228 m_hbrBackground
= NULL
;
229 #endif // wxUSE_UXTHEME
232 // default for dynamic class
233 wxNotebook::wxNotebook()
238 // the same arguments as for wxControl
239 wxNotebook::wxNotebook(wxWindow
*parent
,
244 const wxString
& name
)
248 Create(parent
, id
, pos
, size
, style
, name
);
252 bool wxNotebook::Create(wxWindow
*parent
,
257 const wxString
& name
)
259 // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the
260 // control is simply not rendered correctly), so disable them in this case
261 const int verComCtl32
= wxApp::GetComCtl32Version();
262 if ( verComCtl32
== 600 )
264 // check if we use themes at all -- if we don't, we're still ok
266 if ( wxUxThemeEngine::GetIfActive() )
269 style
&= ~(wxNB_BOTTOM
| wxNB_LEFT
| wxNB_RIGHT
);
273 LPCTSTR className
= WC_TABCONTROL
;
275 // SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it
276 // causes horrible flicker when resizing notebook, so get rid of it by
277 // using a class without these styles (but otherwise identical to it)
278 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
280 static ClassRegistrar s_clsNotebook
;
281 if ( !s_clsNotebook
.IsInitialized() )
283 // get a copy of standard class and modify it
286 if ( ::GetClassInfo(::GetModuleHandle(NULL
), WC_TABCONTROL
, &wc
) )
288 wc
.lpszClassName
= wxT("_wx_SysTabCtl32");
289 wc
.style
&= ~(CS_HREDRAW
| CS_VREDRAW
);
291 s_clsNotebook
.Register(wc
);
295 wxLogLastError(_T("GetClassInfoEx(SysTabCtl32)"));
299 // use our custom class if available but fall back to the standard
300 // notebook if we failed to register it
301 if ( s_clsNotebook
.IsRegistered() )
303 // it's ok to use c_str() here as the static s_clsNotebook object
304 // has sufficiently long lifetime
305 className
= s_clsNotebook
.GetName().c_str();
309 if ( !CreateControl(parent
, id
, pos
, size
, style
| wxTAB_TRAVERSAL
,
310 wxDefaultValidator
, name
) )
313 if ( !MSWCreateControl(className
, wxEmptyString
, pos
, size
) )
317 if ( HasFlag(wxNB_NOPAGETHEME
) ||
318 wxSystemOptions::IsFalse(wxT("msw.notebook.themed-background")) )
320 SetBackgroundColour(GetThemeBackgroundColour());
322 #endif // wxUSE_UXTHEME
324 // Undocumented hack to get flat notebook style
325 // In fact, we should probably only do this in some
326 // curcumstances, i.e. if we know we will have a border
327 // at the bottom (the tab control doesn't draw it itself)
328 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
329 if (HasFlag(wxNB_FLAT
))
331 SendMessage(m_hwnd
, CCM_SETVERSION
, COMCTL32_VERSION
, 0);
333 SetBackgroundColour(*wxWHITE
);
339 WXDWORD
wxNotebook::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
341 WXDWORD tabStyle
= wxControl::MSWGetStyle(style
, exstyle
);
343 tabStyle
|= WS_TABSTOP
| TCS_TABS
;
345 if ( style
& wxNB_MULTILINE
)
346 tabStyle
|= TCS_MULTILINE
;
347 if ( style
& wxNB_FIXEDWIDTH
)
348 tabStyle
|= TCS_FIXEDWIDTH
;
350 if ( style
& wxNB_BOTTOM
)
351 tabStyle
|= TCS_RIGHT
;
352 else if ( style
& wxNB_LEFT
)
353 tabStyle
|= TCS_VERTICAL
;
354 else if ( style
& wxNB_RIGHT
)
355 tabStyle
|= TCS_VERTICAL
| TCS_RIGHT
;
360 // note that we never want to have the default WS_EX_CLIENTEDGE style
361 // as it looks too ugly for the notebooks
368 wxNotebook::~wxNotebook()
371 if ( m_hbrBackground
)
372 ::DeleteObject((HBRUSH
)m_hbrBackground
);
373 #endif // wxUSE_UXTHEME
376 // ----------------------------------------------------------------------------
377 // wxNotebook accessors
378 // ----------------------------------------------------------------------------
380 size_t wxNotebook::GetPageCount() const
383 wxASSERT( (int)m_pages
.Count() == TabCtrl_GetItemCount(m_hwnd
) );
385 return m_pages
.Count();
388 int wxNotebook::GetRowCount() const
390 return TabCtrl_GetRowCount(m_hwnd
);
393 int wxNotebook::SetSelection(size_t nPage
)
395 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
397 if ( int(nPage
) != m_nSelection
)
399 wxNotebookEvent
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, m_windowId
);
400 event
.SetSelection(nPage
);
401 event
.SetOldSelection(m_nSelection
);
402 event
.SetEventObject(this);
403 if ( !GetEventHandler()->ProcessEvent(event
) || event
.IsAllowed() )
405 // program allows the page change
406 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
407 (void)GetEventHandler()->ProcessEvent(event
);
409 TabCtrl_SetCurSel(m_hwnd
, nPage
);
416 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
)
418 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
421 tcItem
.mask
= TCIF_TEXT
;
422 tcItem
.pszText
= (wxChar
*)strText
.c_str();
424 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
427 wxString
wxNotebook::GetPageText(size_t nPage
) const
429 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") );
433 tcItem
.mask
= TCIF_TEXT
;
434 tcItem
.pszText
= buf
;
435 tcItem
.cchTextMax
= WXSIZEOF(buf
);
438 if ( TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) )
439 str
= tcItem
.pszText
;
444 int wxNotebook::GetPageImage(size_t nPage
) const
446 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
449 tcItem
.mask
= TCIF_IMAGE
;
451 return TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) ? tcItem
.iImage
: -1;
454 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
)
456 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
459 tcItem
.mask
= TCIF_IMAGE
;
460 tcItem
.iImage
= nImage
;
462 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
465 void wxNotebook::SetImageList(wxImageList
* imageList
)
467 wxNotebookBase::SetImageList(imageList
);
471 TabCtrl_SetImageList(m_hwnd
, (HIMAGELIST
)imageList
->GetHIMAGELIST());
475 // ----------------------------------------------------------------------------
476 // wxNotebook size settings
477 // ----------------------------------------------------------------------------
479 void wxNotebook::SetPageSize(const wxSize
& size
)
481 // transform the page size into the notebook size
488 TabCtrl_AdjustRect(GetHwnd(), true, &rc
);
491 SetSize(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
494 void wxNotebook::SetPadding(const wxSize
& padding
)
496 TabCtrl_SetPadding(GetHwnd(), padding
.x
, padding
.y
);
499 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
501 void wxNotebook::SetTabSize(const wxSize
& sz
)
503 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE
, 0, MAKELPARAM(sz
.x
, sz
.y
));
506 wxSize
wxNotebook::CalcSizeFromPage(const wxSize
& sizePage
) const
508 wxSize sizeTotal
= sizePage
;
510 // We need to make getting tab size part of the wxWidgets API.
512 if (GetPageCount() > 0)
515 TabCtrl_GetItemRect((HWND
) GetHWND(), 0, & rect
);
516 tabSize
.x
= rect
.right
- rect
.left
;
517 tabSize
.y
= rect
.bottom
- rect
.top
;
519 if ( HasFlag(wxNB_LEFT
) || HasFlag(wxNB_RIGHT
) )
521 sizeTotal
.x
+= tabSize
.x
+ 7;
527 sizeTotal
.y
+= tabSize
.y
+ 7;
533 void wxNotebook::AdjustPageSize(wxNotebookPage
*page
)
535 wxCHECK_RET( page
, _T("NULL page in wxNotebook::AdjustPageSize") );
541 // get the page size from the notebook size
542 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
544 // This check is to work around a bug in TabCtrl_AdjustRect which will
545 // cause a crash on win2k, or on XP with themes disabled, if the
546 // wxNB_MULTILINE style is used and the rectangle is very small, (such as
547 // when the notebook is first created.) The value of 20 is just
548 // arbitrarily chosen, if there is a better way to determine this value
549 // then please do so. --RD
550 if (rc
.right
> 20 && rc
.bottom
> 20)
552 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
553 page
->SetSize(rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
557 // ----------------------------------------------------------------------------
558 // wxNotebook operations
559 // ----------------------------------------------------------------------------
561 // remove one page from the notebook, without deleting
562 wxNotebookPage
*wxNotebook::DoRemovePage(size_t nPage
)
564 wxNotebookPage
*pageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
568 TabCtrl_DeleteItem(m_hwnd
, nPage
);
570 if ( m_pages
.IsEmpty() )
572 // no selection any more, the notebook becamse empty
575 else // notebook still not empty
577 int selNew
= TabCtrl_GetCurSel(m_hwnd
);
580 // No selection change, just refresh the current selection.
581 // Because it could be that the slection index changed
582 // we need to update it.
583 // Note: this does not mean the selection it self changed.
584 m_nSelection
= selNew
;
585 m_pages
[m_nSelection
]->Refresh();
587 else if (int(nPage
) == m_nSelection
)
589 // The selection was deleted.
591 // Determine new selection.
592 if (m_nSelection
== int(GetPageCount()))
593 selNew
= m_nSelection
- 1;
595 selNew
= m_nSelection
;
597 // m_nSelection must be always valid so reset it before calling
600 SetSelection(selNew
);
604 wxFAIL
; // Windows did not behave ok.
612 bool wxNotebook::DeleteAllPages()
614 size_t nPageCount
= GetPageCount();
616 for ( nPage
= 0; nPage
< nPageCount
; nPage
++ )
617 delete m_pages
[nPage
];
621 TabCtrl_DeleteAllItems(m_hwnd
);
625 InvalidateBestSize();
629 // same as AddPage() but does it at given position
630 bool wxNotebook::InsertPage(size_t nPage
,
631 wxNotebookPage
*pPage
,
632 const wxString
& strText
,
636 wxCHECK_MSG( pPage
!= NULL
, false, _T("NULL page in wxNotebook::InsertPage") );
637 wxCHECK_MSG( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false,
638 _T("invalid index in wxNotebook::InsertPage") );
640 wxASSERT_MSG( pPage
->GetParent() == this,
641 _T("notebook pages must have notebook as parent") );
643 // add a new tab to the control
644 // ----------------------------
646 // init all fields to 0
648 wxZeroMemory(tcItem
);
650 // set the image, if any
653 tcItem
.mask
|= TCIF_IMAGE
;
654 tcItem
.iImage
= imageId
;
658 if ( !strText
.empty() )
660 tcItem
.mask
|= TCIF_TEXT
;
661 tcItem
.pszText
= (wxChar
*)strText
.c_str(); // const_cast
664 // hide the page: unless it is selected, it shouldn't be shown (and if it
665 // is selected it will be shown later)
666 HWND hwnd
= GetWinHwnd(pPage
);
667 SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~WS_VISIBLE
);
669 // this updates internal flag too -- otherwise it would get out of sync
670 // with the real state
674 // fit the notebook page to the tab control's display area: this should be
675 // done before adding it to the notebook or TabCtrl_InsertItem() will
676 // change the notebooks size itself!
677 AdjustPageSize(pPage
);
679 // finally do insert it
680 if ( TabCtrl_InsertItem(m_hwnd
, nPage
, &tcItem
) == -1 )
682 wxLogError(wxT("Can't create the notebook page '%s'."), strText
.c_str());
687 // succeeded: save the pointer to the page
688 m_pages
.Insert(pPage
, nPage
);
690 // we may need to adjust the size again if the notebook size changed:
691 // normally this only happens for the first page we add (the tabs which
692 // hadn't been there before are now shown) but for a multiline notebook it
693 // can happen for any page at all as a new row could have been started
694 if ( m_pages
.GetCount() == 1 || HasFlag(wxNB_MULTILINE
) )
696 AdjustPageSize(pPage
);
699 // now deal with the selection
700 // ---------------------------
702 // if the inserted page is before the selected one, we must update the
703 // index of the selected page
704 if ( int(nPage
) <= m_nSelection
)
706 // one extra page added
710 // some page should be selected: either this one or the first one if there
711 // is still no selection
715 else if ( m_nSelection
== -1 )
719 SetSelection(selNew
);
721 InvalidateBestSize();
726 int wxNotebook::HitTest(const wxPoint
& pt
, long *flags
) const
728 TC_HITTESTINFO hitTestInfo
;
729 hitTestInfo
.pt
.x
= pt
.x
;
730 hitTestInfo
.pt
.y
= pt
.y
;
731 int item
= TabCtrl_HitTest(GetHwnd(), &hitTestInfo
);
737 if ((hitTestInfo
.flags
& TCHT_NOWHERE
) == TCHT_NOWHERE
)
738 *flags
|= wxNB_HITTEST_NOWHERE
;
739 if ((hitTestInfo
.flags
& TCHT_ONITEM
) == TCHT_ONITEM
)
740 *flags
|= wxNB_HITTEST_ONITEM
;
741 if ((hitTestInfo
.flags
& TCHT_ONITEMICON
) == TCHT_ONITEMICON
)
742 *flags
|= wxNB_HITTEST_ONICON
;
743 if ((hitTestInfo
.flags
& TCHT_ONITEMLABEL
) == TCHT_ONITEMLABEL
)
744 *flags
|= wxNB_HITTEST_ONLABEL
;
751 // ----------------------------------------------------------------------------
752 // wxNotebook callbacks
753 // ----------------------------------------------------------------------------
755 void wxNotebook::OnSize(wxSizeEvent
& event
)
758 // background bitmap size has changed, update the brush using it too
760 #endif // wxUSE_UXTHEME
762 if ( GetPageCount() == 0 )
764 // Prevents droppings on resize, but does cause some flicker
765 // when there are no pages.
771 // fit all the notebook pages to the tab control's display area
774 rc
.left
= rc
.top
= 0;
775 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
777 // save the total size, we'll use it below
778 int widthNbook
= rc
.right
- rc
.left
,
779 heightNbook
= rc
.bottom
- rc
.top
;
781 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
782 // returns completely false values for multiline tab controls after the tabs
783 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
785 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
787 // and the only work around I could find was this ugly hack... without it
788 // simply toggling the "multiline" checkbox in the notebook sample resulted
789 // in a noticeable page displacement
790 if ( HasFlag(wxNB_MULTILINE
) )
792 // avoid an infinite recursion: we get another notification too!
793 static bool s_isInOnSize
= false;
798 SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
,
799 MAKELPARAM(rc
.right
, rc
.bottom
));
800 s_isInOnSize
= false;
804 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
806 int width
= rc
.right
- rc
.left
,
807 height
= rc
.bottom
- rc
.top
;
808 size_t nCount
= m_pages
.Count();
809 for ( size_t nPage
= 0; nPage
< nCount
; nPage
++ ) {
810 wxNotebookPage
*pPage
= m_pages
[nPage
];
811 pPage
->SetSize(rc
.left
, rc
.top
, width
, height
);
815 // unless we had already repainted everything, we now need to refresh
816 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
818 // invalidate areas not covered by pages
819 RefreshRect(wxRect(0, 0, widthNbook
, rc
.top
), false);
820 RefreshRect(wxRect(0, rc
.top
, rc
.left
, height
), false);
821 RefreshRect(wxRect(0, rc
.bottom
, widthNbook
, heightNbook
- rc
.bottom
),
823 RefreshRect(wxRect(rc
.right
, rc
.top
, widthNbook
- rc
.bottom
, height
),
830 void wxNotebook::OnSelChange(wxNotebookEvent
& event
)
832 // is it our tab control?
833 if ( event
.GetEventObject() == this )
835 int sel
= event
.GetOldSelection();
837 m_pages
[sel
]->Show(false);
839 sel
= event
.GetSelection();
842 wxNotebookPage
*pPage
= m_pages
[sel
];
846 // If the newly focused window is not a child of the new page,
847 // SetFocus was not successful and the notebook itself should be
849 wxWindow
*currentFocus
= FindFocus();
850 wxWindow
*startFocus
= currentFocus
;
851 while ( currentFocus
&& currentFocus
!= pPage
&& currentFocus
!= this )
852 currentFocus
= currentFocus
->GetParent();
854 if ( startFocus
== pPage
|| currentFocus
!= pPage
)
858 else // no pages in the notebook, give the focus to itself
866 // we want to give others a chance to process this message as well
870 bool wxNotebook::MSWTranslateMessage(WXMSG
*wxmsg
)
872 const MSG
* const msg
= (MSG
*)wxmsg
;
874 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
875 // TAB will be passed to the currently selected page, CTRL+TAB and
876 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
877 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
879 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_TAB
&&
880 msg
->hwnd
== m_hwnd
&&
881 (wxIsCtrlDown() || !wxIsShiftDown()) )
883 return MSWProcessMessage(wxmsg
);
889 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
)
891 if ( event
.IsWindowChange() ) {
893 AdvanceSelection(event
.GetDirection());
896 // we get this event in 3 cases
898 // a) one of our pages might have generated it because the user TABbed
899 // out from it in which case we should propagate the event upwards and
900 // our parent will take care of setting the focus to prev/next sibling
904 // b) the parent panel wants to give the focus to us so that we
905 // forward it to our selected page. We can't deal with this in
906 // OnSetFocus() because we don't know which direction the focus came
907 // from in this case and so can't choose between setting the focus to
908 // first or last panel child
912 // c) we ourselves (see MSWTranslateMessage) generated the event
914 wxWindow
* const parent
= GetParent();
916 const bool isFromParent
= event
.GetEventObject() == parent
;
917 const bool isFromSelf
= event
.GetEventObject() == this;
919 if ( isFromParent
|| isFromSelf
)
921 // no, it doesn't come from child, case (b) or (c): forward to a
922 // page but only if direction is backwards (TAB) or from ourselves,
923 if ( m_nSelection
!= -1 &&
924 (!event
.GetDirection() || isFromSelf
) )
926 // so that the page knows that the event comes from it's parent
927 // and is being propagated downwards
928 event
.SetEventObject(this);
930 wxWindow
*page
= m_pages
[m_nSelection
];
931 if ( !page
->GetEventHandler()->ProcessEvent(event
) )
935 //else: page manages focus inside it itself
937 else // otherwise set the focus to the notebook itself
944 // it comes from our child, case (a), pass to the parent, but only
945 // if the direction is forwards. Otherwise set the focus to the
946 // notebook itself. The notebook is always the 'first' control of a
948 if ( !event
.GetDirection() )
954 event
.SetCurrentFocus(this);
955 parent
->GetEventHandler()->ProcessEvent(event
);
963 WXHBRUSH
wxNotebook::QueryBgBitmap()
966 ::GetClientRect(GetHwnd(), &rc
);
969 TabCtrl_AdjustRect(GetHwnd(), false, &rc
);
971 WindowHDC
hDC(GetHwnd());
972 MemoryHDC
hDCMem(hDC
);
973 CompatibleBitmap
hBmp(hDC
, rc
.right
, rc
.bottom
);
975 SelectInHDC
selectBmp(hDCMem
, hBmp
);
977 wxUxThemeHandle
theme(this, L
"TAB");
980 AdjustRectForThemeBg(rc
);
982 wxUxThemeEngine::Get()->DrawThemeBackground
993 return (WXHBRUSH
)::CreatePatternBrush(hBmp
);
996 void wxNotebook::UpdateBgBrush()
998 if ( m_hbrBackground
)
999 ::DeleteObject((HBRUSH
)m_hbrBackground
);
1001 if ( !m_hasBgCol
&& wxUxThemeEngine::GetIfActive() )
1003 m_hbrBackground
= QueryBgBitmap();
1007 m_hbrBackground
= NULL
;
1011 WXHBRUSH
wxNotebook::MSWGetBgBrushForChild(WXHDC hDC
, wxWindow
*win
)
1013 if ( m_hbrBackground
)
1015 // before drawing with the background brush, we need to position it
1018 ::GetWindowRect(GetHwndOf(win
), &rc
);
1020 ::MapWindowPoints(NULL
, GetHwnd(), (POINT
*)&rc
, 1);
1022 if ( !::SetBrushOrgEx((HDC
)hDC
, -rc
.left
, -rc
.top
, NULL
) )
1024 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
1027 return m_hbrBackground
;
1030 return wxNotebookBase::MSWGetBgBrushForChild(hDC
, win
);
1033 wxColour
wxNotebook::MSWGetBgColourForChild(wxWindow
*WXUNUSED(win
))
1036 return GetBackgroundColour();
1038 // Experimental: don't do this since we're doing it in wxPanel
1039 #if 0 // defined(__POCKETPC__) || defined(__SMARTPHONE__)
1040 // For some reason, the pages will be grey by default.
1041 // Normally they should be white on these platforms.
1042 // (However the static control backgrounds are painted
1043 // in the correct colour, just not the rest of it.)
1044 // So let's give WinCE a hint.
1045 else if (!win
->m_hasBgCol
)
1049 if ( !wxUxThemeEngine::GetIfActive() )
1050 return wxNullColour
;
1052 return GetThemeBackgroundColour();
1056 wxNotebook::MSWPrintChild(wxWindow
*win
,
1058 WXLPARAM
WXUNUSED(lParam
))
1060 // Don't paint the theme for the child if we have a solid background
1066 ::GetClientRect(GetHwnd(), &rc
);
1069 TabCtrl_AdjustRect(GetHwnd(), false, &rc
);
1071 wxUxThemeHandle
theme(win
, L
"TAB");
1074 // map from this client to win client coords
1075 ::MapWindowPoints(GetHwnd(), GetHwndOf(win
), (POINT
*)&rc
, 2);
1077 AdjustRectForThemeBg(rc
);
1078 wxUxThemeEngine::Get()->DrawThemeBackground
1092 #endif // wxUSE_UXTHEME
1094 // Windows only: attempts to get colour for UX theme page background
1095 wxColour
wxNotebook::GetThemeBackgroundColour() const
1098 if (wxUxThemeEngine::Get())
1100 wxUxThemeHandle
hTheme((wxNotebook
*) this, L
"TAB");
1103 // This is total guesswork.
1104 // See PlatformSDK\Include\Tmschema.h for values
1105 COLORREF themeColor
;
1106 wxUxThemeEngine::Get()->GetThemeColor(
1110 3821 /* FILLCOLORHINT */,
1114 [DS] Workaround for WindowBlinds:
1115 Some themes return a near black theme color using FILLCOLORHINT,
1116 this makes notebook pages have an ugly black background and makes
1117 text (usually black) unreadable. Retry again with FILLCOLOR.
1119 This workaround potentially breaks appearance of some themes,
1120 but in practice it already fixes some themes.
1122 if (themeColor
== 1)
1124 wxUxThemeEngine::Get()->GetThemeColor(
1128 3802 /* FILLCOLOR */,
1132 return wxRGBToColour(themeColor
);
1135 #endif // wxUSE_UXTHEME
1137 return GetBackgroundColour();
1140 // ----------------------------------------------------------------------------
1141 // wxNotebook base class virtuals
1142 // ----------------------------------------------------------------------------
1144 #if wxUSE_CONSTRAINTS
1146 // override these 2 functions to do nothing: everything is done in OnSize
1148 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
))
1150 // don't set the sizes of the pages - their correct size is not yet known
1151 wxControl::SetConstraintSizes(false);
1154 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
))
1159 #endif // wxUSE_CONSTRAINTS
1161 // ----------------------------------------------------------------------------
1162 // wxNotebook Windows message handlers
1163 // ----------------------------------------------------------------------------
1165 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
,
1166 WXWORD pos
, WXHWND control
)
1168 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1173 return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
);
1176 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
)
1178 wxNotebookEvent
event(wxEVT_NULL
, m_windowId
);
1180 NMHDR
* hdr
= (NMHDR
*)lParam
;
1181 switch ( hdr
->code
) {
1183 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
1186 case TCN_SELCHANGING
:
1187 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
);
1191 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1194 event
.SetSelection(TabCtrl_GetCurSel(m_hwnd
));
1195 event
.SetOldSelection(m_nSelection
);
1196 event
.SetEventObject(this);
1197 event
.SetInt(idCtrl
);
1199 bool processed
= GetEventHandler()->ProcessEvent(event
);
1200 *result
= !event
.IsAllowed();
1204 #endif // wxUSE_NOTEBOOK