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
)
98 EVT_SIZE(wxNotebook::OnSize
)
100 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
103 #if wxUSE_EXTENDED_RTTI
104 WX_DEFINE_FLAGS( wxNotebookStyle
)
106 wxBEGIN_FLAGS( wxNotebookStyle
)
107 // new style border flags, we put them first to
108 // use them for streaming out
109 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
110 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
111 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
112 wxFLAGS_MEMBER(wxBORDER_RAISED
)
113 wxFLAGS_MEMBER(wxBORDER_STATIC
)
114 wxFLAGS_MEMBER(wxBORDER_NONE
)
116 // old style border flags
117 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
118 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
119 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
120 wxFLAGS_MEMBER(wxRAISED_BORDER
)
121 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
122 wxFLAGS_MEMBER(wxBORDER
)
124 // standard window styles
125 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
126 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
127 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
128 wxFLAGS_MEMBER(wxWANTS_CHARS
)
129 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
130 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
131 wxFLAGS_MEMBER(wxVSCROLL
)
132 wxFLAGS_MEMBER(wxHSCROLL
)
134 wxFLAGS_MEMBER(wxNB_FIXEDWIDTH
)
135 wxFLAGS_MEMBER(wxNB_LEFT
)
136 wxFLAGS_MEMBER(wxNB_RIGHT
)
137 wxFLAGS_MEMBER(wxNB_BOTTOM
)
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
) )
302 WXDWORD
wxNotebook::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
304 WXDWORD tabStyle
= wxControl::MSWGetStyle(style
, exstyle
);
306 tabStyle
|= WS_TABSTOP
| TCS_TABS
;
308 if ( style
& wxNB_MULTILINE
)
309 tabStyle
|= TCS_MULTILINE
;
310 if ( style
& wxNB_FIXEDWIDTH
)
311 tabStyle
|= TCS_FIXEDWIDTH
;
313 if ( style
& wxNB_BOTTOM
)
314 tabStyle
|= TCS_RIGHT
;
315 else if ( style
& wxNB_LEFT
)
316 tabStyle
|= TCS_VERTICAL
;
317 else if ( style
& wxNB_RIGHT
)
318 tabStyle
|= TCS_VERTICAL
| TCS_RIGHT
;
323 // note that we never want to have the default WS_EX_CLIENTEDGE style
324 // as it looks too ugly for the notebooks
331 wxNotebook::~wxNotebook()
334 if ( m_hbrBackground
)
335 ::DeleteObject((HBRUSH
)m_hbrBackground
);
336 #endif // wxUSE_UXTHEME
339 // ----------------------------------------------------------------------------
340 // wxNotebook accessors
341 // ----------------------------------------------------------------------------
343 size_t wxNotebook::GetPageCount() const
346 wxASSERT( (int)m_pages
.Count() == TabCtrl_GetItemCount(m_hwnd
) );
348 return m_pages
.Count();
351 int wxNotebook::GetRowCount() const
353 return TabCtrl_GetRowCount(m_hwnd
);
356 int wxNotebook::SetSelection(size_t nPage
)
358 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
360 if ( int(nPage
) != m_nSelection
)
362 wxNotebookEvent
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, m_windowId
);
363 event
.SetSelection(nPage
);
364 event
.SetOldSelection(m_nSelection
);
365 event
.SetEventObject(this);
366 if ( !GetEventHandler()->ProcessEvent(event
) || event
.IsAllowed() )
368 // program allows the page change
369 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
370 (void)GetEventHandler()->ProcessEvent(event
);
372 TabCtrl_SetCurSel(m_hwnd
, nPage
);
379 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
)
381 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
384 tcItem
.mask
= TCIF_TEXT
;
385 tcItem
.pszText
= (wxChar
*)strText
.c_str();
387 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
390 wxString
wxNotebook::GetPageText(size_t nPage
) const
392 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") );
396 tcItem
.mask
= TCIF_TEXT
;
397 tcItem
.pszText
= buf
;
398 tcItem
.cchTextMax
= WXSIZEOF(buf
);
401 if ( TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) )
402 str
= tcItem
.pszText
;
407 int wxNotebook::GetPageImage(size_t nPage
) const
409 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
412 tcItem
.mask
= TCIF_IMAGE
;
414 return TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) ? tcItem
.iImage
: -1;
417 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
)
419 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
422 tcItem
.mask
= TCIF_IMAGE
;
423 tcItem
.iImage
= nImage
;
425 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
428 void wxNotebook::SetImageList(wxImageList
* imageList
)
430 wxNotebookBase::SetImageList(imageList
);
434 TabCtrl_SetImageList(m_hwnd
, (HIMAGELIST
)imageList
->GetHIMAGELIST());
438 // ----------------------------------------------------------------------------
439 // wxNotebook size settings
440 // ----------------------------------------------------------------------------
442 void wxNotebook::SetPageSize(const wxSize
& size
)
444 // transform the page size into the notebook size
451 TabCtrl_AdjustRect(GetHwnd(), true, &rc
);
454 SetSize(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
457 void wxNotebook::SetPadding(const wxSize
& padding
)
459 TabCtrl_SetPadding(GetHwnd(), padding
.x
, padding
.y
);
462 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
464 void wxNotebook::SetTabSize(const wxSize
& sz
)
466 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE
, 0, MAKELPARAM(sz
.x
, sz
.y
));
469 wxSize
wxNotebook::CalcSizeFromPage(const wxSize
& sizePage
) const
471 wxSize sizeTotal
= sizePage
;
473 // We need to make getting tab size part of the wxWidgets API.
474 wxSize
tabSize(0, 0);
475 if (GetPageCount() > 0)
478 TabCtrl_GetItemRect((HWND
) GetHWND(), 0, & rect
);
479 tabSize
.x
= rect
.right
- rect
.left
;
480 tabSize
.y
= rect
.bottom
- rect
.top
;
482 if ( HasFlag(wxNB_LEFT
) || HasFlag(wxNB_RIGHT
) )
484 sizeTotal
.x
+= tabSize
.x
+ 7;
490 sizeTotal
.y
+= tabSize
.y
+ 7;
496 void wxNotebook::AdjustPageSize(wxNotebookPage
*page
)
498 wxCHECK_RET( page
, _T("NULL page in wxNotebook::AdjustPageSize") );
504 // get the page size from the notebook size
505 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
507 // This check is to work around a bug in TabCtrl_AdjustRect which will
508 // cause a crash on win2k, or on XP with themes disabled, if the
509 // wxNB_MULTILINE style is used and the rectangle is very small, (such as
510 // when the notebook is first created.) The value of 20 is just
511 // arbitrarily chosen, if there is a better way to determine this value
512 // then please do so. --RD
513 if (rc
.right
> 20 && rc
.bottom
> 20)
515 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
516 page
->SetSize(rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
520 // ----------------------------------------------------------------------------
521 // wxNotebook operations
522 // ----------------------------------------------------------------------------
524 // remove one page from the notebook, without deleting
525 wxNotebookPage
*wxNotebook::DoRemovePage(size_t nPage
)
527 wxNotebookPage
*pageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
531 TabCtrl_DeleteItem(m_hwnd
, nPage
);
533 if ( m_pages
.IsEmpty() )
535 // no selection any more, the notebook becamse empty
538 else // notebook still not empty
540 int selNew
= TabCtrl_GetCurSel(m_hwnd
);
543 // No selection change, just refresh the current selection.
544 // Because it could be that the slection index changed
545 // we need to update it.
546 // Note: this does not mean the selection it self changed.
547 m_nSelection
= selNew
;
548 m_pages
[m_nSelection
]->Refresh();
550 else if (int(nPage
) == m_nSelection
)
552 // The selection was deleted.
554 // Determine new selection.
555 if (m_nSelection
== int(GetPageCount()))
556 selNew
= m_nSelection
- 1;
558 selNew
= m_nSelection
;
560 // m_nSelection must be always valid so reset it before calling
563 SetSelection(selNew
);
567 wxFAIL
; // Windows did not behave ok.
575 bool wxNotebook::DeleteAllPages()
577 size_t nPageCount
= GetPageCount();
579 for ( nPage
= 0; nPage
< nPageCount
; nPage
++ )
580 delete m_pages
[nPage
];
584 TabCtrl_DeleteAllItems(m_hwnd
);
588 InvalidateBestSize();
592 // same as AddPage() but does it at given position
593 bool wxNotebook::InsertPage(size_t nPage
,
594 wxNotebookPage
*pPage
,
595 const wxString
& strText
,
599 wxCHECK_MSG( pPage
!= NULL
, false, _T("NULL page in wxNotebook::InsertPage") );
600 wxCHECK_MSG( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false,
601 _T("invalid index in wxNotebook::InsertPage") );
603 wxASSERT_MSG( pPage
->GetParent() == this,
604 _T("notebook pages must have notebook as parent") );
606 // add a new tab to the control
607 // ----------------------------
609 // init all fields to 0
611 wxZeroMemory(tcItem
);
613 // set the image, if any
616 tcItem
.mask
|= TCIF_IMAGE
;
617 tcItem
.iImage
= imageId
;
621 if ( !strText
.IsEmpty() )
623 tcItem
.mask
|= TCIF_TEXT
;
624 tcItem
.pszText
= (wxChar
*)strText
.c_str(); // const_cast
627 // hide the page: unless it is selected, it shouldn't be shown (and if it
628 // is selected it will be shown later)
629 HWND hwnd
= GetWinHwnd(pPage
);
630 SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~WS_VISIBLE
);
632 // this updates internal flag too -- otherwise it would get out of sync
633 // with the real state
637 // fit the notebook page to the tab control's display area: this should be
638 // done before adding it to the notebook or TabCtrl_InsertItem() will
639 // change the notebooks size itself!
640 AdjustPageSize(pPage
);
642 // finally do insert it
643 if ( TabCtrl_InsertItem(m_hwnd
, nPage
, &tcItem
) == -1 )
645 wxLogError(wxT("Can't create the notebook page '%s'."), strText
.c_str());
650 // succeeded: save the pointer to the page
651 m_pages
.Insert(pPage
, nPage
);
653 // we may need to adjust the size again if the notebook size changed:
654 // normally this only happens for the first page we add (the tabs which
655 // hadn't been there before are now shown) but for a multiline notebook it
656 // can happen for any page at all as a new row could have been started
657 if ( m_pages
.GetCount() == 1 || HasFlag(wxNB_MULTILINE
) )
659 AdjustPageSize(pPage
);
662 // now deal with the selection
663 // ---------------------------
665 // if the inserted page is before the selected one, we must update the
666 // index of the selected page
667 if ( int(nPage
) <= m_nSelection
)
669 // one extra page added
673 // some page should be selected: either this one or the first one if there
674 // is still no selection
678 else if ( m_nSelection
== -1 )
682 SetSelection(selNew
);
684 InvalidateBestSize();
686 if (HasFlag(wxNB_NOPAGETHEME
) || (wxSystemOptions::HasOption(wxT("msw.notebook.themed-background")) &&
687 wxSystemOptions::GetOptionInt(wxT("msw.notebook.themed-background")) == 0))
689 wxColour col
= GetThemeBackgroundColour();
692 pPage
->SetBackgroundColour(col
);
699 int wxNotebook::HitTest(const wxPoint
& pt
, long *flags
) const
701 TC_HITTESTINFO hitTestInfo
;
702 hitTestInfo
.pt
.x
= pt
.x
;
703 hitTestInfo
.pt
.y
= pt
.y
;
704 int item
= TabCtrl_HitTest(GetHwnd(), &hitTestInfo
);
710 if ((hitTestInfo
.flags
& TCHT_NOWHERE
) == TCHT_NOWHERE
)
711 *flags
|= wxNB_HITTEST_NOWHERE
;
712 if ((hitTestInfo
.flags
& TCHT_ONITEM
) == TCHT_ONITEM
)
713 *flags
|= wxNB_HITTEST_ONITEM
;
714 if ((hitTestInfo
.flags
& TCHT_ONITEMICON
) == TCHT_ONITEMICON
)
715 *flags
|= wxNB_HITTEST_ONICON
;
716 if ((hitTestInfo
.flags
& TCHT_ONITEMLABEL
) == TCHT_ONITEMLABEL
)
717 *flags
|= wxNB_HITTEST_ONLABEL
;
724 // ----------------------------------------------------------------------------
725 // wxNotebook callbacks
726 // ----------------------------------------------------------------------------
728 void wxNotebook::OnSize(wxSizeEvent
& event
)
730 // update the background brush
733 #endif // wxUSE_UXTHEME
735 // fit all the notebook pages to the tab control's display area
738 rc
.left
= rc
.top
= 0;
739 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
741 // save the total size, we'll use it below
742 int widthNbook
= rc
.right
- rc
.left
,
743 heightNbook
= rc
.bottom
- rc
.top
;
745 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
746 // returns completely false values for multiline tab controls after the tabs
747 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
749 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
751 // and the only work around I could find was this ugly hack... without it
752 // simply toggling the "multiline" checkbox in the notebook sample resulted
753 // in a noticeable page displacement
754 if ( HasFlag(wxNB_MULTILINE
) )
756 // avoid an infinite recursion: we get another notification too!
757 static bool s_isInOnSize
= false;
762 SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
,
763 MAKELPARAM(rc
.right
, rc
.bottom
));
764 s_isInOnSize
= false;
768 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
770 int width
= rc
.right
- rc
.left
,
771 height
= rc
.bottom
- rc
.top
;
772 size_t nCount
= m_pages
.Count();
773 for ( size_t nPage
= 0; nPage
< nCount
; nPage
++ ) {
774 wxNotebookPage
*pPage
= m_pages
[nPage
];
775 pPage
->SetSize(rc
.left
, rc
.top
, width
, height
);
779 // unless we had already repainted everything, we now need to refresh
780 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
782 // invalidate areas not covered by pages
783 RefreshRect(wxRect(0, 0, widthNbook
, rc
.top
), false);
784 RefreshRect(wxRect(0, rc
.top
, rc
.left
, height
), false);
785 RefreshRect(wxRect(0, rc
.bottom
, widthNbook
, heightNbook
- rc
.bottom
),
787 RefreshRect(wxRect(rc
.right
, rc
.top
, widthNbook
- rc
.bottom
, height
),
794 void wxNotebook::OnSelChange(wxNotebookEvent
& event
)
796 // is it our tab control?
797 if ( event
.GetEventObject() == this )
799 int sel
= event
.GetOldSelection();
801 m_pages
[sel
]->Show(false);
803 sel
= event
.GetSelection();
806 wxNotebookPage
*pPage
= m_pages
[sel
];
810 // If the newly focused window is not a child of the new page,
811 // SetFocus was not successful and the notebook itself should be
813 wxWindow
*currentFocus
= FindFocus();
814 wxWindow
*startFocus
= currentFocus
;
815 while ( currentFocus
&& currentFocus
!= pPage
&& currentFocus
!= this )
816 currentFocus
= currentFocus
->GetParent();
818 if ( startFocus
== pPage
|| currentFocus
!= pPage
)
822 else // no pages in the notebook, give the focus to itself
830 // we want to give others a chance to process this message as well
834 bool wxNotebook::MSWTranslateMessage(WXMSG
*wxmsg
)
836 const MSG
* const msg
= (MSG
*)wxmsg
;
838 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
839 // TAB will be passed to the currently selected page, CTRL+TAB and
840 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
841 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
843 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_TAB
&&
844 msg
->hwnd
== m_hwnd
&&
845 (wxIsCtrlDown() || !wxIsShiftDown()) )
847 return MSWProcessMessage(wxmsg
);
853 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
)
855 if ( event
.IsWindowChange() ) {
857 AdvanceSelection(event
.GetDirection());
860 // we get this event in 3 cases
862 // a) one of our pages might have generated it because the user TABbed
863 // out from it in which case we should propagate the event upwards and
864 // our parent will take care of setting the focus to prev/next sibling
868 // b) the parent panel wants to give the focus to us so that we
869 // forward it to our selected page. We can't deal with this in
870 // OnSetFocus() because we don't know which direction the focus came
871 // from in this case and so can't choose between setting the focus to
872 // first or last panel child
876 // c) we ourselves (see MSWTranslateMessage) generated the event
878 wxWindow
* const parent
= GetParent();
880 const bool isFromParent
= event
.GetEventObject() == parent
;
881 const bool isFromSelf
= event
.GetEventObject() == this;
883 if ( isFromParent
|| isFromSelf
)
885 // no, it doesn't come from child, case (b) or (c): forward to a
886 // page but only if direction is backwards (TAB) or from ourselves,
887 if ( m_nSelection
!= -1 &&
888 (!event
.GetDirection() || isFromSelf
) )
890 // so that the page knows that the event comes from it's parent
891 // and is being propagated downwards
892 event
.SetEventObject(this);
894 wxWindow
*page
= m_pages
[m_nSelection
];
895 if ( !page
->GetEventHandler()->ProcessEvent(event
) )
899 //else: page manages focus inside it itself
901 else // otherwise set the focus to the notebook itself
908 // it comes from our child, case (a), pass to the parent, but only
909 // if the direction is forwards. Otherwise set the focus to the
910 // notebook itself. The notebook is always the 'first' control of a
912 if ( !event
.GetDirection() )
918 event
.SetCurrentFocus(this);
919 parent
->GetEventHandler()->ProcessEvent(event
);
927 WXHANDLE
wxNotebook::QueryBgBitmap(wxWindow
*win
)
930 GetWindowRect(GetHwnd(), &rc
);
932 WindowHDC
hDC(GetHwnd());
933 MemoryHDC
hDCMem(hDC
);
934 CompatibleBitmap
hBmp(hDC
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
936 SelectInHDC
selectBmp(hDCMem
, hBmp
);
938 ::SendMessage(GetHwnd(), WM_PRINTCLIENT
,
940 PRF_ERASEBKGND
| PRF_CLIENT
| PRF_NONCLIENT
);
945 ::GetWindowRect(GetHwndOf(win
), &rc2
);
947 COLORREF c
= ::GetPixel(hDCMem
, rc2
.left
- rc
.left
, rc2
.top
- rc
.top
);
951 //else: we are asked to create the brush
953 return (WXHANDLE
)::CreatePatternBrush(hBmp
);
956 void wxNotebook::UpdateBgBrush()
958 if ( m_hbrBackground
)
959 ::DeleteObject((HBRUSH
)m_hbrBackground
);
961 if ( !m_hasBgCol
&& wxUxThemeEngine::GetIfActive() )
963 m_hbrBackground
= (WXHBRUSH
)QueryBgBitmap();
967 m_hbrBackground
= NULL
;
971 WXHBRUSH
wxNotebook::MSWGetBgBrushForChild(WXHDC hDC
, wxWindow
*win
)
973 if ( m_hbrBackground
)
975 // before drawing with the background brush, we need to position it
978 ::GetWindowRect(GetHwndOf(win
), &rc
);
980 ::MapWindowPoints(NULL
, GetHwnd(), (POINT
*)&rc
, 1);
982 if ( !::SetBrushOrgEx((HDC
)hDC
, -rc
.left
, -rc
.top
, NULL
) )
984 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
987 return m_hbrBackground
;
990 return wxNotebookBase::MSWGetBgBrushForChild(hDC
, win
);
993 wxColour
wxNotebook::MSWGetBgColourForChild(wxWindow
*win
)
996 return GetBackgroundColour();
998 if ( !wxUxThemeEngine::GetIfActive() )
1001 COLORREF c
= (COLORREF
)QueryBgBitmap(win
);
1003 return c
== CLR_INVALID
? wxNullColour
: wxRGBToColour(c
);
1006 #endif // wxUSE_UXTHEME
1008 // Windows only: attempts to get colour for UX theme page background
1009 wxColour
wxNotebook::GetThemeBackgroundColour() const
1012 if (wxUxThemeEngine::Get())
1014 wxUxThemeHandle
hTheme((wxNotebook
*) this, L
"TAB");
1017 // This is total guesswork.
1018 // See PlatformSDK\Include\Tmschema.h for values
1019 COLORREF themeColor
;
1020 wxUxThemeEngine::Get()->GetThemeColor(
1024 3821 /* FILLCOLORHINT */,
1028 [DS] Workaround for WindowBlinds:
1029 Some themes return a near black theme color using FILLCOLORHINT,
1030 this makes notebook pages have an ugly black background and makes
1031 text (usually black) unreadable. Retry again with FILLCOLOR.
1033 This workaround potentially breaks appearance of some themes,
1034 but in practice it already fixes some themes.
1036 if (themeColor
== 1)
1038 wxUxThemeEngine::Get()->GetThemeColor(
1042 3802 /* FILLCOLOR */,
1046 wxColour
colour(GetRValue(themeColor
), GetGValue(themeColor
), GetBValue(themeColor
));
1050 #endif // wxUSE_UXTHEME
1052 return GetBackgroundColour();
1055 // ----------------------------------------------------------------------------
1056 // wxNotebook base class virtuals
1057 // ----------------------------------------------------------------------------
1059 #if wxUSE_CONSTRAINTS
1061 // override these 2 functions to do nothing: everything is done in OnSize
1063 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
))
1065 // don't set the sizes of the pages - their correct size is not yet known
1066 wxControl::SetConstraintSizes(false);
1069 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
))
1074 #endif // wxUSE_CONSTRAINTS
1076 // ----------------------------------------------------------------------------
1077 // wxNotebook Windows message handlers
1078 // ----------------------------------------------------------------------------
1080 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
,
1081 WXWORD pos
, WXHWND control
)
1083 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1088 return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
);
1091 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
)
1093 wxNotebookEvent
event(wxEVT_NULL
, m_windowId
);
1095 NMHDR
* hdr
= (NMHDR
*)lParam
;
1096 switch ( hdr
->code
) {
1098 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
1101 case TCN_SELCHANGING
:
1102 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
);
1106 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1109 event
.SetSelection(TabCtrl_GetCurSel(m_hwnd
));
1110 event
.SetOldSelection(m_nSelection
);
1111 event
.SetEventObject(this);
1112 event
.SetInt(idCtrl
);
1114 bool processed
= GetEventHandler()->ProcessEvent(event
);
1115 *result
= !event
.IsAllowed();
1119 #endif // wxUSE_NOTEBOOK