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