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 // fit all the notebook pages to the tab control's display area
750 rc
.left
= rc
.top
= 0;
751 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
753 // save the total size, we'll use it below
754 int widthNbook
= rc
.right
- rc
.left
,
755 heightNbook
= rc
.bottom
- rc
.top
;
757 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
758 // returns completely false values for multiline tab controls after the tabs
759 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
761 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
763 // and the only work around I could find was this ugly hack... without it
764 // simply toggling the "multiline" checkbox in the notebook sample resulted
765 // in a noticeable page displacement
766 if ( HasFlag(wxNB_MULTILINE
) )
768 // avoid an infinite recursion: we get another notification too!
769 static bool s_isInOnSize
= false;
774 SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
,
775 MAKELPARAM(rc
.right
, rc
.bottom
));
776 s_isInOnSize
= false;
780 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
782 int width
= rc
.right
- rc
.left
,
783 height
= rc
.bottom
- rc
.top
;
784 size_t nCount
= m_pages
.Count();
785 for ( size_t nPage
= 0; nPage
< nCount
; nPage
++ ) {
786 wxNotebookPage
*pPage
= m_pages
[nPage
];
787 pPage
->SetSize(rc
.left
, rc
.top
, width
, height
);
791 // unless we had already repainted everything, we now need to refresh
792 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
794 // invalidate areas not covered by pages
795 RefreshRect(wxRect(0, 0, widthNbook
, rc
.top
), false);
796 RefreshRect(wxRect(0, rc
.top
, rc
.left
, height
), false);
797 RefreshRect(wxRect(0, rc
.bottom
, widthNbook
, heightNbook
- rc
.bottom
),
799 RefreshRect(wxRect(rc
.right
, rc
.top
, widthNbook
- rc
.bottom
, height
),
806 void wxNotebook::OnSelChange(wxNotebookEvent
& event
)
808 // is it our tab control?
809 if ( event
.GetEventObject() == this )
811 int sel
= event
.GetOldSelection();
813 m_pages
[sel
]->Show(false);
815 sel
= event
.GetSelection();
818 wxNotebookPage
*pPage
= m_pages
[sel
];
822 // If the newly focused window is not a child of the new page,
823 // SetFocus was not successful and the notebook itself should be
825 wxWindow
*currentFocus
= FindFocus();
826 wxWindow
*startFocus
= currentFocus
;
827 while ( currentFocus
&& currentFocus
!= pPage
&& currentFocus
!= this )
828 currentFocus
= currentFocus
->GetParent();
830 if ( startFocus
== pPage
|| currentFocus
!= pPage
)
834 else // no pages in the notebook, give the focus to itself
842 // we want to give others a chance to process this message as well
846 bool wxNotebook::MSWTranslateMessage(WXMSG
*wxmsg
)
848 const MSG
* const msg
= (MSG
*)wxmsg
;
850 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
851 // TAB will be passed to the currently selected page, CTRL+TAB and
852 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
853 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
855 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_TAB
&&
856 msg
->hwnd
== m_hwnd
&&
857 (wxIsCtrlDown() || !wxIsShiftDown()) )
859 return MSWProcessMessage(wxmsg
);
865 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
)
867 if ( event
.IsWindowChange() ) {
869 AdvanceSelection(event
.GetDirection());
872 // we get this event in 3 cases
874 // a) one of our pages might have generated it because the user TABbed
875 // out from it in which case we should propagate the event upwards and
876 // our parent will take care of setting the focus to prev/next sibling
880 // b) the parent panel wants to give the focus to us so that we
881 // forward it to our selected page. We can't deal with this in
882 // OnSetFocus() because we don't know which direction the focus came
883 // from in this case and so can't choose between setting the focus to
884 // first or last panel child
888 // c) we ourselves (see MSWTranslateMessage) generated the event
890 wxWindow
* const parent
= GetParent();
892 const bool isFromParent
= event
.GetEventObject() == parent
;
893 const bool isFromSelf
= event
.GetEventObject() == this;
895 if ( isFromParent
|| isFromSelf
)
897 // no, it doesn't come from child, case (b) or (c): forward to a
898 // page but only if direction is backwards (TAB) or from ourselves,
899 if ( m_nSelection
!= -1 &&
900 (!event
.GetDirection() || isFromSelf
) )
902 // so that the page knows that the event comes from it's parent
903 // and is being propagated downwards
904 event
.SetEventObject(this);
906 wxWindow
*page
= m_pages
[m_nSelection
];
907 if ( !page
->GetEventHandler()->ProcessEvent(event
) )
911 //else: page manages focus inside it itself
913 else // otherwise set the focus to the notebook itself
920 // it comes from our child, case (a), pass to the parent, but only
921 // if the direction is forwards. Otherwise set the focus to the
922 // notebook itself. The notebook is always the 'first' control of a
924 if ( !event
.GetDirection() )
930 event
.SetCurrentFocus(this);
931 parent
->GetEventHandler()->ProcessEvent(event
);
939 WXHANDLE
wxNotebook::QueryBgBitmap(wxWindow
*win
)
942 GetWindowRect(GetHwnd(), &rc
);
944 WindowHDC
hDC(GetHwnd());
945 MemoryHDC
hDCMem(hDC
);
946 CompatibleBitmap
hBmp(hDC
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
948 SelectInHDC
selectBmp(hDCMem
, hBmp
);
950 ::SendMessage(GetHwnd(), WM_PRINTCLIENT
,
952 PRF_ERASEBKGND
| PRF_CLIENT
| PRF_NONCLIENT
);
957 ::GetWindowRect(GetHwndOf(win
), &rc2
);
959 COLORREF c
= ::GetPixel(hDCMem
, rc2
.left
- rc
.left
, rc2
.top
- rc
.top
);
963 //else: we are asked to create the brush
965 return (WXHANDLE
)::CreatePatternBrush(hBmp
);
968 void wxNotebook::UpdateBgBrush()
970 if ( m_hbrBackground
)
971 ::DeleteObject((HBRUSH
)m_hbrBackground
);
973 if ( !m_hasBgCol
&& wxUxThemeEngine::GetIfActive() )
975 m_hbrBackground
= (WXHBRUSH
)QueryBgBitmap();
979 m_hbrBackground
= NULL
;
983 WXHBRUSH
wxNotebook::MSWGetBgBrushForChild(WXHDC hDC
, wxWindow
*win
)
985 if ( m_hbrBackground
)
987 // before drawing with the background brush, we need to position it
990 ::GetWindowRect(GetHwndOf(win
), &rc
);
992 ::MapWindowPoints(NULL
, GetHwnd(), (POINT
*)&rc
, 1);
994 if ( !::SetBrushOrgEx((HDC
)hDC
, -rc
.left
, -rc
.top
, NULL
) )
996 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
999 return m_hbrBackground
;
1002 return wxNotebookBase::MSWGetBgBrushForChild(hDC
, win
);
1005 wxColour
wxNotebook::MSWGetBgColourForChild(wxWindow
*win
)
1008 return GetBackgroundColour();
1010 // Experimental: don't do this since we're doing it in wxPanel
1011 #if 0 // defined(__POCKETPC__) || defined(__SMARTPHONE__)
1012 // For some reason, the pages will be grey by default.
1013 // Normally they should be white on these platforms.
1014 // (However the static control backgrounds are painted
1015 // in the correct colour, just not the rest of it.)
1016 // So let's give WinCE a hint.
1017 else if (!win
->m_hasBgCol
)
1021 if ( !wxUxThemeEngine::GetIfActive() )
1022 return wxNullColour
;
1024 COLORREF c
= (COLORREF
)QueryBgBitmap(win
);
1026 return c
== CLR_INVALID
? wxNullColour
: wxRGBToColour(c
);
1030 wxNotebook::MSWPrintChild(wxWindow
*win
,
1032 WXLPARAM
WXUNUSED(lParam
))
1034 // Don't paint the theme for the child if we have a solid
1036 if (m_hasBgCol
|| HasFlag(wxNB_NOPAGETHEME
) || (wxSystemOptions::HasOption(wxT("msw.notebook.themed-background")) &&
1037 wxSystemOptions::GetOptionInt(wxT("msw.notebook.themed-background")) == 0))
1041 ::GetClientRect(GetHwnd(), &rc
);
1042 TabCtrl_AdjustRect(GetHwnd(), true, &rc
);
1043 ::MapWindowPoints(GetHwnd(), GetHwndOf(win
), (POINT
*)&rc
, 2);
1045 wxUxThemeHandle
theme(win
, L
"TAB");
1048 wxUxThemeEngine::Get()->DrawThemeBackground
1062 #endif // wxUSE_UXTHEME
1064 // Windows only: attempts to get colour for UX theme page background
1065 wxColour
wxNotebook::GetThemeBackgroundColour() const
1068 if (wxUxThemeEngine::Get())
1070 wxUxThemeHandle
hTheme((wxNotebook
*) this, L
"TAB");
1073 // This is total guesswork.
1074 // See PlatformSDK\Include\Tmschema.h for values
1075 COLORREF themeColor
;
1076 wxUxThemeEngine::Get()->GetThemeColor(
1080 3821 /* FILLCOLORHINT */,
1084 [DS] Workaround for WindowBlinds:
1085 Some themes return a near black theme color using FILLCOLORHINT,
1086 this makes notebook pages have an ugly black background and makes
1087 text (usually black) unreadable. Retry again with FILLCOLOR.
1089 This workaround potentially breaks appearance of some themes,
1090 but in practice it already fixes some themes.
1092 if (themeColor
== 1)
1094 wxUxThemeEngine::Get()->GetThemeColor(
1098 3802 /* FILLCOLOR */,
1102 wxColour
colour(GetRValue(themeColor
), GetGValue(themeColor
), GetBValue(themeColor
));
1106 #endif // wxUSE_UXTHEME
1108 return GetBackgroundColour();
1111 // ----------------------------------------------------------------------------
1112 // wxNotebook base class virtuals
1113 // ----------------------------------------------------------------------------
1115 #if wxUSE_CONSTRAINTS
1117 // override these 2 functions to do nothing: everything is done in OnSize
1119 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
))
1121 // don't set the sizes of the pages - their correct size is not yet known
1122 wxControl::SetConstraintSizes(false);
1125 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
))
1130 #endif // wxUSE_CONSTRAINTS
1132 // ----------------------------------------------------------------------------
1133 // wxNotebook Windows message handlers
1134 // ----------------------------------------------------------------------------
1136 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
,
1137 WXWORD pos
, WXHWND control
)
1139 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1144 return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
);
1147 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
)
1149 wxNotebookEvent
event(wxEVT_NULL
, m_windowId
);
1151 NMHDR
* hdr
= (NMHDR
*)lParam
;
1152 switch ( hdr
->code
) {
1154 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
1157 case TCN_SELCHANGING
:
1158 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
);
1162 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1165 event
.SetSelection(TabCtrl_GetCurSel(m_hwnd
));
1166 event
.SetOldSelection(m_nSelection
);
1167 event
.SetEventObject(this);
1168 event
.SetInt(idCtrl
);
1170 bool processed
= GetEventHandler()->ProcessEvent(event
);
1171 *result
= !event
.IsAllowed();
1175 #endif // wxUSE_NOTEBOOK