]> git.saurik.com Git - wxWidgets.git/blame - src/msw/notebook.cpp
First part of '[ 1216148 ] cleanup: unused variables and declarations'.
[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);
306302e1
JS
970
971 // As per bug report:
972 // http://sourceforge.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863,
973 // we should not set the page focus (and thereby the focus for
974 // a child window) since it erroneously selects radio button controls and also
975 // breaks keyboard handling for a notebook's scroll buttons. So
976 // we always focus the notebook and not the page.
977 SetFocus();
1d5b3bf0
VZ
978
979 }
980 else // no pages in the notebook, give the focus to itself
981 {
982 SetFocus();
5d1d2d46 983 }
0398b1d6 984
5d1d2d46
VZ
985 m_nSelection = sel;
986 }
88310e2e
VZ
987
988 // we want to give others a chance to process this message as well
989 event.Skip();
990}
991
b8bdaa7c 992bool wxNotebook::MSWTranslateMessage(WXMSG *wxmsg)
88310e2e 993{
b8bdaa7c 994 const MSG * const msg = (MSG *)wxmsg;
88310e2e 995
1d5b3bf0
VZ
996 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
997 // TAB will be passed to the currently selected page, CTRL+TAB and
998 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
999 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
1000 // process it.
b8bdaa7c 1001 if ( msg->message == WM_KEYDOWN && msg->wParam == VK_TAB &&
01c8cbf5 1002 msg->hwnd == GetHwnd() &&
1d5b3bf0 1003 (wxIsCtrlDown() || !wxIsShiftDown()) )
b8bdaa7c
VZ
1004 {
1005 return MSWProcessMessage(wxmsg);
1006 }
d9506e77 1007
b8bdaa7c 1008 return false;
88310e2e
VZ
1009}
1010
1011void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
1012{
d9506e77
VZ
1013 if ( event.IsWindowChange() ) {
1014 // change pages
1015 AdvanceSelection(event.GetDirection());
1016 }
1017 else {
b8bdaa7c 1018 // we get this event in 3 cases
d9506e77
VZ
1019 //
1020 // a) one of our pages might have generated it because the user TABbed
1021 // out from it in which case we should propagate the event upwards and
1022 // our parent will take care of setting the focus to prev/next sibling
1023 //
1024 // or
1025 //
1026 // b) the parent panel wants to give the focus to us so that we
1027 // forward it to our selected page. We can't deal with this in
1028 // OnSetFocus() because we don't know which direction the focus came
1029 // from in this case and so can't choose between setting the focus to
1030 // first or last panel child
b8bdaa7c
VZ
1031 //
1032 // or
1033 //
1034 // c) we ourselves (see MSWTranslateMessage) generated the event
1035 //
1036 wxWindow * const parent = GetParent();
1037
3c99602b
MB
1038 // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
1039 const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
1040 const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
b8bdaa7c
VZ
1041
1042 if ( isFromParent || isFromSelf )
d9506e77 1043 {
b8bdaa7c
VZ
1044 // no, it doesn't come from child, case (b) or (c): forward to a
1045 // page but only if direction is backwards (TAB) or from ourselves,
1046 if ( m_nSelection != -1 &&
1047 (!event.GetDirection() || isFromSelf) )
d9506e77
VZ
1048 {
1049 // so that the page knows that the event comes from it's parent
1050 // and is being propagated downwards
1051 event.SetEventObject(this);
1052
1e6feb95 1053 wxWindow *page = m_pages[m_nSelection];
d9506e77
VZ
1054 if ( !page->GetEventHandler()->ProcessEvent(event) )
1055 {
1056 page->SetFocus();
1057 }
1058 //else: page manages focus inside it itself
1059 }
b8bdaa7c 1060 else // otherwise set the focus to the notebook itself
d9506e77 1061 {
d9506e77
VZ
1062 SetFocus();
1063 }
1064 }
1065 else
1066 {
b8bdaa7c
VZ
1067 // it comes from our child, case (a), pass to the parent, but only
1068 // if the direction is forwards. Otherwise set the focus to the
1069 // notebook itself. The notebook is always the 'first' control of a
1070 // page.
1071 if ( !event.GetDirection() )
1072 {
1073 SetFocus();
1074 }
1075 else if ( parent )
1076 {
d9506e77
VZ
1077 event.SetCurrentFocus(this);
1078 parent->GetEventHandler()->ProcessEvent(event);
1079 }
1080 }
88310e2e 1081 }
88310e2e
VZ
1082}
1083
caf95d2a
VZ
1084#if wxUSE_UXTHEME
1085
c3732409 1086bool wxNotebook::DoDrawBackground(WXHDC hDC, wxWindow *child)
caf95d2a 1087{
c3732409
VZ
1088 wxUxThemeHandle theme(child ? child : this, L"TAB");
1089 if ( !theme )
1090 return false;
1091
1092 // get the notebook client rect (we're not interested in drawing tabs
1093 // themselves)
1094 wxRect r = GetPageSize();
1095 if ( r.IsEmpty() )
1096 return false;
1097
c4a95f6f 1098 RECT rc;
c3732409
VZ
1099 wxCopyRectToRECT(r, rc);
1100
1101 // map rect to the coords of the window we're drawing in
1102 if ( child )
1103 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1104
1105
1106 // apparently DrawThemeBackground() modifies the rect passed to it and if we
1107 // don't do these adjustments, there are some drawing artifacts which are
1108 // only visible with some non default themes; so modify the rect here using
1109 // the magic numbers below so that it still paints the correct area
1110 rc.left -= 2;
1111 rc.top -= 2;
1112 rc.right += 4;
1113 rc.bottom += 5;
1114
1115
1116 wxUxThemeEngine::Get()->DrawThemeBackground
1117 (
1118 theme,
92199f4c 1119 (HDC) hDC,
c3732409
VZ
1120 9 /* TABP_PANE */,
1121 0,
1122 &rc,
1123 NULL
1124 );
1125
1126 return true;
1127}
de359565 1128
c3732409
VZ
1129WXHBRUSH wxNotebook::QueryBgBitmap()
1130{
1131 wxRect r = GetPageSize();
1132 if ( r.IsEmpty() )
1133 return 0;
c4a95f6f
VZ
1134
1135 WindowHDC hDC(GetHwnd());
1136 MemoryHDC hDCMem(hDC);
c3732409 1137 CompatibleBitmap hBmp(hDC, r.x + r.width, r.y + r.height);
c4a95f6f
VZ
1138
1139 SelectInHDC selectBmp(hDCMem, hBmp);
caf95d2a 1140
c3732409
VZ
1141 if ( !DoDrawBackground((WXHDC)(HDC)hDCMem) )
1142 return 0;
0f770734 1143
de359565 1144 return (WXHBRUSH)::CreatePatternBrush(hBmp);
c4a95f6f 1145}
caf95d2a 1146
c4a95f6f
VZ
1147void wxNotebook::UpdateBgBrush()
1148{
1149 if ( m_hbrBackground )
1150 ::DeleteObject((HBRUSH)m_hbrBackground);
caf95d2a 1151
c4a95f6f
VZ
1152 if ( !m_hasBgCol && wxUxThemeEngine::GetIfActive() )
1153 {
de359565 1154 m_hbrBackground = QueryBgBitmap();
caf95d2a 1155 }
c3732409 1156 else // no themes or we've got user-defined solid colour
caf95d2a
VZ
1157 {
1158 m_hbrBackground = NULL;
1159 }
1160}
1161
2bae4332 1162WXHBRUSH wxNotebook::MSWGetBgBrushForChild(WXHDC hDC, WXHWND hWnd)
caf95d2a 1163{
caf95d2a
VZ
1164 if ( m_hbrBackground )
1165 {
1166 // before drawing with the background brush, we need to position it
1167 // correctly
caf95d2a 1168 RECT rc;
2bae4332 1169 ::GetWindowRect((HWND)hWnd, &rc);
caf95d2a
VZ
1170
1171 ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
1172
5c836c46 1173 if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
caf95d2a
VZ
1174 {
1175 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
1176 }
c4a95f6f
VZ
1177
1178 return m_hbrBackground;
5c836c46
VZ
1179 }
1180
2bae4332 1181 return wxNotebookBase::MSWGetBgBrushForChild(hDC, hWnd);
5c836c46 1182}
caf95d2a 1183
c3732409 1184bool wxNotebook::MSWPrintChild(WXHDC hDC, wxWindow *child)
07c19327 1185{
c3732409
VZ
1186 // solid background colour overrides themed background drawing
1187 if ( !UseBgCol() && DoDrawBackground(hDC, child) )
1188 return true;
de359565 1189
4dab5279
JS
1190 // If we're using a solid colour (for example if we've switched off
1191 // theming for this notebook), paint it
1192 if (UseBgCol())
1193 {
1194 wxRect r = GetPageSize();
1195 if ( r.IsEmpty() )
1196 return false;
1197
1198 RECT rc;
1199 wxCopyRectToRECT(r, rc);
1200
1201 // map rect to the coords of the window we're drawing in
1202 if ( child )
1203 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1204
1205 wxBrush brush(GetBackgroundColour());
1206 HBRUSH hbr = GetHbrushOf(brush);
01c8cbf5 1207
4dab5279
JS
1208 ::FillRect((HDC) hDC, &rc, hbr);
1209
1210 return true;
1211 }
1212
c3732409 1213 return wxNotebookBase::MSWPrintChild(hDC, child);
07c19327
VZ
1214}
1215
caf95d2a
VZ
1216#endif // wxUSE_UXTHEME
1217
25057aba
JS
1218// Windows only: attempts to get colour for UX theme page background
1219wxColour wxNotebook::GetThemeBackgroundColour() const
1220{
1221#if wxUSE_UXTHEME
1222 if (wxUxThemeEngine::Get())
1223 {
1224 wxUxThemeHandle hTheme((wxNotebook*) this, L"TAB");
1225 if (hTheme)
1226 {
1227 // This is total guesswork.
1228 // See PlatformSDK\Include\Tmschema.h for values
1229 COLORREF themeColor;
1230 wxUxThemeEngine::Get()->GetThemeColor(
1231 hTheme,
1232 10 /* TABP_BODY */,
1233 1 /* NORMAL */,
1234 3821 /* FILLCOLORHINT */,
1235 &themeColor);
1236
1237 /*
1238 [DS] Workaround for WindowBlinds:
1239 Some themes return a near black theme color using FILLCOLORHINT,
1240 this makes notebook pages have an ugly black background and makes
1241 text (usually black) unreadable. Retry again with FILLCOLOR.
1242
1243 This workaround potentially breaks appearance of some themes,
1244 but in practice it already fixes some themes.
1245 */
1246 if (themeColor == 1)
1247 {
1248 wxUxThemeEngine::Get()->GetThemeColor(
1249 hTheme,
1250 10 /* TABP_BODY */,
1251 1 /* NORMAL */,
1252 3802 /* FILLCOLOR */,
1253 &themeColor);
1254 }
1255
7dccdf81 1256 return wxRGBToColour(themeColor);
25057aba
JS
1257 }
1258 }
1259#endif // wxUSE_UXTHEME
1260
1261 return GetBackgroundColour();
1262}
1263
88310e2e
VZ
1264// ----------------------------------------------------------------------------
1265// wxNotebook base class virtuals
1266// ----------------------------------------------------------------------------
b5c3b538 1267
0b481c72
VZ
1268#if wxUSE_CONSTRAINTS
1269
b5c3b538
VZ
1270// override these 2 functions to do nothing: everything is done in OnSize
1271
4b7f2165 1272void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
b5c3b538
VZ
1273{
1274 // don't set the sizes of the pages - their correct size is not yet known
b8bdaa7c 1275 wxControl::SetConstraintSizes(false);
b5c3b538
VZ
1276}
1277
4b7f2165 1278bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
b5c3b538 1279{
b8bdaa7c 1280 return true;
b5c3b538
VZ
1281}
1282
0b481c72
VZ
1283#endif // wxUSE_CONSTRAINTS
1284
0df3fbd7
VZ
1285// ----------------------------------------------------------------------------
1286// wxNotebook Windows message handlers
1287// ----------------------------------------------------------------------------
1288
1289bool wxNotebook::MSWOnScroll(int orientation, WXWORD nSBCode,
1290 WXWORD pos, WXHWND control)
1291{
1292 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1293 // up-down control
1294 if ( control )
b8bdaa7c 1295 return false;
0df3fbd7
VZ
1296
1297 return wxNotebookBase::MSWOnScroll(orientation, nSBCode, pos, control);
1298}
1299
a23fd0e1 1300bool wxNotebook::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
88310e2e 1301{
93a19f17 1302 wxNotebookEvent event(wxEVT_NULL, m_windowId);
88310e2e
VZ
1303
1304 NMHDR* hdr = (NMHDR *)lParam;
1305 switch ( hdr->code ) {
1306 case TCN_SELCHANGE:
1307 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
1308 break;
1309
1310 case TCN_SELCHANGING:
1311 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
1312 break;
1313
fd3f686c 1314 default:
a23fd0e1 1315 return wxControl::MSWOnNotify(idCtrl, lParam, result);
88310e2e
VZ
1316 }
1317
01c8cbf5 1318 event.SetSelection(TabCtrl_GetCurSel(GetHwnd()));
93a19f17 1319 event.SetOldSelection(m_nSelection);
88310e2e 1320 event.SetEventObject(this);
a23fd0e1 1321 event.SetInt(idCtrl);
88310e2e 1322
fd3f686c
VZ
1323 bool processed = GetEventHandler()->ProcessEvent(event);
1324 *result = !event.IsAllowed();
1325 return processed;
88310e2e
VZ
1326}
1327
1e6feb95 1328#endif // wxUSE_NOTEBOOK