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