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"
38 #include "wx/msw/private.h"
42 #ifdef __GNUWIN32_OLD__
43 #include "wx/msw/gnuwin32/extra.h"
46 #if !(defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__))
50 #include "wx/msw/winundef.h"
53 #include "wx/msw/uxtheme.h"
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 // check that the page index is valid
61 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount())
64 #define m_hwnd (HWND)GetHWND()
66 // ----------------------------------------------------------------------------
68 // ----------------------------------------------------------------------------
70 // This is a work-around for missing defines in gcc-2.95 headers
72 #define TCS_RIGHT 0x0002
76 #define TCS_VERTICAL 0x0080
80 #define TCS_BOTTOM TCS_RIGHT
83 // ----------------------------------------------------------------------------
85 // ----------------------------------------------------------------------------
87 #include <wx/listimpl.cpp>
89 WX_DEFINE_LIST( wxNotebookPageInfoList
) ;
91 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
)
92 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
)
94 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
)
95 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange
)
97 EVT_SIZE(wxNotebook::OnSize
)
99 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
102 #if wxUSE_EXTENDED_RTTI
103 WX_DEFINE_FLAGS( wxNotebookStyle
)
105 wxBEGIN_FLAGS( wxNotebookStyle
)
106 // new style border flags, we put them first to
107 // use them for streaming out
108 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
109 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
110 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
111 wxFLAGS_MEMBER(wxBORDER_RAISED
)
112 wxFLAGS_MEMBER(wxBORDER_STATIC
)
113 wxFLAGS_MEMBER(wxBORDER_NONE
)
115 // old style border flags
116 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
117 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
118 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
119 wxFLAGS_MEMBER(wxRAISED_BORDER
)
120 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
121 wxFLAGS_MEMBER(wxBORDER
)
123 // standard window styles
124 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
125 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
126 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
127 wxFLAGS_MEMBER(wxWANTS_CHARS
)
128 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
129 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
130 wxFLAGS_MEMBER(wxVSCROLL
)
131 wxFLAGS_MEMBER(wxHSCROLL
)
133 wxFLAGS_MEMBER(wxNB_FIXEDWIDTH
)
134 wxFLAGS_MEMBER(wxNB_LEFT
)
135 wxFLAGS_MEMBER(wxNB_RIGHT
)
136 wxFLAGS_MEMBER(wxNB_BOTTOM
)
138 wxEND_FLAGS( wxNotebookStyle
)
140 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebook
, wxControl
,"wx/notebook.h")
141 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebookPageInfo
, wxObject
, "wx/notebook.h" )
143 wxCOLLECTION_TYPE_INFO( wxNotebookPageInfo
* , wxNotebookPageInfoList
) ;
145 template<> void wxCollectionToVariantArray( wxNotebookPageInfoList
const &theList
, wxxVariantArray
&value
)
147 wxListCollectionToVariantArray
<wxNotebookPageInfoList::compatibility_iterator
>( theList
, value
) ;
150 wxBEGIN_PROPERTIES_TABLE(wxNotebook
)
151 wxEVENT_PROPERTY( PageChanging
, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, wxNotebookEvent
)
152 wxEVENT_PROPERTY( PageChanged
, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
, wxNotebookEvent
)
154 wxPROPERTY_COLLECTION( PageInfos
, wxNotebookPageInfoList
, wxNotebookPageInfo
* , AddPageInfo
, GetPageInfos
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
155 wxPROPERTY_FLAGS( WindowStyle
, wxNotebookStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
156 wxEND_PROPERTIES_TABLE()
158 wxBEGIN_HANDLERS_TABLE(wxNotebook
)
159 wxEND_HANDLERS_TABLE()
161 wxCONSTRUCTOR_5( wxNotebook
, wxWindow
* , Parent
, wxWindowID
, Id
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
164 wxBEGIN_PROPERTIES_TABLE(wxNotebookPageInfo
)
165 wxREADONLY_PROPERTY( Page
, wxNotebookPage
* , GetPage
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
166 wxREADONLY_PROPERTY( Text
, wxString
, GetText
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
167 wxREADONLY_PROPERTY( Selected
, bool , GetSelected
, false, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
168 wxREADONLY_PROPERTY( ImageId
, int , GetImageId
, -1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
169 wxEND_PROPERTIES_TABLE()
171 wxBEGIN_HANDLERS_TABLE(wxNotebookPageInfo
)
172 wxEND_HANDLERS_TABLE()
174 wxCONSTRUCTOR_4( wxNotebookPageInfo
, wxNotebookPage
* , Page
, wxString
, Text
, bool , Selected
, int , ImageId
)
177 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
)
178 IMPLEMENT_DYNAMIC_CLASS(wxNotebookPageInfo
, wxObject
)
180 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxNotifyEvent
)
182 // ============================================================================
184 // ============================================================================
186 // ----------------------------------------------------------------------------
187 // wxNotebook construction
188 // ----------------------------------------------------------------------------
190 const wxNotebookPageInfoList
& wxNotebook::GetPageInfos() const
192 wxNotebookPageInfoList
* list
= const_cast< wxNotebookPageInfoList
* >( &m_pageInfos
) ;
193 WX_CLEAR_LIST( wxNotebookPageInfoList
, *list
) ;
194 for( size_t i
= 0 ; i
< GetPageCount() ; ++i
)
196 wxNotebookPageInfo
*info
= new wxNotebookPageInfo() ;
197 info
->Create( const_cast<wxNotebook
*>(this)->GetPage(i
) , GetPageText(i
) , GetSelection() == int(i
) , GetPageImage(i
) ) ;
198 list
->Append( info
) ;
203 // common part of all ctors
204 void wxNotebook::Init()
210 m_hbrBackground
= NULL
;
211 #endif // wxUSE_UXTHEME
214 // default for dynamic class
215 wxNotebook::wxNotebook()
220 // the same arguments as for wxControl
221 wxNotebook::wxNotebook(wxWindow
*parent
,
226 const wxString
& name
)
230 Create(parent
, id
, pos
, size
, style
, name
);
234 bool wxNotebook::Create(wxWindow
*parent
,
239 const wxString
& name
)
241 // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the
242 // control is simply not rendered correctly), so disable them in this case
243 const int verComCtl32
= wxApp::GetComCtl32Version();
244 if ( verComCtl32
== 600 )
246 // check if we use themes at all -- if we don't, we're still ok
248 if ( wxUxThemeEngine::GetIfActive() )
251 style
&= ~(wxNB_BOTTOM
| wxNB_LEFT
| wxNB_RIGHT
);
255 LPCTSTR className
= WC_TABCONTROL
;
257 // SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it
258 // causes horrible flicker when resizing notebook, so get rid of it by
259 // using a class without these styles (but otherwise identical to it)
260 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
262 static ClassRegistrar s_clsNotebook
;
263 if ( !s_clsNotebook
.IsInitialized() )
265 // get a copy of standard class and modify it
268 if ( ::GetClassInfo(::GetModuleHandle(NULL
), WC_TABCONTROL
, &wc
) )
270 wc
.lpszClassName
= wxT("_wx_SysTabCtl32");
271 wc
.style
&= ~(CS_HREDRAW
| CS_VREDRAW
);
273 s_clsNotebook
.Register(wc
);
277 wxLogLastError(_T("GetClassInfoEx(SysTabCtl32)"));
281 // use our custom class if available but fall back to the standard
282 // notebook if we failed to register it
283 if ( s_clsNotebook
.IsRegistered() )
285 // it's ok to use c_str() here as the static s_clsNotebook object
286 // has sufficiently long lifetime
287 className
= s_clsNotebook
.GetName().c_str();
291 if ( !CreateControl(parent
, id
, pos
, size
, style
| wxTAB_TRAVERSAL
,
292 wxDefaultValidator
, name
) )
295 if ( !MSWCreateControl(className
, wxEmptyString
, pos
, size
) )
301 WXDWORD
wxNotebook::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
303 WXDWORD tabStyle
= wxControl::MSWGetStyle(style
, exstyle
);
305 tabStyle
|= WS_TABSTOP
| TCS_TABS
;
307 if ( style
& wxNB_MULTILINE
)
308 tabStyle
|= TCS_MULTILINE
;
309 if ( style
& wxNB_FIXEDWIDTH
)
310 tabStyle
|= TCS_FIXEDWIDTH
;
312 if ( style
& wxNB_BOTTOM
)
313 tabStyle
|= TCS_RIGHT
;
314 else if ( style
& wxNB_LEFT
)
315 tabStyle
|= TCS_VERTICAL
;
316 else if ( style
& wxNB_RIGHT
)
317 tabStyle
|= TCS_VERTICAL
| TCS_RIGHT
;
322 // note that we never want to have the default WS_EX_CLIENTEDGE style
323 // as it looks too ugly for the notebooks
330 wxNotebook::~wxNotebook()
333 if ( m_hbrBackground
)
334 ::DeleteObject((HBRUSH
)m_hbrBackground
);
335 #endif // wxUSE_UXTHEME
338 // ----------------------------------------------------------------------------
339 // wxNotebook accessors
340 // ----------------------------------------------------------------------------
342 size_t wxNotebook::GetPageCount() const
345 wxASSERT( (int)m_pages
.Count() == TabCtrl_GetItemCount(m_hwnd
) );
347 return m_pages
.Count();
350 int wxNotebook::GetRowCount() const
352 return TabCtrl_GetRowCount(m_hwnd
);
355 int wxNotebook::SetSelection(size_t nPage
)
357 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
359 if ( int(nPage
) != m_nSelection
)
361 wxNotebookEvent
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, m_windowId
);
362 event
.SetSelection(nPage
);
363 event
.SetOldSelection(m_nSelection
);
364 event
.SetEventObject(this);
365 if ( !GetEventHandler()->ProcessEvent(event
) || event
.IsAllowed() )
367 // program allows the page change
368 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
369 (void)GetEventHandler()->ProcessEvent(event
);
371 TabCtrl_SetCurSel(m_hwnd
, nPage
);
378 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
)
380 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
383 tcItem
.mask
= TCIF_TEXT
;
384 tcItem
.pszText
= (wxChar
*)strText
.c_str();
386 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
389 wxString
wxNotebook::GetPageText(size_t nPage
) const
391 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") );
395 tcItem
.mask
= TCIF_TEXT
;
396 tcItem
.pszText
= buf
;
397 tcItem
.cchTextMax
= WXSIZEOF(buf
);
400 if ( TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) )
401 str
= tcItem
.pszText
;
406 int wxNotebook::GetPageImage(size_t nPage
) const
408 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
411 tcItem
.mask
= TCIF_IMAGE
;
413 return TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) ? tcItem
.iImage
: -1;
416 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
)
418 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
421 tcItem
.mask
= TCIF_IMAGE
;
422 tcItem
.iImage
= nImage
;
424 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
427 void wxNotebook::SetImageList(wxImageList
* imageList
)
429 wxNotebookBase::SetImageList(imageList
);
433 TabCtrl_SetImageList(m_hwnd
, (HIMAGELIST
)imageList
->GetHIMAGELIST());
437 // ----------------------------------------------------------------------------
438 // wxNotebook size settings
439 // ----------------------------------------------------------------------------
441 void wxNotebook::SetPageSize(const wxSize
& size
)
443 // transform the page size into the notebook size
450 TabCtrl_AdjustRect(GetHwnd(), true, &rc
);
453 SetSize(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
456 void wxNotebook::SetPadding(const wxSize
& padding
)
458 TabCtrl_SetPadding(GetHwnd(), padding
.x
, padding
.y
);
461 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
463 void wxNotebook::SetTabSize(const wxSize
& sz
)
465 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE
, 0, MAKELPARAM(sz
.x
, sz
.y
));
468 wxSize
wxNotebook::CalcSizeFromPage(const wxSize
& sizePage
) const
470 wxSize sizeTotal
= sizePage
;
472 // We need to make getting tab size part of the wxWidgets API.
473 wxSize
tabSize(0, 0);
474 if (GetPageCount() > 0)
477 TabCtrl_GetItemRect((HWND
) GetHWND(), 0, & rect
);
478 tabSize
.x
= rect
.right
- rect
.left
;
479 tabSize
.y
= rect
.bottom
- rect
.top
;
481 if ( HasFlag(wxNB_LEFT
) || HasFlag(wxNB_RIGHT
) )
483 sizeTotal
.x
+= tabSize
.x
+ 7;
489 sizeTotal
.y
+= tabSize
.y
+ 7;
495 void wxNotebook::AdjustPageSize(wxNotebookPage
*page
)
497 wxCHECK_RET( page
, _T("NULL page in wxNotebook::AdjustPageSize") );
503 // get the page size from the notebook size
504 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
506 // This check is to work around a bug in TabCtrl_AdjustRect which will
507 // cause a crash on win2k, or on XP with themes disabled, if the
508 // wxNB_MULTILINE style is used and the rectangle is very small, (such as
509 // when the notebook is first created.) The value of 20 is just
510 // arbitrarily chosen, if there is a better way to determine this value
511 // then please do so. --RD
512 if (rc
.right
> 20 && rc
.bottom
> 20)
514 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
515 page
->SetSize(rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
519 // ----------------------------------------------------------------------------
520 // wxNotebook operations
521 // ----------------------------------------------------------------------------
523 // remove one page from the notebook, without deleting
524 wxNotebookPage
*wxNotebook::DoRemovePage(size_t nPage
)
526 wxNotebookPage
*pageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
530 TabCtrl_DeleteItem(m_hwnd
, nPage
);
532 if ( m_pages
.IsEmpty() )
534 // no selection any more, the notebook becamse empty
537 else // notebook still not empty
539 int selNew
= TabCtrl_GetCurSel(m_hwnd
);
542 // No selection change, just refresh the current selection.
543 // Because it could be that the slection index changed
544 // we need to update it.
545 // Note: this does not mean the selection it self changed.
546 m_nSelection
= selNew
;
547 m_pages
[m_nSelection
]->Refresh();
549 else if (int(nPage
) == m_nSelection
)
551 // The selection was deleted.
553 // Determine new selection.
554 if (m_nSelection
== int(GetPageCount()))
555 selNew
= m_nSelection
- 1;
557 selNew
= m_nSelection
;
559 // m_nSelection must be always valid so reset it before calling
562 SetSelection(selNew
);
566 wxFAIL
; // Windows did not behave ok.
574 bool wxNotebook::DeleteAllPages()
576 size_t nPageCount
= GetPageCount();
578 for ( nPage
= 0; nPage
< nPageCount
; nPage
++ )
579 delete m_pages
[nPage
];
583 TabCtrl_DeleteAllItems(m_hwnd
);
587 InvalidateBestSize();
591 // same as AddPage() but does it at given position
592 bool wxNotebook::InsertPage(size_t nPage
,
593 wxNotebookPage
*pPage
,
594 const wxString
& strText
,
598 wxCHECK_MSG( pPage
!= NULL
, false, _T("NULL page in wxNotebook::InsertPage") );
599 wxCHECK_MSG( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false,
600 _T("invalid index in wxNotebook::InsertPage") );
602 wxASSERT_MSG( pPage
->GetParent() == this,
603 _T("notebook pages must have notebook as parent") );
605 // add a new tab to the control
606 // ----------------------------
608 // init all fields to 0
610 wxZeroMemory(tcItem
);
612 // set the image, if any
615 tcItem
.mask
|= TCIF_IMAGE
;
616 tcItem
.iImage
= imageId
;
620 if ( !strText
.IsEmpty() )
622 tcItem
.mask
|= TCIF_TEXT
;
623 tcItem
.pszText
= (wxChar
*)strText
.c_str(); // const_cast
626 // hide the page: unless it is selected, it shouldn't be shown (and if it
627 // is selected it will be shown later)
628 HWND hwnd
= GetWinHwnd(pPage
);
629 SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~WS_VISIBLE
);
631 // this updates internal flag too -- otherwise it would get out of sync
632 // with the real state
636 // fit the notebook page to the tab control's display area: this should be
637 // done before adding it to the notebook or TabCtrl_InsertItem() will
638 // change the notebooks size itself!
639 AdjustPageSize(pPage
);
641 // finally do insert it
642 if ( TabCtrl_InsertItem(m_hwnd
, nPage
, &tcItem
) == -1 )
644 wxLogError(wxT("Can't create the notebook page '%s'."), strText
.c_str());
649 // succeeded: save the pointer to the page
650 m_pages
.Insert(pPage
, nPage
);
652 // we may need to adjust the size again if the notebook size changed:
653 // normally this only happens for the first page we add (the tabs which
654 // hadn't been there before are now shown) but for a multiline notebook it
655 // can happen for any page at all as a new row could have been started
656 if ( m_pages
.GetCount() == 1 || HasFlag(wxNB_MULTILINE
) )
658 AdjustPageSize(pPage
);
661 // now deal with the selection
662 // ---------------------------
664 // if the inserted page is before the selected one, we must update the
665 // index of the selected page
666 if ( int(nPage
) <= m_nSelection
)
668 // one extra page added
672 // some page should be selected: either this one or the first one if there
673 // is still no selection
677 else if ( m_nSelection
== -1 )
681 SetSelection(selNew
);
683 InvalidateBestSize();
687 int wxNotebook::HitTest(const wxPoint
& pt
, long *flags
) const
689 TC_HITTESTINFO hitTestInfo
;
690 hitTestInfo
.pt
.x
= pt
.x
;
691 hitTestInfo
.pt
.y
= pt
.y
;
692 int item
= TabCtrl_HitTest(GetHwnd(), &hitTestInfo
);
698 if ((hitTestInfo
.flags
& TCHT_NOWHERE
) == TCHT_NOWHERE
)
699 *flags
|= wxNB_HITTEST_NOWHERE
;
700 if ((hitTestInfo
.flags
& TCHT_ONITEM
) == TCHT_ONITEM
)
701 *flags
|= wxNB_HITTEST_ONITEM
;
702 if ((hitTestInfo
.flags
& TCHT_ONITEMICON
) == TCHT_ONITEMICON
)
703 *flags
|= wxNB_HITTEST_ONICON
;
704 if ((hitTestInfo
.flags
& TCHT_ONITEMLABEL
) == TCHT_ONITEMLABEL
)
705 *flags
|= wxNB_HITTEST_ONLABEL
;
712 // ----------------------------------------------------------------------------
713 // wxNotebook callbacks
714 // ----------------------------------------------------------------------------
716 void wxNotebook::OnSize(wxSizeEvent
& event
)
718 // update the background brush
721 #endif // wxUSE_UXTHEME
723 // fit all the notebook pages to the tab control's display area
726 rc
.left
= rc
.top
= 0;
727 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
729 // save the total size, we'll use it below
730 int widthNbook
= rc
.right
- rc
.left
,
731 heightNbook
= rc
.bottom
- rc
.top
;
733 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
734 // returns completely false values for multiline tab controls after the tabs
735 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
737 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
739 // and the only work around I could find was this ugly hack... without it
740 // simply toggling the "multiline" checkbox in the notebook sample resulted
741 // in a noticeable page displacement
742 if ( HasFlag(wxNB_MULTILINE
) )
744 // avoid an infinite recursion: we get another notification too!
745 static bool s_isInOnSize
= false;
750 SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
,
751 MAKELPARAM(rc
.right
, rc
.bottom
));
752 s_isInOnSize
= false;
756 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
758 int width
= rc
.right
- rc
.left
,
759 height
= rc
.bottom
- rc
.top
;
760 size_t nCount
= m_pages
.Count();
761 for ( size_t nPage
= 0; nPage
< nCount
; nPage
++ ) {
762 wxNotebookPage
*pPage
= m_pages
[nPage
];
763 pPage
->SetSize(rc
.left
, rc
.top
, width
, height
);
767 // unless we had already repainted everything, we now need to refresh
768 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
770 // invalidate areas not covered by pages
771 RefreshRect(wxRect(0, 0, widthNbook
, rc
.top
), false);
772 RefreshRect(wxRect(0, rc
.top
, rc
.left
, height
), false);
773 RefreshRect(wxRect(0, rc
.bottom
, widthNbook
, heightNbook
- rc
.bottom
),
775 RefreshRect(wxRect(rc
.right
, rc
.top
, widthNbook
- rc
.bottom
, height
),
782 void wxNotebook::OnSelChange(wxNotebookEvent
& event
)
784 // is it our tab control?
785 if ( event
.GetEventObject() == this )
787 int sel
= event
.GetOldSelection();
789 m_pages
[sel
]->Show(false);
791 sel
= event
.GetSelection();
794 wxNotebookPage
*pPage
= m_pages
[sel
];
798 // If the newly focused window is not a child of the new page,
799 // SetFocus was not successful and the notebook itself should be
801 wxWindow
*currentFocus
= FindFocus();
802 wxWindow
*startFocus
= currentFocus
;
803 while ( currentFocus
&& currentFocus
!= pPage
&& currentFocus
!= this )
804 currentFocus
= currentFocus
->GetParent();
806 if ( startFocus
== pPage
|| currentFocus
!= pPage
)
810 else // no pages in the notebook, give the focus to itself
818 // we want to give others a chance to process this message as well
822 bool wxNotebook::MSWTranslateMessage(WXMSG
*wxmsg
)
824 const MSG
* const msg
= (MSG
*)wxmsg
;
826 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
827 // TAB will be passed to the currently selected page, CTRL+TAB and
828 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
829 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
831 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_TAB
&&
832 msg
->hwnd
== m_hwnd
&&
833 (wxIsCtrlDown() || !wxIsShiftDown()) )
835 return MSWProcessMessage(wxmsg
);
841 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
)
843 if ( event
.IsWindowChange() ) {
845 AdvanceSelection(event
.GetDirection());
848 // we get this event in 3 cases
850 // a) one of our pages might have generated it because the user TABbed
851 // out from it in which case we should propagate the event upwards and
852 // our parent will take care of setting the focus to prev/next sibling
856 // b) the parent panel wants to give the focus to us so that we
857 // forward it to our selected page. We can't deal with this in
858 // OnSetFocus() because we don't know which direction the focus came
859 // from in this case and so can't choose between setting the focus to
860 // first or last panel child
864 // c) we ourselves (see MSWTranslateMessage) generated the event
866 wxWindow
* const parent
= GetParent();
868 const bool isFromParent
= event
.GetEventObject() == parent
;
869 const bool isFromSelf
= event
.GetEventObject() == this;
871 if ( isFromParent
|| isFromSelf
)
873 // no, it doesn't come from child, case (b) or (c): forward to a
874 // page but only if direction is backwards (TAB) or from ourselves,
875 if ( m_nSelection
!= -1 &&
876 (!event
.GetDirection() || isFromSelf
) )
878 // so that the page knows that the event comes from it's parent
879 // and is being propagated downwards
880 event
.SetEventObject(this);
882 wxWindow
*page
= m_pages
[m_nSelection
];
883 if ( !page
->GetEventHandler()->ProcessEvent(event
) )
887 //else: page manages focus inside it itself
889 else // otherwise set the focus to the notebook itself
896 // it comes from our child, case (a), pass to the parent, but only
897 // if the direction is forwards. Otherwise set the focus to the
898 // notebook itself. The notebook is always the 'first' control of a
900 if ( !event
.GetDirection() )
906 event
.SetCurrentFocus(this);
907 parent
->GetEventHandler()->ProcessEvent(event
);
915 WXHANDLE
wxNotebook::QueryBgBitmap(wxWindow
*win
)
918 GetWindowRect(GetHwnd(), &rc
);
920 WindowHDC
hDC(GetHwnd());
921 MemoryHDC
hDCMem(hDC
);
922 CompatibleBitmap
hBmp(hDC
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
924 SelectInHDC
selectBmp(hDCMem
, hBmp
);
926 ::SendMessage(GetHwnd(), WM_PRINTCLIENT
,
928 PRF_ERASEBKGND
| PRF_CLIENT
| PRF_NONCLIENT
);
933 ::GetWindowRect(GetHwndOf(win
), &rc2
);
935 COLORREF c
= ::GetPixel(hDCMem
, rc2
.left
- rc
.left
, rc2
.top
- rc
.top
);
939 //else: we are asked to create the brush
941 return (WXHANDLE
)::CreatePatternBrush(hBmp
);
944 void wxNotebook::UpdateBgBrush()
946 if ( m_hbrBackground
)
947 ::DeleteObject((HBRUSH
)m_hbrBackground
);
949 if ( !m_hasBgCol
&& wxUxThemeEngine::GetIfActive() )
951 m_hbrBackground
= (WXHBRUSH
)QueryBgBitmap();
955 m_hbrBackground
= NULL
;
959 WXHBRUSH
wxNotebook::MSWGetBgBrushForChild(WXHDC hDC
, wxWindow
*win
)
961 if ( m_hbrBackground
)
963 // before drawing with the background brush, we need to position it
966 ::GetWindowRect(GetHwndOf(win
), &rc
);
968 ::MapWindowPoints(NULL
, GetHwnd(), (POINT
*)&rc
, 1);
970 if ( !::SetBrushOrgEx((HDC
)hDC
, -rc
.left
, -rc
.top
, NULL
) )
972 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
975 return m_hbrBackground
;
978 return wxNotebookBase::MSWGetBgBrushForChild(hDC
, win
);
981 wxColour
wxNotebook::MSWGetBgColourForChild(wxWindow
*win
)
984 return GetBackgroundColour();
986 if ( !wxUxThemeEngine::GetIfActive() )
989 COLORREF c
= (COLORREF
)QueryBgBitmap(win
);
991 return c
== CLR_INVALID
? wxNullColour
: wxRGBToColour(c
);
994 #endif // wxUSE_UXTHEME
996 // ----------------------------------------------------------------------------
997 // wxNotebook base class virtuals
998 // ----------------------------------------------------------------------------
1000 #if wxUSE_CONSTRAINTS
1002 // override these 2 functions to do nothing: everything is done in OnSize
1004 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
))
1006 // don't set the sizes of the pages - their correct size is not yet known
1007 wxControl::SetConstraintSizes(false);
1010 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
))
1015 #endif // wxUSE_CONSTRAINTS
1017 // ----------------------------------------------------------------------------
1018 // wxNotebook Windows message handlers
1019 // ----------------------------------------------------------------------------
1021 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
,
1022 WXWORD pos
, WXHWND control
)
1024 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1029 return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
);
1032 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
)
1034 wxNotebookEvent
event(wxEVT_NULL
, m_windowId
);
1036 NMHDR
* hdr
= (NMHDR
*)lParam
;
1037 switch ( hdr
->code
) {
1039 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
1042 case TCN_SELCHANGING
:
1043 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
);
1047 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1050 event
.SetSelection(TabCtrl_GetCurSel(m_hwnd
));
1051 event
.SetOldSelection(m_nSelection
);
1052 event
.SetEventObject(this);
1053 event
.SetInt(idCtrl
);
1055 bool processed
= GetEventHandler()->ProcessEvent(event
);
1056 *result
= !event
.IsAllowed();
1060 #endif // wxUSE_NOTEBOOK