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
) )
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
);
311 WXDWORD
wxNotebook::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
313 WXDWORD tabStyle
= wxControl::MSWGetStyle(style
, exstyle
);
315 tabStyle
|= WS_TABSTOP
| TCS_TABS
;
317 if ( style
& wxNB_MULTILINE
)
318 tabStyle
|= TCS_MULTILINE
;
319 if ( style
& wxNB_FIXEDWIDTH
)
320 tabStyle
|= TCS_FIXEDWIDTH
;
322 if ( style
& wxNB_BOTTOM
)
323 tabStyle
|= TCS_RIGHT
;
324 else if ( style
& wxNB_LEFT
)
325 tabStyle
|= TCS_VERTICAL
;
326 else if ( style
& wxNB_RIGHT
)
327 tabStyle
|= TCS_VERTICAL
| TCS_RIGHT
;
332 // note that we never want to have the default WS_EX_CLIENTEDGE style
333 // as it looks too ugly for the notebooks
340 wxNotebook::~wxNotebook()
343 if ( m_hbrBackground
)
344 ::DeleteObject((HBRUSH
)m_hbrBackground
);
345 #endif // wxUSE_UXTHEME
348 // ----------------------------------------------------------------------------
349 // wxNotebook accessors
350 // ----------------------------------------------------------------------------
352 size_t wxNotebook::GetPageCount() const
355 wxASSERT( (int)m_pages
.Count() == TabCtrl_GetItemCount(m_hwnd
) );
357 return m_pages
.Count();
360 int wxNotebook::GetRowCount() const
362 return TabCtrl_GetRowCount(m_hwnd
);
365 int wxNotebook::SetSelection(size_t nPage
)
367 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
369 if ( int(nPage
) != m_nSelection
)
371 wxNotebookEvent
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
, m_windowId
);
372 event
.SetSelection(nPage
);
373 event
.SetOldSelection(m_nSelection
);
374 event
.SetEventObject(this);
375 if ( !GetEventHandler()->ProcessEvent(event
) || event
.IsAllowed() )
377 // program allows the page change
378 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
379 (void)GetEventHandler()->ProcessEvent(event
);
381 TabCtrl_SetCurSel(m_hwnd
, nPage
);
388 bool wxNotebook::SetPageText(size_t nPage
, const wxString
& strText
)
390 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
393 tcItem
.mask
= TCIF_TEXT
;
394 tcItem
.pszText
= (wxChar
*)strText
.c_str();
396 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
399 wxString
wxNotebook::GetPageText(size_t nPage
) const
401 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") );
405 tcItem
.mask
= TCIF_TEXT
;
406 tcItem
.pszText
= buf
;
407 tcItem
.cchTextMax
= WXSIZEOF(buf
);
410 if ( TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) )
411 str
= tcItem
.pszText
;
416 int wxNotebook::GetPageImage(size_t nPage
) const
418 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
421 tcItem
.mask
= TCIF_IMAGE
;
423 return TabCtrl_GetItem(m_hwnd
, nPage
, &tcItem
) ? tcItem
.iImage
: -1;
426 bool wxNotebook::SetPageImage(size_t nPage
, int nImage
)
428 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
431 tcItem
.mask
= TCIF_IMAGE
;
432 tcItem
.iImage
= nImage
;
434 return TabCtrl_SetItem(m_hwnd
, nPage
, &tcItem
) != 0;
437 void wxNotebook::SetImageList(wxImageList
* imageList
)
439 wxNotebookBase::SetImageList(imageList
);
443 TabCtrl_SetImageList(m_hwnd
, (HIMAGELIST
)imageList
->GetHIMAGELIST());
447 // ----------------------------------------------------------------------------
448 // wxNotebook size settings
449 // ----------------------------------------------------------------------------
451 void wxNotebook::SetPageSize(const wxSize
& size
)
453 // transform the page size into the notebook size
460 TabCtrl_AdjustRect(GetHwnd(), true, &rc
);
463 SetSize(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
466 void wxNotebook::SetPadding(const wxSize
& padding
)
468 TabCtrl_SetPadding(GetHwnd(), padding
.x
, padding
.y
);
471 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
473 void wxNotebook::SetTabSize(const wxSize
& sz
)
475 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE
, 0, MAKELPARAM(sz
.x
, sz
.y
));
478 wxSize
wxNotebook::CalcSizeFromPage(const wxSize
& sizePage
) const
480 wxSize sizeTotal
= sizePage
;
482 // We need to make getting tab size part of the wxWidgets API.
484 if (GetPageCount() > 0)
487 TabCtrl_GetItemRect((HWND
) GetHWND(), 0, & rect
);
488 tabSize
.x
= rect
.right
- rect
.left
;
489 tabSize
.y
= rect
.bottom
- rect
.top
;
491 if ( HasFlag(wxNB_LEFT
) || HasFlag(wxNB_RIGHT
) )
493 sizeTotal
.x
+= tabSize
.x
+ 7;
499 sizeTotal
.y
+= tabSize
.y
+ 7;
505 void wxNotebook::AdjustPageSize(wxNotebookPage
*page
)
507 wxCHECK_RET( page
, _T("NULL page in wxNotebook::AdjustPageSize") );
513 // get the page size from the notebook size
514 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
516 // This check is to work around a bug in TabCtrl_AdjustRect which will
517 // cause a crash on win2k, or on XP with themes disabled, if the
518 // wxNB_MULTILINE style is used and the rectangle is very small, (such as
519 // when the notebook is first created.) The value of 20 is just
520 // arbitrarily chosen, if there is a better way to determine this value
521 // then please do so. --RD
522 if (rc
.right
> 20 && rc
.bottom
> 20)
524 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
525 page
->SetSize(rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
529 // ----------------------------------------------------------------------------
530 // wxNotebook operations
531 // ----------------------------------------------------------------------------
533 // remove one page from the notebook, without deleting
534 wxNotebookPage
*wxNotebook::DoRemovePage(size_t nPage
)
536 wxNotebookPage
*pageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
540 TabCtrl_DeleteItem(m_hwnd
, nPage
);
542 if ( m_pages
.IsEmpty() )
544 // no selection any more, the notebook becamse empty
547 else // notebook still not empty
549 int selNew
= TabCtrl_GetCurSel(m_hwnd
);
552 // No selection change, just refresh the current selection.
553 // Because it could be that the slection index changed
554 // we need to update it.
555 // Note: this does not mean the selection it self changed.
556 m_nSelection
= selNew
;
557 m_pages
[m_nSelection
]->Refresh();
559 else if (int(nPage
) == m_nSelection
)
561 // The selection was deleted.
563 // Determine new selection.
564 if (m_nSelection
== int(GetPageCount()))
565 selNew
= m_nSelection
- 1;
567 selNew
= m_nSelection
;
569 // m_nSelection must be always valid so reset it before calling
572 SetSelection(selNew
);
576 wxFAIL
; // Windows did not behave ok.
584 bool wxNotebook::DeleteAllPages()
586 size_t nPageCount
= GetPageCount();
588 for ( nPage
= 0; nPage
< nPageCount
; nPage
++ )
589 delete m_pages
[nPage
];
593 TabCtrl_DeleteAllItems(m_hwnd
);
597 InvalidateBestSize();
601 // same as AddPage() but does it at given position
602 bool wxNotebook::InsertPage(size_t nPage
,
603 wxNotebookPage
*pPage
,
604 const wxString
& strText
,
608 wxCHECK_MSG( pPage
!= NULL
, false, _T("NULL page in wxNotebook::InsertPage") );
609 wxCHECK_MSG( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false,
610 _T("invalid index in wxNotebook::InsertPage") );
612 wxASSERT_MSG( pPage
->GetParent() == this,
613 _T("notebook pages must have notebook as parent") );
615 // add a new tab to the control
616 // ----------------------------
618 // init all fields to 0
620 wxZeroMemory(tcItem
);
622 // set the image, if any
625 tcItem
.mask
|= TCIF_IMAGE
;
626 tcItem
.iImage
= imageId
;
630 if ( !strText
.empty() )
632 tcItem
.mask
|= TCIF_TEXT
;
633 tcItem
.pszText
= (wxChar
*)strText
.c_str(); // const_cast
636 // hide the page: unless it is selected, it shouldn't be shown (and if it
637 // is selected it will be shown later)
638 HWND hwnd
= GetWinHwnd(pPage
);
639 SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~WS_VISIBLE
);
641 // this updates internal flag too -- otherwise it would get out of sync
642 // with the real state
646 // fit the notebook page to the tab control's display area: this should be
647 // done before adding it to the notebook or TabCtrl_InsertItem() will
648 // change the notebooks size itself!
649 AdjustPageSize(pPage
);
651 // finally do insert it
652 if ( TabCtrl_InsertItem(m_hwnd
, nPage
, &tcItem
) == -1 )
654 wxLogError(wxT("Can't create the notebook page '%s'."), strText
.c_str());
659 // succeeded: save the pointer to the page
660 m_pages
.Insert(pPage
, nPage
);
662 // we may need to adjust the size again if the notebook size changed:
663 // normally this only happens for the first page we add (the tabs which
664 // hadn't been there before are now shown) but for a multiline notebook it
665 // can happen for any page at all as a new row could have been started
666 if ( m_pages
.GetCount() == 1 || HasFlag(wxNB_MULTILINE
) )
668 AdjustPageSize(pPage
);
671 // now deal with the selection
672 // ---------------------------
674 // if the inserted page is before the selected one, we must update the
675 // index of the selected page
676 if ( int(nPage
) <= m_nSelection
)
678 // one extra page added
682 // some page should be selected: either this one or the first one if there
683 // is still no selection
687 else if ( m_nSelection
== -1 )
691 SetSelection(selNew
);
693 InvalidateBestSize();
698 int wxNotebook::HitTest(const wxPoint
& pt
, long *flags
) const
700 TC_HITTESTINFO hitTestInfo
;
701 hitTestInfo
.pt
.x
= pt
.x
;
702 hitTestInfo
.pt
.y
= pt
.y
;
703 int item
= TabCtrl_HitTest(GetHwnd(), &hitTestInfo
);
709 if ((hitTestInfo
.flags
& TCHT_NOWHERE
) == TCHT_NOWHERE
)
710 *flags
|= wxNB_HITTEST_NOWHERE
;
711 if ((hitTestInfo
.flags
& TCHT_ONITEM
) == TCHT_ONITEM
)
712 *flags
|= wxNB_HITTEST_ONITEM
;
713 if ((hitTestInfo
.flags
& TCHT_ONITEMICON
) == TCHT_ONITEMICON
)
714 *flags
|= wxNB_HITTEST_ONICON
;
715 if ((hitTestInfo
.flags
& TCHT_ONITEMLABEL
) == TCHT_ONITEMLABEL
)
716 *flags
|= wxNB_HITTEST_ONLABEL
;
723 // ----------------------------------------------------------------------------
724 // wxNotebook callbacks
725 // ----------------------------------------------------------------------------
727 void wxNotebook::OnSize(wxSizeEvent
& event
)
729 // update the background brush
732 #endif // wxUSE_UXTHEME
734 // fit all the notebook pages to the tab control's display area
737 rc
.left
= rc
.top
= 0;
738 GetSize((int *)&rc
.right
, (int *)&rc
.bottom
);
740 // save the total size, we'll use it below
741 int widthNbook
= rc
.right
- rc
.left
,
742 heightNbook
= rc
.bottom
- rc
.top
;
744 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
745 // returns completely false values for multiline tab controls after the tabs
746 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
748 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
750 // and the only work around I could find was this ugly hack... without it
751 // simply toggling the "multiline" checkbox in the notebook sample resulted
752 // in a noticeable page displacement
753 if ( HasFlag(wxNB_MULTILINE
) )
755 // avoid an infinite recursion: we get another notification too!
756 static bool s_isInOnSize
= false;
761 SendMessage(GetHwnd(), WM_SIZE
, SIZE_RESTORED
,
762 MAKELPARAM(rc
.right
, rc
.bottom
));
763 s_isInOnSize
= false;
767 TabCtrl_AdjustRect(m_hwnd
, false, &rc
);
769 int width
= rc
.right
- rc
.left
,
770 height
= rc
.bottom
- rc
.top
;
771 size_t nCount
= m_pages
.Count();
772 for ( size_t nPage
= 0; nPage
< nCount
; nPage
++ ) {
773 wxNotebookPage
*pPage
= m_pages
[nPage
];
774 pPage
->SetSize(rc
.left
, rc
.top
, width
, height
);
778 // unless we had already repainted everything, we now need to refresh
779 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
781 // invalidate areas not covered by pages
782 RefreshRect(wxRect(0, 0, widthNbook
, rc
.top
), false);
783 RefreshRect(wxRect(0, rc
.top
, rc
.left
, height
), false);
784 RefreshRect(wxRect(0, rc
.bottom
, widthNbook
, heightNbook
- rc
.bottom
),
786 RefreshRect(wxRect(rc
.right
, rc
.top
, widthNbook
- rc
.bottom
, height
),
793 void wxNotebook::OnSelChange(wxNotebookEvent
& event
)
795 // is it our tab control?
796 if ( event
.GetEventObject() == this )
798 int sel
= event
.GetOldSelection();
800 m_pages
[sel
]->Show(false);
802 sel
= event
.GetSelection();
805 wxNotebookPage
*pPage
= m_pages
[sel
];
809 // If the newly focused window is not a child of the new page,
810 // SetFocus was not successful and the notebook itself should be
812 wxWindow
*currentFocus
= FindFocus();
813 wxWindow
*startFocus
= currentFocus
;
814 while ( currentFocus
&& currentFocus
!= pPage
&& currentFocus
!= this )
815 currentFocus
= currentFocus
->GetParent();
817 if ( startFocus
== pPage
|| currentFocus
!= pPage
)
821 else // no pages in the notebook, give the focus to itself
829 // we want to give others a chance to process this message as well
833 bool wxNotebook::MSWTranslateMessage(WXMSG
*wxmsg
)
835 const MSG
* const msg
= (MSG
*)wxmsg
;
837 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
838 // TAB will be passed to the currently selected page, CTRL+TAB and
839 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
840 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
842 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_TAB
&&
843 msg
->hwnd
== m_hwnd
&&
844 (wxIsCtrlDown() || !wxIsShiftDown()) )
846 return MSWProcessMessage(wxmsg
);
852 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
)
854 if ( event
.IsWindowChange() ) {
856 AdvanceSelection(event
.GetDirection());
859 // we get this event in 3 cases
861 // a) one of our pages might have generated it because the user TABbed
862 // out from it in which case we should propagate the event upwards and
863 // our parent will take care of setting the focus to prev/next sibling
867 // b) the parent panel wants to give the focus to us so that we
868 // forward it to our selected page. We can't deal with this in
869 // OnSetFocus() because we don't know which direction the focus came
870 // from in this case and so can't choose between setting the focus to
871 // first or last panel child
875 // c) we ourselves (see MSWTranslateMessage) generated the event
877 wxWindow
* const parent
= GetParent();
879 const bool isFromParent
= event
.GetEventObject() == parent
;
880 const bool isFromSelf
= event
.GetEventObject() == this;
882 if ( isFromParent
|| isFromSelf
)
884 // no, it doesn't come from child, case (b) or (c): forward to a
885 // page but only if direction is backwards (TAB) or from ourselves,
886 if ( m_nSelection
!= -1 &&
887 (!event
.GetDirection() || isFromSelf
) )
889 // so that the page knows that the event comes from it's parent
890 // and is being propagated downwards
891 event
.SetEventObject(this);
893 wxWindow
*page
= m_pages
[m_nSelection
];
894 if ( !page
->GetEventHandler()->ProcessEvent(event
) )
898 //else: page manages focus inside it itself
900 else // otherwise set the focus to the notebook itself
907 // it comes from our child, case (a), pass to the parent, but only
908 // if the direction is forwards. Otherwise set the focus to the
909 // notebook itself. The notebook is always the 'first' control of a
911 if ( !event
.GetDirection() )
917 event
.SetCurrentFocus(this);
918 parent
->GetEventHandler()->ProcessEvent(event
);
926 WXHANDLE
wxNotebook::QueryBgBitmap(wxWindow
*win
)
929 GetWindowRect(GetHwnd(), &rc
);
931 WindowHDC
hDC(GetHwnd());
932 MemoryHDC
hDCMem(hDC
);
933 CompatibleBitmap
hBmp(hDC
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
935 SelectInHDC
selectBmp(hDCMem
, hBmp
);
937 ::SendMessage(GetHwnd(), WM_PRINTCLIENT
,
939 PRF_ERASEBKGND
| PRF_CLIENT
| PRF_NONCLIENT
);
944 ::GetWindowRect(GetHwndOf(win
), &rc2
);
946 COLORREF c
= ::GetPixel(hDCMem
, rc2
.left
- rc
.left
, rc2
.top
- rc
.top
);
950 //else: we are asked to create the brush
952 return (WXHANDLE
)::CreatePatternBrush(hBmp
);
955 void wxNotebook::UpdateBgBrush()
957 if ( m_hbrBackground
)
958 ::DeleteObject((HBRUSH
)m_hbrBackground
);
960 if ( !m_hasBgCol
&& wxUxThemeEngine::GetIfActive() )
962 m_hbrBackground
= (WXHBRUSH
)QueryBgBitmap();
966 m_hbrBackground
= NULL
;
970 WXHBRUSH
wxNotebook::MSWGetBgBrushForChild(WXHDC hDC
, wxWindow
*win
)
972 if ( m_hbrBackground
)
974 // before drawing with the background brush, we need to position it
977 ::GetWindowRect(GetHwndOf(win
), &rc
);
979 ::MapWindowPoints(NULL
, GetHwnd(), (POINT
*)&rc
, 1);
981 if ( !::SetBrushOrgEx((HDC
)hDC
, -rc
.left
, -rc
.top
, NULL
) )
983 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
986 return m_hbrBackground
;
989 return wxNotebookBase::MSWGetBgBrushForChild(hDC
, win
);
992 wxColour
wxNotebook::MSWGetBgColourForChild(wxWindow
*win
)
995 return GetBackgroundColour();
997 if ( !wxUxThemeEngine::GetIfActive() )
1000 COLORREF c
= (COLORREF
)QueryBgBitmap(win
);
1002 return c
== CLR_INVALID
? wxNullColour
: wxRGBToColour(c
);
1005 #endif // wxUSE_UXTHEME
1007 // Windows only: attempts to get colour for UX theme page background
1008 wxColour
wxNotebook::GetThemeBackgroundColour() const
1011 if (wxUxThemeEngine::Get())
1013 wxUxThemeHandle
hTheme((wxNotebook
*) this, L
"TAB");
1016 // This is total guesswork.
1017 // See PlatformSDK\Include\Tmschema.h for values
1018 COLORREF themeColor
;
1019 wxUxThemeEngine::Get()->GetThemeColor(
1023 3821 /* FILLCOLORHINT */,
1027 [DS] Workaround for WindowBlinds:
1028 Some themes return a near black theme color using FILLCOLORHINT,
1029 this makes notebook pages have an ugly black background and makes
1030 text (usually black) unreadable. Retry again with FILLCOLOR.
1032 This workaround potentially breaks appearance of some themes,
1033 but in practice it already fixes some themes.
1035 if (themeColor
== 1)
1037 wxUxThemeEngine::Get()->GetThemeColor(
1041 3802 /* FILLCOLOR */,
1045 wxColour
colour(GetRValue(themeColor
), GetGValue(themeColor
), GetBValue(themeColor
));
1049 #endif // wxUSE_UXTHEME
1051 return GetBackgroundColour();
1054 // ----------------------------------------------------------------------------
1055 // wxNotebook base class virtuals
1056 // ----------------------------------------------------------------------------
1058 #if wxUSE_CONSTRAINTS
1060 // override these 2 functions to do nothing: everything is done in OnSize
1062 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse
))
1064 // don't set the sizes of the pages - their correct size is not yet known
1065 wxControl::SetConstraintSizes(false);
1068 bool wxNotebook::DoPhase(int WXUNUSED(nPhase
))
1073 #endif // wxUSE_CONSTRAINTS
1075 // ----------------------------------------------------------------------------
1076 // wxNotebook Windows message handlers
1077 // ----------------------------------------------------------------------------
1079 bool wxNotebook::MSWOnScroll(int orientation
, WXWORD nSBCode
,
1080 WXWORD pos
, WXHWND control
)
1082 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1087 return wxNotebookBase::MSWOnScroll(orientation
, nSBCode
, pos
, control
);
1090 bool wxNotebook::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
* result
)
1092 wxNotebookEvent
event(wxEVT_NULL
, m_windowId
);
1094 NMHDR
* hdr
= (NMHDR
*)lParam
;
1095 switch ( hdr
->code
) {
1097 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
1100 case TCN_SELCHANGING
:
1101 event
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
);
1105 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1108 event
.SetSelection(TabCtrl_GetCurSel(m_hwnd
));
1109 event
.SetOldSelection(m_nSelection
);
1110 event
.SetEventObject(this);
1111 event
.SetInt(idCtrl
);
1113 bool processed
= GetEventHandler()->ProcessEvent(event
);
1114 *result
= !event
.IsAllowed();
1118 #endif // wxUSE_NOTEBOOK