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 // ----------------------------------------------------------------------------
188 // apparently DrawThemeBackground() modifies the rect passed to it and if we
189 // don't call this function there are some drawing artifacts which are only
190 // visible with some non default themes; so modify the rect here so that it
191 // still paints the correct area
192 static void AdjustRectForThemeBg(RECT
& rc
)
194 // magic numbers needed to compensate for DrawThemeBackground()
202 // ============================================================================
204 // ============================================================================
206 // ----------------------------------------------------------------------------
207 // wxNotebook construction
208 // ----------------------------------------------------------------------------
210 const wxNotebookPageInfoList
& wxNotebook::GetPageInfos() const
212 wxNotebookPageInfoList
* list
= const_cast< wxNotebookPageInfoList
* >( &m_pageInfos
) ;
213 WX_CLEAR_LIST( wxNotebookPageInfoList
, *list
) ;
214 for( size_t i
= 0 ; i
< GetPageCount() ; ++i
)
216 wxNotebookPageInfo
*info
= new wxNotebookPageInfo() ;
217 info
->Create( const_cast<wxNotebook
*>(this)->GetPage(i
) , GetPageText(i
) , GetSelection() == int(i
) , GetPageImage(i
) ) ;
218 list
->Append( info
) ;
223 // common part of all ctors
224 void wxNotebook::Init()
230 m_hbrBackground
= NULL
;
231 #endif // wxUSE_UXTHEME
234 // default for dynamic class
235 wxNotebook::wxNotebook()
240 // the same arguments as for wxControl
241 wxNotebook::wxNotebook(wxWindow
*parent
,
246 const wxString
& name
)
250 Create(parent
, id
, pos
, size
, style
, name
);
254 bool wxNotebook::Create(wxWindow
*parent
,
259 const wxString
& name
)
262 // Not sure why, but without this style, there is no border
263 // around the notebook tabs.
264 if (style
& wxNB_FLAT
)
265 style
|= wxBORDER_SUNKEN
;
268 // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the
269 // control is simply not rendered correctly), so disable them in this case
270 const int verComCtl32
= wxApp::GetComCtl32Version();
271 if ( verComCtl32
== 600 )
273 // check if we use themes at all -- if we don't, we're still ok
275 if ( wxUxThemeEngine::GetIfActive() )
278 style
&= ~(wxNB_BOTTOM
| wxNB_LEFT
| wxNB_RIGHT
);
282 LPCTSTR className
= WC_TABCONTROL
;
284 // SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it
285 // causes horrible flicker when resizing notebook, so get rid of it by
286 // using a class without these styles (but otherwise identical to it)
287 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
289 static ClassRegistrar s_clsNotebook
;
290 if ( !s_clsNotebook
.IsInitialized() )
292 // get a copy of standard class and modify it
295 if ( ::GetClassInfo(::GetModuleHandle(NULL
), WC_TABCONTROL
, &wc
) )
297 wc
.lpszClassName
= wxT("_wx_SysTabCtl32");
298 wc
.style
&= ~(CS_HREDRAW
| CS_VREDRAW
);
300 s_clsNotebook
.Register(wc
);
304 wxLogLastError(_T("GetClassInfoEx(SysTabCtl32)"));
308 // use our custom class if available but fall back to the standard
309 // notebook if we failed to register it
310 if ( s_clsNotebook
.IsRegistered() )
312 // it's ok to use c_str() here as the static s_clsNotebook object
313 // has sufficiently long lifetime
314 className
= s_clsNotebook
.GetName().c_str();
318 if ( !CreateControl(parent
, id
, pos
, size
, style
| wxTAB_TRAVERSAL
,
319 wxDefaultValidator
, name
) )
322 if ( !MSWCreateControl(className
, wxEmptyString
, pos
, size
) )
326 if ( HasFlag(wxNB_NOPAGETHEME
) ||
327 wxSystemOptions::IsFalse(wxT("msw.notebook.themed-background")) )
329 SetBackgroundColour(GetThemeBackgroundColour());
331 #endif // wxUSE_UXTHEME
333 // Undocumented hack to get flat notebook style
334 // In fact, we should probably only do this in some
335 // curcumstances, i.e. if we know we will have a border
336 // at the bottom (the tab control doesn't draw it itself)
337 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
338 if (HasFlag(wxNB_FLAT
))
340 SendMessage(m_hwnd
, CCM_SETVERSION
, COMCTL32_VERSION
, 0);
342 SetBackgroundColour(*wxWHITE
);
348 WXDWORD
wxNotebook::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
350 WXDWORD tabStyle
= wxControl::MSWGetStyle(style
, exstyle
);
352 tabStyle
|= WS_TABSTOP
| TCS_TABS
;
354 if ( style
& wxNB_MULTILINE
)
355 tabStyle
|= TCS_MULTILINE
;
356 if ( style
& wxNB_FIXEDWIDTH
)
357 tabStyle
|= TCS_FIXEDWIDTH
;
359 if ( style
& wxNB_BOTTOM
)
360 tabStyle
|= TCS_RIGHT
;
361 else if ( style
& wxNB_LEFT
)
362 tabStyle
|= TCS_VERTICAL
;
363 else if ( style
& wxNB_RIGHT
)
364 tabStyle
|= TCS_VERTICAL
| TCS_RIGHT
;
369 // note that we never want to have the default WS_EX_CLIENTEDGE style
370 // as it looks too ugly for the notebooks
377 wxNotebook::~wxNotebook()
380 if ( m_hbrBackground
)
381 ::DeleteObject((HBRUSH
)m_hbrBackground
);
382 #endif // wxUSE_UXTHEME
385 // ----------------------------------------------------------------------------
386 // wxNotebook accessors
387 // ----------------------------------------------------------------------------
389 size_t wxNotebook::GetPageCount() const
392 wxASSERT( (int)m_pages
.Count() == TabCtrl_GetItemCount(m_hwnd
) );
394 return m_pages
.Count();
397 int wxNotebook::GetRowCount() const
399 return TabCtrl_GetRowCount(m_hwnd
);
402 int wxNotebook::SetSelection(size_t nPage
)
404 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
406 if ( int(nPage
) != m_nSelection
)
408 wxNotebookEvent
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, m_windowId
);
409 event
.SetSelection(nPage
);
410 event
.SetOldSelection(m_nSelection
);
411 event
.SetEventObject(this);
412 if ( !GetEventHandler()->ProcessEvent(event
) || event
.IsAllowed() )
414 // program allows the page change
415 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
416 (void)GetEventHandler()->ProcessEvent(event
);
418 TabCtrl_SetCurSel(m_hwnd
, nPage
);
425 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
)
427 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
430 tcItem
.mask
= TCIF_TEXT
;
431 tcItem
.pszText
= (wxChar
*)strText
.c_str();
433 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
436 wxString
wxNotebook::GetPageText(size_t nPage
) const
438 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") );
442 tcItem
.mask
= TCIF_TEXT
;
443 tcItem
.pszText
= buf
;
444 tcItem
.cchTextMax
= WXSIZEOF(buf
);
447 if ( TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) )
448 str
= tcItem
.pszText
;
453 int wxNotebook::GetPageImage(size_t nPage
) const
455 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
458 tcItem
.mask
= TCIF_IMAGE
;
460 return TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) ? tcItem
.iImage
: -1;
463 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
)
465 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
468 tcItem
.mask
= TCIF_IMAGE
;
469 tcItem
.iImage
= nImage
;
471 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
474 void wxNotebook::SetImageList(wxImageList
* imageList
)
476 wxNotebookBase::SetImageList(imageList
);
480 TabCtrl_SetImageList(m_hwnd
, (HIMAGELIST
)imageList
->GetHIMAGELIST());
484 // ----------------------------------------------------------------------------
485 // wxNotebook size settings
486 // ----------------------------------------------------------------------------
488 void wxNotebook::SetPageSize(const wxSize
& size
)
490 // transform the page size into the notebook size
497 TabCtrl_AdjustRect(GetHwnd(), true, &rc
);
500 SetSize(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
503 void wxNotebook::SetPadding(const wxSize
& padding
)
505 TabCtrl_SetPadding(GetHwnd(), padding
.x
, padding
.y
);
508 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
510 void wxNotebook::SetTabSize(const wxSize
& sz
)
512 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE
, 0, MAKELPARAM(sz
.x
, sz
.y
));
515 wxSize
wxNotebook::CalcSizeFromPage(const wxSize
& sizePage
) const
517 wxSize sizeTotal
= sizePage
;
519 // We need to make getting tab size part of the wxWidgets API.
521 if (GetPageCount() > 0)
524 TabCtrl_GetItemRect((HWND
) GetHWND(), 0, & rect
);
525 tabSize
.x
= rect
.right
- rect
.left
;
526 tabSize
.y
= rect
.bottom
- rect
.top
;
528 if ( HasFlag(wxNB_LEFT
) || HasFlag(wxNB_RIGHT
) )
530 sizeTotal
.x
+= tabSize
.x
+ 7;
536 sizeTotal
.y
+= tabSize
.y
+ 7;
542 void wxNotebook::AdjustPageSize(wxNotebookPage
*page
)
544 wxCHECK_RET( page
, _T("NULL page in wxNotebook::AdjustPageSize") );
550 // get the page size from the notebook size
551 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
553 // This check is to work around a bug in TabCtrl_AdjustRect which will
554 // cause a crash on win2k, or on XP with themes disabled, if the
555 // wxNB_MULTILINE style is used and the rectangle is very small, (such as
556 // when the notebook is first created.) The value of 20 is just
557 // arbitrarily chosen, if there is a better way to determine this value
558 // then please do so. --RD
559 if (rc
.right
> 20 && rc
.bottom
> 20)
561 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
562 page
->SetSize(rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
566 // ----------------------------------------------------------------------------
567 // wxNotebook operations
568 // ----------------------------------------------------------------------------
570 // remove one page from the notebook, without deleting
571 wxNotebookPage
*wxNotebook::DoRemovePage(size_t nPage
)
573 wxNotebookPage
*pageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
577 TabCtrl_DeleteItem(m_hwnd
, nPage
);
579 if ( m_pages
.IsEmpty() )
581 // no selection any more, the notebook becamse empty
584 else // notebook still not empty
586 int selNew
= TabCtrl_GetCurSel(m_hwnd
);
589 // No selection change, just refresh the current selection.
590 // Because it could be that the slection index changed
591 // we need to update it.
592 // Note: this does not mean the selection it self changed.
593 m_nSelection
= selNew
;
594 m_pages
[m_nSelection
]->Refresh();
596 else if (int(nPage
) == m_nSelection
)
598 // The selection was deleted.
600 // Determine new selection.
601 if (m_nSelection
== int(GetPageCount()))
602 selNew
= m_nSelection
- 1;
604 selNew
= m_nSelection
;
606 // m_nSelection must be always valid so reset it before calling
609 SetSelection(selNew
);
613 wxFAIL
; // Windows did not behave ok.
621 bool wxNotebook::DeleteAllPages()
623 size_t nPageCount
= GetPageCount();
625 for ( nPage
= 0; nPage
< nPageCount
; nPage
++ )
626 delete m_pages
[nPage
];
630 TabCtrl_DeleteAllItems(m_hwnd
);
634 InvalidateBestSize();
638 // same as AddPage() but does it at given position
639 bool wxNotebook::InsertPage(size_t nPage
,
640 wxNotebookPage
*pPage
,
641 const wxString
& strText
,
645 wxCHECK_MSG( pPage
!= NULL
, false, _T("NULL page in wxNotebook::InsertPage") );
646 wxCHECK_MSG( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false,
647 _T("invalid index in wxNotebook::InsertPage") );
649 wxASSERT_MSG( pPage
->GetParent() == this,
650 _T("notebook pages must have notebook as parent") );
652 // add a new tab to the control
653 // ----------------------------
655 // init all fields to 0
657 wxZeroMemory(tcItem
);
659 // set the image, if any
662 tcItem
.mask
|= TCIF_IMAGE
;
663 tcItem
.iImage
= imageId
;
667 if ( !strText
.empty() )
669 tcItem
.mask
|= TCIF_TEXT
;
670 tcItem
.pszText
= (wxChar
*)strText
.c_str(); // const_cast
673 // hide the page: unless it is selected, it shouldn't be shown (and if it
674 // is selected it will be shown later)
675 HWND hwnd
= GetWinHwnd(pPage
);
676 SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~WS_VISIBLE
);
678 // this updates internal flag too -- otherwise it would get out of sync
679 // with the real state
683 // fit the notebook page to the tab control's display area: this should be
684 // done before adding it to the notebook or TabCtrl_InsertItem() will
685 // change the notebooks size itself!
686 AdjustPageSize(pPage
);
688 // finally do insert it
689 if ( TabCtrl_InsertItem(m_hwnd
, nPage
, &tcItem
) == -1 )
691 wxLogError(wxT("Can't create the notebook page '%s'."), strText
.c_str());
696 // succeeded: save the pointer to the page
697 m_pages
.Insert(pPage
, nPage
);
699 // we may need to adjust the size again if the notebook size changed:
700 // normally this only happens for the first page we add (the tabs which
701 // hadn't been there before are now shown) but for a multiline notebook it
702 // can happen for any page at all as a new row could have been started
703 if ( m_pages
.GetCount() == 1 || HasFlag(wxNB_MULTILINE
) )
705 AdjustPageSize(pPage
);
708 // now deal with the selection
709 // ---------------------------
711 // if the inserted page is before the selected one, we must update the
712 // index of the selected page
713 if ( int(nPage
) <= m_nSelection
)
715 // one extra page added
719 // some page should be selected: either this one or the first one if there
720 // is still no selection
724 else if ( m_nSelection
== -1 )
728 SetSelection(selNew
);
730 InvalidateBestSize();
735 int wxNotebook::HitTest(const wxPoint
& pt
, long *flags
) const
737 TC_HITTESTINFO hitTestInfo
;
738 hitTestInfo
.pt
.x
= pt
.x
;
739 hitTestInfo
.pt
.y
= pt
.y
;
740 int item
= TabCtrl_HitTest(GetHwnd(), &hitTestInfo
);
746 if ((hitTestInfo
.flags
& TCHT_NOWHERE
) == TCHT_NOWHERE
)
747 *flags
|= wxNB_HITTEST_NOWHERE
;
748 if ((hitTestInfo
.flags
& TCHT_ONITEM
) == TCHT_ONITEM
)
749 *flags
|= wxNB_HITTEST_ONITEM
;
750 if ((hitTestInfo
.flags
& TCHT_ONITEMICON
) == TCHT_ONITEMICON
)
751 *flags
|= wxNB_HITTEST_ONICON
;
752 if ((hitTestInfo
.flags
& TCHT_ONITEMLABEL
) == TCHT_ONITEMLABEL
)
753 *flags
|= wxNB_HITTEST_ONLABEL
;
760 // ----------------------------------------------------------------------------
761 // wxNotebook callbacks
762 // ----------------------------------------------------------------------------
764 void wxNotebook::OnSize(wxSizeEvent
& event
)
767 // background bitmap size has changed, update the brush using it too
769 #endif // wxUSE_UXTHEME
771 if ( GetPageCount() == 0 )
773 // Prevents droppings on resize, but does cause some flicker
774 // when there are no pages.
780 // fit all the notebook pages to the tab control's display area
783 rc
.left
= rc
.top
= 0;
784 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
786 // save the total size, we'll use it below
787 int widthNbook
= rc
.right
- rc
.left
,
788 heightNbook
= rc
.bottom
- rc
.top
;
790 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
791 // returns completely false values for multiline tab controls after the tabs
792 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
794 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
796 // and the only work around I could find was this ugly hack... without it
797 // simply toggling the "multiline" checkbox in the notebook sample resulted
798 // in a noticeable page displacement
799 if ( HasFlag(wxNB_MULTILINE
) )
801 // avoid an infinite recursion: we get another notification too!
802 static bool s_isInOnSize
= false;
807 SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
,
808 MAKELPARAM(rc
.right
, rc
.bottom
));
809 s_isInOnSize
= false;
813 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
815 int width
= rc
.right
- rc
.left
,
816 height
= rc
.bottom
- rc
.top
;
817 size_t nCount
= m_pages
.Count();
818 for ( size_t nPage
= 0; nPage
< nCount
; nPage
++ ) {
819 wxNotebookPage
*pPage
= m_pages
[nPage
];
820 pPage
->SetSize(rc
.left
, rc
.top
, width
, height
);
824 // unless we had already repainted everything, we now need to refresh
825 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
827 // invalidate areas not covered by pages
828 RefreshRect(wxRect(0, 0, widthNbook
, rc
.top
), false);
829 RefreshRect(wxRect(0, rc
.top
, rc
.left
, height
), false);
830 RefreshRect(wxRect(0, rc
.bottom
, widthNbook
, heightNbook
- rc
.bottom
),
832 RefreshRect(wxRect(rc
.right
, rc
.top
, widthNbook
- rc
.bottom
, height
),
839 void wxNotebook::OnSelChange(wxNotebookEvent
& event
)
841 // is it our tab control?
842 if ( event
.GetEventObject() == this )
844 int sel
= event
.GetOldSelection();
846 m_pages
[sel
]->Show(false);
848 sel
= event
.GetSelection();
851 wxNotebookPage
*pPage
= m_pages
[sel
];
855 // If the newly focused window is not a child of the new page,
856 // SetFocus was not successful and the notebook itself should be
858 wxWindow
*currentFocus
= FindFocus();
859 wxWindow
*startFocus
= currentFocus
;
860 while ( currentFocus
&& currentFocus
!= pPage
&& currentFocus
!= this )
861 currentFocus
= currentFocus
->GetParent();
863 if ( startFocus
== pPage
|| currentFocus
!= pPage
)
867 else // no pages in the notebook, give the focus to itself
875 // we want to give others a chance to process this message as well
879 bool wxNotebook::MSWTranslateMessage(WXMSG
*wxmsg
)
881 const MSG
* const msg
= (MSG
*)wxmsg
;
883 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
884 // TAB will be passed to the currently selected page, CTRL+TAB and
885 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
886 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
888 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_TAB
&&
889 msg
->hwnd
== m_hwnd
&&
890 (wxIsCtrlDown() || !wxIsShiftDown()) )
892 return MSWProcessMessage(wxmsg
);
898 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
)
900 if ( event
.IsWindowChange() ) {
902 AdvanceSelection(event
.GetDirection());
905 // we get this event in 3 cases
907 // a) one of our pages might have generated it because the user TABbed
908 // out from it in which case we should propagate the event upwards and
909 // our parent will take care of setting the focus to prev/next sibling
913 // b) the parent panel wants to give the focus to us so that we
914 // forward it to our selected page. We can't deal with this in
915 // OnSetFocus() because we don't know which direction the focus came
916 // from in this case and so can't choose between setting the focus to
917 // first or last panel child
921 // c) we ourselves (see MSWTranslateMessage) generated the event
923 wxWindow
* const parent
= GetParent();
925 const bool isFromParent
= event
.GetEventObject() == parent
;
926 const bool isFromSelf
= event
.GetEventObject() == this;
928 if ( isFromParent
|| isFromSelf
)
930 // no, it doesn't come from child, case (b) or (c): forward to a
931 // page but only if direction is backwards (TAB) or from ourselves,
932 if ( m_nSelection
!= -1 &&
933 (!event
.GetDirection() || isFromSelf
) )
935 // so that the page knows that the event comes from it's parent
936 // and is being propagated downwards
937 event
.SetEventObject(this);
939 wxWindow
*page
= m_pages
[m_nSelection
];
940 if ( !page
->GetEventHandler()->ProcessEvent(event
) )
944 //else: page manages focus inside it itself
946 else // otherwise set the focus to the notebook itself
953 // it comes from our child, case (a), pass to the parent, but only
954 // if the direction is forwards. Otherwise set the focus to the
955 // notebook itself. The notebook is always the 'first' control of a
957 if ( !event
.GetDirection() )
963 event
.SetCurrentFocus(this);
964 parent
->GetEventHandler()->ProcessEvent(event
);
972 WXHBRUSH
wxNotebook::QueryBgBitmap()
975 ::GetClientRect(GetHwnd(), &rc
);
978 TabCtrl_AdjustRect(GetHwnd(), false, &rc
);
980 WindowHDC
hDC(GetHwnd());
981 MemoryHDC
hDCMem(hDC
);
982 CompatibleBitmap
hBmp(hDC
, rc
.right
, rc
.bottom
);
984 SelectInHDC
selectBmp(hDCMem
, hBmp
);
986 wxUxThemeHandle
theme(this, L
"TAB");
989 AdjustRectForThemeBg(rc
);
991 wxUxThemeEngine::Get()->DrawThemeBackground
1002 return (WXHBRUSH
)::CreatePatternBrush(hBmp
);
1005 void wxNotebook::UpdateBgBrush()
1007 if ( m_hbrBackground
)
1008 ::DeleteObject((HBRUSH
)m_hbrBackground
);
1010 if ( !m_hasBgCol
&& wxUxThemeEngine::GetIfActive() )
1012 m_hbrBackground
= QueryBgBitmap();
1016 m_hbrBackground
= NULL
;
1020 WXHBRUSH
wxNotebook::MSWGetBgBrushForChild(WXHDC hDC
, wxWindow
*win
)
1022 if ( m_hbrBackground
)
1024 // before drawing with the background brush, we need to position it
1027 ::GetWindowRect(GetHwndOf(win
), &rc
);
1029 ::MapWindowPoints(NULL
, GetHwnd(), (POINT
*)&rc
, 1);
1031 if ( !::SetBrushOrgEx((HDC
)hDC
, -rc
.left
, -rc
.top
, NULL
) )
1033 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
1036 return m_hbrBackground
;
1039 return wxNotebookBase::MSWGetBgBrushForChild(hDC
, win
);
1042 wxColour
wxNotebook::MSWGetBgColourForChild(wxWindow
*WXUNUSED(win
))
1045 return GetBackgroundColour();
1047 // Experimental: don't do this since we're doing it in wxPanel
1048 #if 0 // defined(__POCKETPC__) || defined(__SMARTPHONE__)
1049 // For some reason, the pages will be grey by default.
1050 // Normally they should be white on these platforms.
1051 // (However the static control backgrounds are painted
1052 // in the correct colour, just not the rest of it.)
1053 // So let's give WinCE a hint.
1054 else if (!win
->m_hasBgCol
)
1058 if ( !wxUxThemeEngine::GetIfActive() )
1059 return wxNullColour
;
1061 return GetThemeBackgroundColour();
1065 wxNotebook::MSWPrintChild(wxWindow
*win
,
1067 WXLPARAM
WXUNUSED(lParam
))
1069 // Don't paint the theme for the child if we have a solid background
1075 ::GetClientRect(GetHwnd(), &rc
);
1078 TabCtrl_AdjustRect(GetHwnd(), false, &rc
);
1080 wxUxThemeHandle
theme(win
, L
"TAB");
1083 // map from this client to win client coords
1084 ::MapWindowPoints(GetHwnd(), GetHwndOf(win
), (POINT
*)&rc
, 2);
1086 AdjustRectForThemeBg(rc
);
1087 wxUxThemeEngine::Get()->DrawThemeBackground
1101 #endif // wxUSE_UXTHEME
1103 // Windows only: attempts to get colour for UX theme page background
1104 wxColour
wxNotebook::GetThemeBackgroundColour() const
1107 if (wxUxThemeEngine::Get())
1109 wxUxThemeHandle
hTheme((wxNotebook
*) this, L
"TAB");
1112 // This is total guesswork.
1113 // See PlatformSDK\Include\Tmschema.h for values
1114 COLORREF themeColor
;
1115 wxUxThemeEngine::Get()->GetThemeColor(
1119 3821 /* FILLCOLORHINT */,
1123 [DS] Workaround for WindowBlinds:
1124 Some themes return a near black theme color using FILLCOLORHINT,
1125 this makes notebook pages have an ugly black background and makes
1126 text (usually black) unreadable. Retry again with FILLCOLOR.
1128 This workaround potentially breaks appearance of some themes,
1129 but in practice it already fixes some themes.
1131 if (themeColor
== 1)
1133 wxUxThemeEngine::Get()->GetThemeColor(
1137 3802 /* FILLCOLOR */,
1141 return wxRGBToColour(themeColor
);
1144 #endif // wxUSE_UXTHEME
1146 return GetBackgroundColour();
1149 // ----------------------------------------------------------------------------
1150 // wxNotebook base class virtuals
1151 // ----------------------------------------------------------------------------
1153 #if wxUSE_CONSTRAINTS
1155 // override these 2 functions to do nothing: everything is done in OnSize
1157 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
))
1159 // don't set the sizes of the pages - their correct size is not yet known
1160 wxControl::SetConstraintSizes(false);
1163 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
))
1168 #endif // wxUSE_CONSTRAINTS
1170 // ----------------------------------------------------------------------------
1171 // wxNotebook Windows message handlers
1172 // ----------------------------------------------------------------------------
1174 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
,
1175 WXWORD pos
, WXHWND control
)
1177 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1182 return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
);
1185 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
)
1187 wxNotebookEvent
event(wxEVT_NULL
, m_windowId
);
1189 NMHDR
* hdr
= (NMHDR
*)lParam
;
1190 switch ( hdr
->code
) {
1192 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
1195 case TCN_SELCHANGING
:
1196 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
);
1200 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1203 event
.SetSelection(TabCtrl_GetCurSel(m_hwnd
));
1204 event
.SetOldSelection(m_nSelection
);
1205 event
.SetEventObject(this);
1206 event
.SetInt(idCtrl
);
1208 bool processed
= GetEventHandler()->ProcessEvent(event
);
1209 *result
= !event
.IsAllowed();
1213 #endif // wxUSE_NOTEBOOK