]> git.saurik.com Git - wxWidgets.git/blame - src/msw/notebook.cpp
wxPopupTransientWindow::Popup no longer captures the mouse, so do it in
[wxWidgets.git] / src / msw / notebook.cpp
CommitLineData
88310e2e
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: msw/notebook.cpp
3// Purpose: implementation of wxNotebook
4// Author: Vadim Zeitlin
907f37b3 5// Modified by:
88310e2e
VZ
6// Created: 11.06.98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 9// Licence: wxWindows licence
88310e2e
VZ
10///////////////////////////////////////////////////////////////////////////////
11
14f355c2 12#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
a3b46648 13#pragma implementation "notebook.h"
88310e2e
VZ
14#endif
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
1e6feb95 20 #pragma hdrstop
88310e2e
VZ
21#endif
22
1e6feb95
VZ
23#if wxUSE_NOTEBOOK
24
77ffb593 25// wxWidgets
88310e2e 26#ifndef WX_PRECOMP
3096bd2f 27 #include "wx/string.h"
bb180f90 28 #include "wx/dc.h"
88310e2e
VZ
29#endif // WX_PRECOMP
30
3096bd2f
VZ
31#include "wx/log.h"
32#include "wx/imaglist.h"
33#include "wx/event.h"
34#include "wx/control.h"
35#include "wx/notebook.h"
04eb05b0 36#include "wx/app.h"
25057aba 37#include "wx/sysopt.h"
254fbd14
JS
38#include "wx/dcclient.h"
39#include "wx/dcmemory.h"
88310e2e 40
3096bd2f 41#include "wx/msw/private.h"
88310e2e 42
c1f3a149 43#include <windowsx.h>
aaab7c01 44
2cef71bc 45#include <commctrl.h>
88310e2e 46
85b43fbf
JS
47#include "wx/msw/winundef.h"
48
49#if wxUSE_UXTHEME
caf95d2a 50 #include "wx/msw/uxtheme.h"
85b43fbf
JS
51#endif
52
88310e2e
VZ
53// ----------------------------------------------------------------------------
54// macros
55// ----------------------------------------------------------------------------
56
57// check that the page index is valid
8d34bf5c 58#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount())
88310e2e
VZ
59
60// hide the ugly cast
61#define m_hwnd (HWND)GetHWND()
62
254fbd14
JS
63#ifdef __WXWINCE__
64#define USE_NOTEBOOK_ANTIFLICKER 0
65#else
66// Set this to 1 to compile anti-flicker code, which creates a potentially
67// large bitmap for every paint event
68#define USE_NOTEBOOK_ANTIFLICKER 0
69#endif
70
74b31181
VZ
71// ----------------------------------------------------------------------------
72// constants
73// ----------------------------------------------------------------------------
74
75// This is a work-around for missing defines in gcc-2.95 headers
76#ifndef TCS_RIGHT
77 #define TCS_RIGHT 0x0002
78#endif
79
80#ifndef TCS_VERTICAL
81 #define TCS_VERTICAL 0x0080
82#endif
83
84#ifndef TCS_BOTTOM
85 #define TCS_BOTTOM TCS_RIGHT
86#endif
87
88310e2e
VZ
88// ----------------------------------------------------------------------------
89// event table
90// ----------------------------------------------------------------------------
91
51741307
SC
92#include <wx/listimpl.cpp>
93
94WX_DEFINE_LIST( wxNotebookPageInfoList ) ;
95
2e4df4bf
VZ
96DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED)
97DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING)
98
d9317fd4 99BEGIN_EVENT_TABLE(wxNotebook, wxControl)
254fbd14
JS
100#if USE_NOTEBOOK_ANTIFLICKER
101 EVT_ERASE_BACKGROUND(wxNotebook::OnEraseBackground)
102 EVT_PAINT(wxNotebook::OnPaint)
103#endif
88310e2e 104 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange)
9026ad85 105 EVT_SIZE(wxNotebook::OnSize)
88310e2e 106 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
d9317fd4 107END_EVENT_TABLE()
88310e2e 108
51596bcb 109#if wxUSE_EXTENDED_RTTI
bc9fb572
JS
110WX_DEFINE_FLAGS( wxNotebookStyle )
111
3ff066a4 112wxBEGIN_FLAGS( wxNotebookStyle )
bc9fb572
JS
113 // new style border flags, we put them first to
114 // use them for streaming out
3ff066a4
SC
115 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
116 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
117 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
118 wxFLAGS_MEMBER(wxBORDER_RAISED)
119 wxFLAGS_MEMBER(wxBORDER_STATIC)
120 wxFLAGS_MEMBER(wxBORDER_NONE)
078cf5cb 121
bc9fb572 122 // old style border flags
3ff066a4
SC
123 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
124 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
125 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
126 wxFLAGS_MEMBER(wxRAISED_BORDER)
127 wxFLAGS_MEMBER(wxSTATIC_BORDER)
cb0afb26 128 wxFLAGS_MEMBER(wxBORDER)
bc9fb572
JS
129
130 // standard window styles
3ff066a4
SC
131 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
132 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
133 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
134 wxFLAGS_MEMBER(wxWANTS_CHARS)
cb0afb26 135 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
3ff066a4
SC
136 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
137 wxFLAGS_MEMBER(wxVSCROLL)
138 wxFLAGS_MEMBER(wxHSCROLL)
139
140 wxFLAGS_MEMBER(wxNB_FIXEDWIDTH)
141 wxFLAGS_MEMBER(wxNB_LEFT)
142 wxFLAGS_MEMBER(wxNB_RIGHT)
143 wxFLAGS_MEMBER(wxNB_BOTTOM)
b554cf63
JS
144 wxFLAGS_MEMBER(wxNB_NOPAGETHEME)
145 wxFLAGS_MEMBER(wxNB_FLAT)
3ff066a4
SC
146
147wxEND_FLAGS( wxNotebookStyle )
51741307 148
51596bcb 149IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebook, wxControl,"wx/notebook.h")
51741307
SC
150IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebookPageInfo, wxObject , "wx/notebook.h" )
151
3ff066a4 152wxCOLLECTION_TYPE_INFO( wxNotebookPageInfo * , wxNotebookPageInfoList ) ;
51596bcb 153
f0a126fe
SC
154template<> void wxCollectionToVariantArray( wxNotebookPageInfoList const &theList, wxxVariantArray &value)
155{
0c6b0084 156 wxListCollectionToVariantArray<wxNotebookPageInfoList::compatibility_iterator>( theList , value ) ;
f0a126fe
SC
157}
158
3ff066a4
SC
159wxBEGIN_PROPERTIES_TABLE(wxNotebook)
160 wxEVENT_PROPERTY( PageChanging , wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING , wxNotebookEvent )
161 wxEVENT_PROPERTY( PageChanged , wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED , wxNotebookEvent )
c5ca409b 162
3ff066a4 163 wxPROPERTY_COLLECTION( PageInfos , wxNotebookPageInfoList , wxNotebookPageInfo* , AddPageInfo , GetPageInfos , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
af498247 164 wxPROPERTY_FLAGS( WindowStyle , wxNotebookStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
3ff066a4 165wxEND_PROPERTIES_TABLE()
51596bcb 166
3ff066a4
SC
167wxBEGIN_HANDLERS_TABLE(wxNotebook)
168wxEND_HANDLERS_TABLE()
51596bcb 169
078cf5cb 170wxCONSTRUCTOR_5( wxNotebook , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle)
51596bcb 171
51741307 172
3ff066a4 173wxBEGIN_PROPERTIES_TABLE(wxNotebookPageInfo)
af498247 174 wxREADONLY_PROPERTY( Page , wxNotebookPage* , GetPage , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
3ff066a4
SC
175 wxREADONLY_PROPERTY( Text , wxString , GetText , wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
176 wxREADONLY_PROPERTY( Selected , bool , GetSelected , false, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
177 wxREADONLY_PROPERTY( ImageId , int , GetImageId , -1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
178wxEND_PROPERTIES_TABLE()
51741307 179
3ff066a4
SC
180wxBEGIN_HANDLERS_TABLE(wxNotebookPageInfo)
181wxEND_HANDLERS_TABLE()
51741307 182
078cf5cb 183wxCONSTRUCTOR_4( wxNotebookPageInfo , wxNotebookPage* , Page , wxString , Text , bool , Selected , int , ImageId )
51741307 184
51596bcb 185#else
d9317fd4 186IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
51741307 187IMPLEMENT_DYNAMIC_CLASS(wxNotebookPageInfo, wxObject )
51596bcb 188#endif
d9317fd4 189IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxNotifyEvent)
88310e2e 190
254fbd14
JS
191// ---------------------------------------------------------------------------
192// private functions
193// ---------------------------------------------------------------------------
194
195#if USE_NOTEBOOK_ANTIFLICKER
196// wnd proc for the spin button
197LRESULT APIENTRY _EXPORT wxNotebookSpinBtnWndProc(HWND hWnd,
198 UINT message,
199 WPARAM wParam,
200 LPARAM lParam);
201
202// ---------------------------------------------------------------------------
203// global vars
204// ---------------------------------------------------------------------------
205
206// the pointer to standard spin button wnd proc
207static WXFARPROC s_wndprocNotebookSpinBtn = (WXFARPROC)NULL;
208#endif
209
88310e2e
VZ
210// ============================================================================
211// implementation
212// ============================================================================
213
214// ----------------------------------------------------------------------------
215// wxNotebook construction
216// ----------------------------------------------------------------------------
217
51741307
SC
218const wxNotebookPageInfoList& wxNotebook::GetPageInfos() const
219{
220 wxNotebookPageInfoList* list = const_cast< wxNotebookPageInfoList* >( &m_pageInfos ) ;
221 WX_CLEAR_LIST( wxNotebookPageInfoList , *list ) ;
34a0c9f4 222 for( size_t i = 0 ; i < GetPageCount() ; ++i )
51741307
SC
223 {
224 wxNotebookPageInfo *info = new wxNotebookPageInfo() ;
34a0c9f4 225 info->Create( const_cast<wxNotebook*>(this)->GetPage(i) , GetPageText(i) , GetSelection() == int(i) , GetPageImage(i) ) ;
51741307
SC
226 list->Append( info ) ;
227 }
228 return m_pageInfos ;
229}
230
88310e2e
VZ
231// common part of all ctors
232void wxNotebook::Init()
233{
1e6feb95 234 m_imageList = NULL;
88310e2e 235 m_nSelection = -1;
caf95d2a
VZ
236
237#if wxUSE_UXTHEME
238 m_hbrBackground = NULL;
239#endif // wxUSE_UXTHEME
88310e2e
VZ
240}
241
242// default for dynamic class
243wxNotebook::wxNotebook()
244{
245 Init();
246}
247
248// the same arguments as for wxControl
249wxNotebook::wxNotebook(wxWindow *parent,
8b9518ee 250 wxWindowID id,
88310e2e
VZ
251 const wxPoint& pos,
252 const wxSize& size,
8b9518ee 253 long style,
88310e2e
VZ
254 const wxString& name)
255{
256 Init();
257
258 Create(parent, id, pos, size, style, name);
259}
260
261// Create() function
262bool wxNotebook::Create(wxWindow *parent,
8b9518ee 263 wxWindowID id,
88310e2e
VZ
264 const wxPoint& pos,
265 const wxSize& size,
8b9518ee 266 long style,
88310e2e
VZ
267 const wxString& name)
268{
45418059
JS
269#ifdef __WXWINCE__
270 // Not sure why, but without this style, there is no border
271 // around the notebook tabs.
272 if (style & wxNB_FLAT)
273 style |= wxBORDER_SUNKEN;
274#endif
c3732409 275
df10208f
VZ
276 // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the
277 // control is simply not rendered correctly), so disable them in this case
278 const int verComCtl32 = wxApp::GetComCtl32Version();
279 if ( verComCtl32 == 600 )
04eb05b0 280 {
df10208f
VZ
281 // check if we use themes at all -- if we don't, we're still ok
282#if wxUSE_UXTHEME
283 if ( wxUxThemeEngine::GetIfActive() )
284#endif
285 {
286 style &= ~(wxNB_BOTTOM | wxNB_LEFT | wxNB_RIGHT);
287 }
04eb05b0 288 }
078cf5cb 289
c1637c89
VZ
290 LPCTSTR className = WC_TABCONTROL;
291
292 // SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it
293 // causes horrible flicker when resizing notebook, so get rid of it by
294 // using a class without these styles (but otherwise identical to it)
295 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
296 {
297 static ClassRegistrar s_clsNotebook;
298 if ( !s_clsNotebook.IsInitialized() )
299 {
300 // get a copy of standard class and modify it
301 WNDCLASS wc;
302
303 if ( ::GetClassInfo(::GetModuleHandle(NULL), WC_TABCONTROL, &wc) )
304 {
305 wc.lpszClassName = wxT("_wx_SysTabCtl32");
306 wc.style &= ~(CS_HREDRAW | CS_VREDRAW);
307
308 s_clsNotebook.Register(wc);
309 }
310 else
311 {
312 wxLogLastError(_T("GetClassInfoEx(SysTabCtl32)"));
313 }
314 }
315
316 // use our custom class if available but fall back to the standard
317 // notebook if we failed to register it
318 if ( s_clsNotebook.IsRegistered() )
319 {
320 // it's ok to use c_str() here as the static s_clsNotebook object
321 // has sufficiently long lifetime
322 className = s_clsNotebook.GetName().c_str();
323 }
324 }
325
6dd16e4f
VZ
326 if ( !CreateControl(parent, id, pos, size, style | wxTAB_TRAVERSAL,
327 wxDefaultValidator, name) )
b8bdaa7c 328 return false;
88310e2e 329
c1637c89 330 if ( !MSWCreateControl(className, wxEmptyString, pos, size) )
b8bdaa7c 331 return false;
907f37b3 332
7dccdf81
VZ
333#if wxUSE_UXTHEME
334 if ( HasFlag(wxNB_NOPAGETHEME) ||
335 wxSystemOptions::IsFalse(wxT("msw.notebook.themed-background")) )
f2b7be7a 336 {
7dccdf81 337 SetBackgroundColour(GetThemeBackgroundColour());
f2b7be7a 338 }
7dccdf81 339#endif // wxUSE_UXTHEME
b554cf63
JS
340
341 // Undocumented hack to get flat notebook style
342 // In fact, we should probably only do this in some
343 // curcumstances, i.e. if we know we will have a border
344 // at the bottom (the tab control doesn't draw it itself)
345#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
346 if (HasFlag(wxNB_FLAT))
347 {
348 SendMessage(m_hwnd, CCM_SETVERSION, COMCTL32_VERSION, 0);
349 if (!m_hasBgCol)
350 SetBackgroundColour(*wxWHITE);
351 }
352#endif
b8bdaa7c 353 return true;
0df3fbd7
VZ
354}
355
356WXDWORD wxNotebook::MSWGetStyle(long style, WXDWORD *exstyle) const
357{
358 WXDWORD tabStyle = wxControl::MSWGetStyle(style, exstyle);
359
360 tabStyle |= WS_TABSTOP | TCS_TABS;
361
2b5f62a0 362 if ( style & wxNB_MULTILINE )
0df3fbd7
VZ
363 tabStyle |= TCS_MULTILINE;
364 if ( style & wxNB_FIXEDWIDTH )
365 tabStyle |= TCS_FIXEDWIDTH;
366
367 if ( style & wxNB_BOTTOM )
368 tabStyle |= TCS_RIGHT;
369 else if ( style & wxNB_LEFT )
370 tabStyle |= TCS_VERTICAL;
371 else if ( style & wxNB_RIGHT )
c3732409 372 tabStyle |= TCS_VERTICAL | TCS_RIGHT;
0df3fbd7
VZ
373
374 // ex style
375 if ( exstyle )
376 {
377 // note that we never want to have the default WS_EX_CLIENTEDGE style
378 // as it looks too ugly for the notebooks
379 *exstyle = 0;
380 }
381
382 return tabStyle;
88310e2e
VZ
383}
384
caf95d2a
VZ
385wxNotebook::~wxNotebook()
386{
387#if wxUSE_UXTHEME
388 if ( m_hbrBackground )
389 ::DeleteObject((HBRUSH)m_hbrBackground);
390#endif // wxUSE_UXTHEME
391}
392
88310e2e
VZ
393// ----------------------------------------------------------------------------
394// wxNotebook accessors
395// ----------------------------------------------------------------------------
07b8d7ec 396
8d34bf5c 397size_t wxNotebook::GetPageCount() const
88310e2e
VZ
398{
399 // consistency check
1e6feb95 400 wxASSERT( (int)m_pages.Count() == TabCtrl_GetItemCount(m_hwnd) );
88310e2e 401
1e6feb95 402 return m_pages.Count();
88310e2e
VZ
403}
404
405int wxNotebook::GetRowCount() const
406{
407 return TabCtrl_GetRowCount(m_hwnd);
408}
409
8d34bf5c 410int wxNotebook::SetSelection(size_t nPage)
88310e2e 411{
078cf5cb 412 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
88310e2e 413
34a0c9f4 414 if ( int(nPage) != m_nSelection )
2b5f62a0
VZ
415 {
416 wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_windowId);
417 event.SetSelection(nPage);
418 event.SetOldSelection(m_nSelection);
419 event.SetEventObject(this);
420 if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
421 {
422 // program allows the page change
423 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
424 (void)GetEventHandler()->ProcessEvent(event);
425
426 TabCtrl_SetCurSel(m_hwnd, nPage);
427 }
428 }
88310e2e 429
2b5f62a0 430 return m_nSelection;
88310e2e
VZ
431}
432
8d34bf5c 433bool wxNotebook::SetPageText(size_t nPage, const wxString& strText)
88310e2e 434{
b8bdaa7c 435 wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
88310e2e
VZ
436
437 TC_ITEM tcItem;
438 tcItem.mask = TCIF_TEXT;
837e5743 439 tcItem.pszText = (wxChar *)strText.c_str();
88310e2e
VZ
440
441 return TabCtrl_SetItem(m_hwnd, nPage, &tcItem) != 0;
442}
443
8d34bf5c 444wxString wxNotebook::GetPageText(size_t nPage) const
88310e2e 445{
fda7962d 446 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxEmptyString, wxT("notebook page out of range") );
88310e2e 447
837e5743 448 wxChar buf[256];
88310e2e
VZ
449 TC_ITEM tcItem;
450 tcItem.mask = TCIF_TEXT;
451 tcItem.pszText = buf;
452 tcItem.cchTextMax = WXSIZEOF(buf);
453
454 wxString str;
455 if ( TabCtrl_GetItem(m_hwnd, nPage, &tcItem) )
456 str = tcItem.pszText;
457
458 return str;
459}
460
8d34bf5c 461int wxNotebook::GetPageImage(size_t nPage) const
88310e2e 462{
223d09f6 463 wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") );
88310e2e
VZ
464
465 TC_ITEM tcItem;
466 tcItem.mask = TCIF_IMAGE;
467
468 return TabCtrl_GetItem(m_hwnd, nPage, &tcItem) ? tcItem.iImage : -1;
469}
470
8d34bf5c 471bool wxNotebook::SetPageImage(size_t nPage, int nImage)
88310e2e 472{
b8bdaa7c 473 wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
88310e2e
VZ
474
475 TC_ITEM tcItem;
476 tcItem.mask = TCIF_IMAGE;
477 tcItem.iImage = nImage;
478
479 return TabCtrl_SetItem(m_hwnd, nPage, &tcItem) != 0;
480}
481
482void wxNotebook::SetImageList(wxImageList* imageList)
907f37b3 483{
07b8d7ec
VZ
484 wxNotebookBase::SetImageList(imageList);
485
486 if ( imageList )
1e6feb95 487 {
07b8d7ec 488 TabCtrl_SetImageList(m_hwnd, (HIMAGELIST)imageList->GetHIMAGELIST());
1e6feb95 489 }
b656febd
VS
490}
491
d9506e77
VZ
492// ----------------------------------------------------------------------------
493// wxNotebook size settings
494// ----------------------------------------------------------------------------
495
c3732409
VZ
496wxRect wxNotebook::GetPageSize() const
497{
498 wxRect r;
499
500 RECT rc;
501 ::GetClientRect(GetHwnd(), &rc);
502
503 // This check is to work around a bug in TabCtrl_AdjustRect which will
504 // cause a crash on win2k, or on XP with themes disabled, if the
505 // wxNB_MULTILINE style is used and the rectangle is very small, (such as
506 // when the notebook is first created.) The value of 20 is just
507 // arbitrarily chosen, if there is a better way to determine this value
508 // then please do so. --RD
509 if ( !HasFlag(wxNB_MULTILINE) || (rc.right > 20 && rc.bottom > 20) )
510 {
511 TabCtrl_AdjustRect(m_hwnd, false, &rc);
512
513 wxCopyRECTToRect(rc, r);
514 }
515
516 return r;
517}
518
d9506e77
VZ
519void wxNotebook::SetPageSize(const wxSize& size)
520{
521 // transform the page size into the notebook size
522 RECT rc;
523 rc.left =
524 rc.top = 0;
525 rc.right = size.x;
526 rc.bottom = size.y;
527
b8bdaa7c 528 TabCtrl_AdjustRect(GetHwnd(), true, &rc);
d9506e77
VZ
529
530 // and now set it
531 SetSize(rc.right - rc.left, rc.bottom - rc.top);
532}
533
534void wxNotebook::SetPadding(const wxSize& padding)
535{
536 TabCtrl_SetPadding(GetHwnd(), padding.x, padding.y);
537}
42e69d6b
VZ
538
539// Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
540// style.
541void wxNotebook::SetTabSize(const wxSize& sz)
542{
543 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE, 0, MAKELPARAM(sz.x, sz.y));
544}
545
2ce7af35
JS
546wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
547{
548 wxSize sizeTotal = sizePage;
078cf5cb 549
77ffb593 550 // We need to make getting tab size part of the wxWidgets API.
8b5d5223 551 wxSize tabSize;
2ce7af35
JS
552 if (GetPageCount() > 0)
553 {
554 RECT rect;
555 TabCtrl_GetItemRect((HWND) GetHWND(), 0, & rect);
556 tabSize.x = rect.right - rect.left;
557 tabSize.y = rect.bottom - rect.top;
558 }
559 if ( HasFlag(wxNB_LEFT) || HasFlag(wxNB_RIGHT) )
560 {
561 sizeTotal.x += tabSize.x + 7;
562 sizeTotal.y += 7;
563 }
564 else
565 {
566 sizeTotal.x += 7;
567 sizeTotal.y += tabSize.y + 7;
568 }
569
570 return sizeTotal;
571}
572
2015f2b3
VZ
573void wxNotebook::AdjustPageSize(wxNotebookPage *page)
574{
575 wxCHECK_RET( page, _T("NULL page in wxNotebook::AdjustPageSize") );
576
c3732409
VZ
577 const wxRect r = GetPageSize();
578 if ( !r.IsEmpty() )
14a6b6e5 579 {
c3732409 580 page->SetSize(r);
14a6b6e5 581 }
2015f2b3
VZ
582}
583
88310e2e
VZ
584// ----------------------------------------------------------------------------
585// wxNotebook operations
586// ----------------------------------------------------------------------------
587
621793f4 588// remove one page from the notebook, without deleting
8d34bf5c 589wxNotebookPage *wxNotebook::DoRemovePage(size_t nPage)
621793f4 590{
df7145da
VZ
591 wxNotebookPage *pageRemoved = wxNotebookBase::DoRemovePage(nPage);
592 if ( !pageRemoved )
593 return NULL;
621793f4 594
df7145da 595 TabCtrl_DeleteItem(m_hwnd, nPage);
621793f4 596
df7145da
VZ
597 if ( m_pages.IsEmpty() )
598 {
599 // no selection any more, the notebook becamse empty
600 m_nSelection = -1;
601 }
602 else // notebook still not empty
603 {
623f5f70
JS
604 int selNew = TabCtrl_GetCurSel(m_hwnd);
605 if (selNew != -1)
df7145da 606 {
623f5f70 607 // No selection change, just refresh the current selection.
078cf5cb
WS
608 // Because it could be that the slection index changed
609 // we need to update it.
623f5f70
JS
610 // Note: this does not mean the selection it self changed.
611 m_nSelection = selNew;
612 m_pages[m_nSelection]->Refresh();
df7145da 613 }
623f5f70 614 else if (int(nPage) == m_nSelection)
43a997b6 615 {
623f5f70 616 // The selection was deleted.
078cf5cb 617
623f5f70
JS
618 // Determine new selection.
619 if (m_nSelection == int(GetPageCount()))
620 selNew = m_nSelection - 1;
621 else
622 selNew = m_nSelection;
078cf5cb 623
43a997b6
VZ
624 // m_nSelection must be always valid so reset it before calling
625 // SetSelection()
626 m_nSelection = -1;
627 SetSelection(selNew);
628 }
623f5f70
JS
629 else
630 {
631 wxFAIL; // Windows did not behave ok.
632 }
df7145da 633 }
47f12f58 634
df7145da 635 return pageRemoved;
621793f4
JS
636}
637
88310e2e
VZ
638// remove all pages
639bool wxNotebook::DeleteAllPages()
640{
8d34bf5c
VZ
641 size_t nPageCount = GetPageCount();
642 size_t nPage;
88310e2e 643 for ( nPage = 0; nPage < nPageCount; nPage++ )
1e6feb95 644 delete m_pages[nPage];
88310e2e 645
1e6feb95 646 m_pages.Clear();
88310e2e 647
907f37b3
VZ
648 TabCtrl_DeleteAllItems(m_hwnd);
649
47f12f58
JS
650 m_nSelection = -1;
651
37144cf0 652 InvalidateBestSize();
b8bdaa7c 653 return true;
88310e2e
VZ
654}
655
88310e2e 656// same as AddPage() but does it at given position
8d34bf5c 657bool wxNotebook::InsertPage(size_t nPage,
88310e2e
VZ
658 wxNotebookPage *pPage,
659 const wxString& strText,
660 bool bSelect,
661 int imageId)
662{
b8bdaa7c
VZ
663 wxCHECK_MSG( pPage != NULL, false, _T("NULL page in wxNotebook::InsertPage") );
664 wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false,
22f3361e 665 _T("invalid index in wxNotebook::InsertPage") );
88310e2e 666
efa14cf2
VZ
667 wxASSERT_MSG( pPage->GetParent() == this,
668 _T("notebook pages must have notebook as parent") );
43427087 669
22f3361e
VZ
670 // add a new tab to the control
671 // ----------------------------
58a8ab88 672
22f3361e
VZ
673 // init all fields to 0
674 TC_ITEM tcItem;
675 wxZeroMemory(tcItem);
58a8ab88 676
22f3361e
VZ
677 // set the image, if any
678 if ( imageId != -1 )
679 {
680 tcItem.mask |= TCIF_IMAGE;
681 tcItem.iImage = imageId;
682 }
88310e2e 683
22f3361e 684 // and the text
8b5d5223 685 if ( !strText.empty() )
22f3361e
VZ
686 {
687 tcItem.mask |= TCIF_TEXT;
688 tcItem.pszText = (wxChar *)strText.c_str(); // const_cast
689 }
43427087 690
e830a6a6
RD
691 // hide the page: unless it is selected, it shouldn't be shown (and if it
692 // is selected it will be shown later)
693 HWND hwnd = GetWinHwnd(pPage);
694 SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);
695
696 // this updates internal flag too -- otherwise it would get out of sync
697 // with the real state
698 pPage->Show(false);
699
700
22f3361e
VZ
701 // fit the notebook page to the tab control's display area: this should be
702 // done before adding it to the notebook or TabCtrl_InsertItem() will
703 // change the notebooks size itself!
2015f2b3 704 AdjustPageSize(pPage);
43427087 705
22f3361e 706 // finally do insert it
2015f2b3
VZ
707 if ( TabCtrl_InsertItem(m_hwnd, nPage, &tcItem) == -1 )
708 {
22f3361e 709 wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());
88310e2e 710
b8bdaa7c 711 return false;
22f3361e 712 }
88310e2e 713
22f3361e
VZ
714 // succeeded: save the pointer to the page
715 m_pages.Insert(pPage, nPage);
42e69d6b 716
56b9925b
VZ
717 // we may need to adjust the size again if the notebook size changed:
718 // normally this only happens for the first page we add (the tabs which
719 // hadn't been there before are now shown) but for a multiline notebook it
720 // can happen for any page at all as a new row could have been started
721 if ( m_pages.GetCount() == 1 || HasFlag(wxNB_MULTILINE) )
2015f2b3
VZ
722 {
723 AdjustPageSize(pPage);
724 }
725
22f3361e
VZ
726 // now deal with the selection
727 // ---------------------------
728
729 // if the inserted page is before the selected one, we must update the
730 // index of the selected page
34a0c9f4 731 if ( int(nPage) <= m_nSelection )
22f3361e
VZ
732 {
733 // one extra page added
734 m_nSelection++;
735 }
736
737 // some page should be selected: either this one or the first one if there
738 // is still no selection
739 int selNew = -1;
740 if ( bSelect )
741 selNew = nPage;
742 else if ( m_nSelection == -1 )
743 selNew = 0;
744
745 if ( selNew != -1 )
746 SetSelection(selNew);
747
37144cf0 748 InvalidateBestSize();
25057aba 749
b8bdaa7c 750 return true;
88310e2e
VZ
751}
752
e450aa69 753int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
ef094fa0
JS
754{
755 TC_HITTESTINFO hitTestInfo;
756 hitTestInfo.pt.x = pt.x;
757 hitTestInfo.pt.y = pt.y;
e450aa69 758 int item = TabCtrl_HitTest(GetHwnd(), &hitTestInfo);
ef094fa0 759
e450aa69
VZ
760 if ( flags )
761 {
762 *flags = 0;
763
764 if ((hitTestInfo.flags & TCHT_NOWHERE) == TCHT_NOWHERE)
765 *flags |= wxNB_HITTEST_NOWHERE;
766 if ((hitTestInfo.flags & TCHT_ONITEM) == TCHT_ONITEM)
767 *flags |= wxNB_HITTEST_ONITEM;
768 if ((hitTestInfo.flags & TCHT_ONITEMICON) == TCHT_ONITEMICON)
769 *flags |= wxNB_HITTEST_ONICON;
770 if ((hitTestInfo.flags & TCHT_ONITEMLABEL) == TCHT_ONITEMLABEL)
771 *flags |= wxNB_HITTEST_ONLABEL;
772 }
ef094fa0
JS
773
774 return item;
775}
776
e450aa69 777
88310e2e
VZ
778// ----------------------------------------------------------------------------
779// wxNotebook callbacks
780// ----------------------------------------------------------------------------
781
9026ad85 782void wxNotebook::OnSize(wxSizeEvent& event)
88310e2e 783{
7dccdf81 784 if ( GetPageCount() == 0 )
f7eaa62f
JS
785 {
786 // Prevents droppings on resize, but does cause some flicker
787 // when there are no pages.
2aa24b60 788 Refresh();
f7eaa62f
JS
789 event.Skip();
790 return;
791 }
254fbd14
JS
792#ifndef __WXWINCE__
793 else
794 {
795 // Without this, we can sometimes get droppings at the edges
796 // of a notebook, for example a notebook in a splitter window.
797 // This needs to be reconciled with the RefreshRect calls
798 // at the end of this function, which weren't enough to prevent
799 // the droppings.
800
801 wxSize sz = GetClientSize();
802
803 // Refresh right side
804 wxRect rect(sz.x-4, 0, 4, sz.y);
805 RefreshRect(rect);
806
807 // Refresh bottom side
808 rect = wxRect(0, sz.y-4, sz.x, 4);
809 RefreshRect(rect);
810
811 // Refresh left side
812 rect = wxRect(0, 0, 4, sz.y);
813 RefreshRect(rect);
814 }
815#endif
f7eaa62f 816
c1637c89 817 // fit all the notebook pages to the tab control's display area
56b9925b 818
c1637c89
VZ
819 RECT rc;
820 rc.left = rc.top = 0;
821 GetSize((int *)&rc.right, (int *)&rc.bottom);
56b9925b 822
c1637c89
VZ
823 // save the total size, we'll use it below
824 int widthNbook = rc.right - rc.left,
825 heightNbook = rc.bottom - rc.top;
826
827 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
828 // returns completely false values for multiline tab controls after the tabs
829 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
830 //
831 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
832 //
833 // and the only work around I could find was this ugly hack... without it
834 // simply toggling the "multiline" checkbox in the notebook sample resulted
835 // in a noticeable page displacement
836 if ( HasFlag(wxNB_MULTILINE) )
837 {
838 // avoid an infinite recursion: we get another notification too!
839 static bool s_isInOnSize = false;
4b7f2165 840
c1637c89
VZ
841 if ( !s_isInOnSize )
842 {
843 s_isInOnSize = true;
844 SendMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED,
845 MAKELPARAM(rc.right, rc.bottom));
846 s_isInOnSize = false;
847 }
848 }
b5c3b538 849
e2f6f8da
RD
850#if wxUSE_UXTHEME
851 // background bitmap size has changed, update the brush using it too
852 UpdateBgBrush();
853#endif // wxUSE_UXTHEME
854
c1637c89
VZ
855 TabCtrl_AdjustRect(m_hwnd, false, &rc);
856
857 int width = rc.right - rc.left,
858 height = rc.bottom - rc.top;
859 size_t nCount = m_pages.Count();
860 for ( size_t nPage = 0; nPage < nCount; nPage++ ) {
861 wxNotebookPage *pPage = m_pages[nPage];
862 pPage->SetSize(rc.left, rc.top, width, height);
863 }
864
865
866 // unless we had already repainted everything, we now need to refresh
867 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
868 {
869 // invalidate areas not covered by pages
870 RefreshRect(wxRect(0, 0, widthNbook, rc.top), false);
871 RefreshRect(wxRect(0, rc.top, rc.left, height), false);
872 RefreshRect(wxRect(0, rc.bottom, widthNbook, heightNbook - rc.bottom),
873 false);
874 RefreshRect(wxRect(rc.right, rc.top, widthNbook - rc.bottom, height),
875 false);
876 }
877
878 event.Skip();
88310e2e
VZ
879}
880
881void wxNotebook::OnSelChange(wxNotebookEvent& event)
882{
883 // is it our tab control?
884 if ( event.GetEventObject() == this )
5d1d2d46 885 {
5d1d2d46
VZ
886 int sel = event.GetOldSelection();
887 if ( sel != -1 )
b8bdaa7c 888 m_pages[sel]->Show(false);
0398b1d6 889
5d1d2d46
VZ
890 sel = event.GetSelection();
891 if ( sel != -1 )
892 {
1e6feb95 893 wxNotebookPage *pPage = m_pages[sel];
b8bdaa7c 894 pPage->Show(true);
1d5b3bf0
VZ
895 pPage->SetFocus();
896
897 // If the newly focused window is not a child of the new page,
898 // SetFocus was not successful and the notebook itself should be
899 // focused
900 wxWindow *currentFocus = FindFocus();
901 wxWindow *startFocus = currentFocus;
902 while ( currentFocus && currentFocus != pPage && currentFocus != this )
903 currentFocus = currentFocus->GetParent();
904
905 if ( startFocus == pPage || currentFocus != pPage )
906 SetFocus();
907
908 }
909 else // no pages in the notebook, give the focus to itself
910 {
911 SetFocus();
5d1d2d46 912 }
0398b1d6 913
5d1d2d46
VZ
914 m_nSelection = sel;
915 }
88310e2e
VZ
916
917 // we want to give others a chance to process this message as well
918 event.Skip();
919}
920
b8bdaa7c 921bool wxNotebook::MSWTranslateMessage(WXMSG *wxmsg)
88310e2e 922{
b8bdaa7c 923 const MSG * const msg = (MSG *)wxmsg;
88310e2e 924
1d5b3bf0
VZ
925 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
926 // TAB will be passed to the currently selected page, CTRL+TAB and
927 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
928 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
929 // process it.
b8bdaa7c
VZ
930 if ( msg->message == WM_KEYDOWN && msg->wParam == VK_TAB &&
931 msg->hwnd == m_hwnd &&
1d5b3bf0 932 (wxIsCtrlDown() || !wxIsShiftDown()) )
b8bdaa7c
VZ
933 {
934 return MSWProcessMessage(wxmsg);
935 }
d9506e77 936
b8bdaa7c 937 return false;
88310e2e
VZ
938}
939
940void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
941{
d9506e77
VZ
942 if ( event.IsWindowChange() ) {
943 // change pages
944 AdvanceSelection(event.GetDirection());
945 }
946 else {
b8bdaa7c 947 // we get this event in 3 cases
d9506e77
VZ
948 //
949 // a) one of our pages might have generated it because the user TABbed
950 // out from it in which case we should propagate the event upwards and
951 // our parent will take care of setting the focus to prev/next sibling
952 //
953 // or
954 //
955 // b) the parent panel wants to give the focus to us so that we
956 // forward it to our selected page. We can't deal with this in
957 // OnSetFocus() because we don't know which direction the focus came
958 // from in this case and so can't choose between setting the focus to
959 // first or last panel child
b8bdaa7c
VZ
960 //
961 // or
962 //
963 // c) we ourselves (see MSWTranslateMessage) generated the event
964 //
965 wxWindow * const parent = GetParent();
966
3c99602b
MB
967 // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
968 const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
969 const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
b8bdaa7c
VZ
970
971 if ( isFromParent || isFromSelf )
d9506e77 972 {
b8bdaa7c
VZ
973 // no, it doesn't come from child, case (b) or (c): forward to a
974 // page but only if direction is backwards (TAB) or from ourselves,
975 if ( m_nSelection != -1 &&
976 (!event.GetDirection() || isFromSelf) )
d9506e77
VZ
977 {
978 // so that the page knows that the event comes from it's parent
979 // and is being propagated downwards
980 event.SetEventObject(this);
981
1e6feb95 982 wxWindow *page = m_pages[m_nSelection];
d9506e77
VZ
983 if ( !page->GetEventHandler()->ProcessEvent(event) )
984 {
985 page->SetFocus();
986 }
987 //else: page manages focus inside it itself
988 }
b8bdaa7c 989 else // otherwise set the focus to the notebook itself
d9506e77 990 {
d9506e77
VZ
991 SetFocus();
992 }
993 }
994 else
995 {
b8bdaa7c
VZ
996 // it comes from our child, case (a), pass to the parent, but only
997 // if the direction is forwards. Otherwise set the focus to the
998 // notebook itself. The notebook is always the 'first' control of a
999 // page.
1000 if ( !event.GetDirection() )
1001 {
1002 SetFocus();
1003 }
1004 else if ( parent )
1005 {
d9506e77
VZ
1006 event.SetCurrentFocus(this);
1007 parent->GetEventHandler()->ProcessEvent(event);
1008 }
1009 }
88310e2e 1010 }
88310e2e
VZ
1011}
1012
caf95d2a
VZ
1013#if wxUSE_UXTHEME
1014
c3732409 1015bool wxNotebook::DoDrawBackground(WXHDC hDC, wxWindow *child)
caf95d2a 1016{
c3732409
VZ
1017 wxUxThemeHandle theme(child ? child : this, L"TAB");
1018 if ( !theme )
1019 return false;
1020
1021 // get the notebook client rect (we're not interested in drawing tabs
1022 // themselves)
1023 wxRect r = GetPageSize();
1024 if ( r.IsEmpty() )
1025 return false;
1026
c4a95f6f 1027 RECT rc;
c3732409
VZ
1028 wxCopyRectToRECT(r, rc);
1029
1030 // map rect to the coords of the window we're drawing in
1031 if ( child )
1032 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1033
1034
1035 // apparently DrawThemeBackground() modifies the rect passed to it and if we
1036 // don't do these adjustments, there are some drawing artifacts which are
1037 // only visible with some non default themes; so modify the rect here using
1038 // the magic numbers below so that it still paints the correct area
1039 rc.left -= 2;
1040 rc.top -= 2;
1041 rc.right += 4;
1042 rc.bottom += 5;
1043
1044
1045 wxUxThemeEngine::Get()->DrawThemeBackground
1046 (
1047 theme,
1048 hDC,
1049 9 /* TABP_PANE */,
1050 0,
1051 &rc,
1052 NULL
1053 );
1054
1055 return true;
1056}
de359565 1057
c3732409
VZ
1058WXHBRUSH wxNotebook::QueryBgBitmap()
1059{
1060 wxRect r = GetPageSize();
1061 if ( r.IsEmpty() )
1062 return 0;
c4a95f6f
VZ
1063
1064 WindowHDC hDC(GetHwnd());
1065 MemoryHDC hDCMem(hDC);
c3732409 1066 CompatibleBitmap hBmp(hDC, r.x + r.width, r.y + r.height);
c4a95f6f
VZ
1067
1068 SelectInHDC selectBmp(hDCMem, hBmp);
caf95d2a 1069
c3732409
VZ
1070 if ( !DoDrawBackground((WXHDC)(HDC)hDCMem) )
1071 return 0;
0f770734 1072
de359565 1073 return (WXHBRUSH)::CreatePatternBrush(hBmp);
c4a95f6f 1074}
caf95d2a 1075
c4a95f6f
VZ
1076void wxNotebook::UpdateBgBrush()
1077{
1078 if ( m_hbrBackground )
1079 ::DeleteObject((HBRUSH)m_hbrBackground);
caf95d2a 1080
c4a95f6f
VZ
1081 if ( !m_hasBgCol && wxUxThemeEngine::GetIfActive() )
1082 {
de359565 1083 m_hbrBackground = QueryBgBitmap();
caf95d2a 1084 }
c3732409 1085 else // no themes or we've got user-defined solid colour
caf95d2a
VZ
1086 {
1087 m_hbrBackground = NULL;
1088 }
1089}
1090
2bae4332 1091WXHBRUSH wxNotebook::MSWGetBgBrushForChild(WXHDC hDC, WXHWND hWnd)
caf95d2a 1092{
caf95d2a
VZ
1093 if ( m_hbrBackground )
1094 {
1095 // before drawing with the background brush, we need to position it
1096 // correctly
caf95d2a 1097 RECT rc;
2bae4332 1098 ::GetWindowRect((HWND)hWnd, &rc);
caf95d2a
VZ
1099
1100 ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
1101
5c836c46 1102 if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
caf95d2a
VZ
1103 {
1104 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
1105 }
c4a95f6f
VZ
1106
1107 return m_hbrBackground;
5c836c46
VZ
1108 }
1109
2bae4332 1110 return wxNotebookBase::MSWGetBgBrushForChild(hDC, hWnd);
5c836c46 1111}
caf95d2a 1112
c3732409 1113bool wxNotebook::MSWPrintChild(WXHDC hDC, wxWindow *child)
07c19327 1114{
c3732409
VZ
1115 // solid background colour overrides themed background drawing
1116 if ( !UseBgCol() && DoDrawBackground(hDC, child) )
1117 return true;
de359565 1118
4dab5279
JS
1119 // If we're using a solid colour (for example if we've switched off
1120 // theming for this notebook), paint it
1121 if (UseBgCol())
1122 {
1123 wxRect r = GetPageSize();
1124 if ( r.IsEmpty() )
1125 return false;
1126
1127 RECT rc;
1128 wxCopyRectToRECT(r, rc);
1129
1130 // map rect to the coords of the window we're drawing in
1131 if ( child )
1132 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1133
1134 wxBrush brush(GetBackgroundColour());
1135 HBRUSH hbr = GetHbrushOf(brush);
1136
1137 ::FillRect((HDC) hDC, &rc, hbr);
1138
1139 return true;
1140 }
1141
c3732409 1142 return wxNotebookBase::MSWPrintChild(hDC, child);
07c19327
VZ
1143}
1144
caf95d2a
VZ
1145#endif // wxUSE_UXTHEME
1146
25057aba
JS
1147// Windows only: attempts to get colour for UX theme page background
1148wxColour wxNotebook::GetThemeBackgroundColour() const
1149{
1150#if wxUSE_UXTHEME
1151 if (wxUxThemeEngine::Get())
1152 {
1153 wxUxThemeHandle hTheme((wxNotebook*) this, L"TAB");
1154 if (hTheme)
1155 {
1156 // This is total guesswork.
1157 // See PlatformSDK\Include\Tmschema.h for values
1158 COLORREF themeColor;
1159 wxUxThemeEngine::Get()->GetThemeColor(
1160 hTheme,
1161 10 /* TABP_BODY */,
1162 1 /* NORMAL */,
1163 3821 /* FILLCOLORHINT */,
1164 &themeColor);
1165
1166 /*
1167 [DS] Workaround for WindowBlinds:
1168 Some themes return a near black theme color using FILLCOLORHINT,
1169 this makes notebook pages have an ugly black background and makes
1170 text (usually black) unreadable. Retry again with FILLCOLOR.
1171
1172 This workaround potentially breaks appearance of some themes,
1173 but in practice it already fixes some themes.
1174 */
1175 if (themeColor == 1)
1176 {
1177 wxUxThemeEngine::Get()->GetThemeColor(
1178 hTheme,
1179 10 /* TABP_BODY */,
1180 1 /* NORMAL */,
1181 3802 /* FILLCOLOR */,
1182 &themeColor);
1183 }
1184
7dccdf81 1185 return wxRGBToColour(themeColor);
25057aba
JS
1186 }
1187 }
1188#endif // wxUSE_UXTHEME
1189
1190 return GetBackgroundColour();
1191}
1192
88310e2e
VZ
1193// ----------------------------------------------------------------------------
1194// wxNotebook base class virtuals
1195// ----------------------------------------------------------------------------
b5c3b538 1196
0b481c72
VZ
1197#if wxUSE_CONSTRAINTS
1198
b5c3b538
VZ
1199// override these 2 functions to do nothing: everything is done in OnSize
1200
4b7f2165 1201void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
b5c3b538
VZ
1202{
1203 // don't set the sizes of the pages - their correct size is not yet known
b8bdaa7c 1204 wxControl::SetConstraintSizes(false);
b5c3b538
VZ
1205}
1206
4b7f2165 1207bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
b5c3b538 1208{
b8bdaa7c 1209 return true;
b5c3b538
VZ
1210}
1211
0b481c72
VZ
1212#endif // wxUSE_CONSTRAINTS
1213
0df3fbd7
VZ
1214// ----------------------------------------------------------------------------
1215// wxNotebook Windows message handlers
1216// ----------------------------------------------------------------------------
1217
1218bool wxNotebook::MSWOnScroll(int orientation, WXWORD nSBCode,
1219 WXWORD pos, WXHWND control)
1220{
1221 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1222 // up-down control
1223 if ( control )
b8bdaa7c 1224 return false;
0df3fbd7
VZ
1225
1226 return wxNotebookBase::MSWOnScroll(orientation, nSBCode, pos, control);
1227}
1228
a23fd0e1 1229bool wxNotebook::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
88310e2e 1230{
93a19f17 1231 wxNotebookEvent event(wxEVT_NULL, m_windowId);
88310e2e
VZ
1232
1233 NMHDR* hdr = (NMHDR *)lParam;
1234 switch ( hdr->code ) {
1235 case TCN_SELCHANGE:
1236 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
1237 break;
1238
1239 case TCN_SELCHANGING:
1240 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
1241 break;
1242
fd3f686c 1243 default:
a23fd0e1 1244 return wxControl::MSWOnNotify(idCtrl, lParam, result);
88310e2e
VZ
1245 }
1246
93a19f17
VZ
1247 event.SetSelection(TabCtrl_GetCurSel(m_hwnd));
1248 event.SetOldSelection(m_nSelection);
88310e2e 1249 event.SetEventObject(this);
a23fd0e1 1250 event.SetInt(idCtrl);
88310e2e 1251
fd3f686c
VZ
1252 bool processed = GetEventHandler()->ProcessEvent(event);
1253 *result = !event.IsAllowed();
1254 return processed;
88310e2e
VZ
1255}
1256
254fbd14
JS
1257#ifndef __WXWINCE__
1258void wxNotebook::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
1259{
1260 // do nothing here
1261}
1262
1263void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event))
1264{
1265 // Better painting behaviour, at the expense of system resources
1266#if USE_NOTEBOOK_ANTIFLICKER
1267 wxPaintDC dc(this);
1268 wxMemoryDC memdc;
1269 RECT rc;
1270 ::GetClientRect(GetHwnd(), &rc);
1271 wxBitmap bmp(rc.right, rc.bottom);
1272 memdc.SelectObject(bmp);
1273
1274 // iterate over all child windows to find spin button
1275 for ( HWND child = ::GetWindow(GetHwnd(), GW_CHILD);
1276 child;
1277 child = ::GetWindow(child, GW_HWNDNEXT) )
1278 {
1279 wxWindow *childWindow = wxFindWinFromHandle((WXHWND)child);
1280
1281 // see if it exists, if no wxWindow found then assume it's the spin btn
1282 if ( !childWindow )
1283 {
1284 // subclass the spin button to override WM_ERASEBKGND
1285 if ( !s_wndprocNotebookSpinBtn )
1286 s_wndprocNotebookSpinBtn = (WXFARPROC)wxGetWindowProc(child);
1287
1288 wxSetWindowProc(child, wxNotebookSpinBtnWndProc);
1289 break;
1290 }
1291 }
1292
1293 HBRUSH hbr = (HBRUSH)m_hbrBackground;
1294
1295 // if there is no special brush just use the solid background colour
1296 wxBrush brush;
1297 if ( !hbr )
1298 {
1299 brush = wxBrush(GetBackgroundColour());
1300 hbr = GetHbrushOf(brush);
1301 }
1302
1303 ::FillRect(GetHdcOf(memdc), &rc, hbr);
1304
1305 MSWDefWindowProc(WM_PAINT, (WPARAM)memdc.GetHDC(), 0);
1306
1307 dc.Blit(0, 0, rc.right, rc.bottom, &memdc, 0, 0);
1308#endif
1309}
1310#endif
1311 // __WXWINCE__
1312
1313#if USE_NOTEBOOK_ANTIFLICKER
1314// ---------------------------------------------------------------------------
1315// window proc for spin button
1316// ---------------------------------------------------------------------------
1317
1318LRESULT APIENTRY _EXPORT wxNotebookSpinBtnWndProc(HWND hwnd,
1319 UINT message,
1320 WPARAM wParam,
1321 LPARAM lParam)
1322{
1323 if ( message == WM_ERASEBKGND )
1324 return 0;
1325
1326 return ::CallWindowProc(CASTWNDPROC s_wndprocNotebookSpinBtn, hwnd, message, wParam, lParam);
1327}
1328
1329#endif
1330 // USE_NOTEBOOK_ANTIFLICKER
1331
1e6feb95 1332#endif // wxUSE_NOTEBOOK