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