]> git.saurik.com Git - wxWidgets.git/blame - src/msw/notebook.cpp
Comitting correct wxGTK.spec again.
[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 }
7dccdf81 348#endif // wxUSE_UXTHEME
b554cf63
JS
349
350 // Undocumented hack to get flat notebook style
351 // In fact, we should probably only do this in some
352 // curcumstances, i.e. if we know we will have a border
353 // at the bottom (the tab control doesn't draw it itself)
354#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
355 if (HasFlag(wxNB_FLAT))
356 {
01c8cbf5 357 SendMessage(GetHwnd(), CCM_SETVERSION, COMCTL32_VERSION, 0);
b554cf63
JS
358 if (!m_hasBgCol)
359 SetBackgroundColour(*wxWHITE);
360 }
361#endif
b8bdaa7c 362 return true;
0df3fbd7
VZ
363}
364
365WXDWORD wxNotebook::MSWGetStyle(long style, WXDWORD *exstyle) const
366{
367 WXDWORD tabStyle = wxControl::MSWGetStyle(style, exstyle);
368
369 tabStyle |= WS_TABSTOP | TCS_TABS;
370
2b5f62a0 371 if ( style & wxNB_MULTILINE )
0df3fbd7
VZ
372 tabStyle |= TCS_MULTILINE;
373 if ( style & wxNB_FIXEDWIDTH )
374 tabStyle |= TCS_FIXEDWIDTH;
375
376 if ( style & wxNB_BOTTOM )
377 tabStyle |= TCS_RIGHT;
378 else if ( style & wxNB_LEFT )
379 tabStyle |= TCS_VERTICAL;
380 else if ( style & wxNB_RIGHT )
c3732409 381 tabStyle |= TCS_VERTICAL | TCS_RIGHT;
0df3fbd7
VZ
382
383 // ex style
384 if ( exstyle )
385 {
386 // note that we never want to have the default WS_EX_CLIENTEDGE style
387 // as it looks too ugly for the notebooks
388 *exstyle = 0;
389 }
390
391 return tabStyle;
88310e2e
VZ
392}
393
caf95d2a
VZ
394wxNotebook::~wxNotebook()
395{
396#if wxUSE_UXTHEME
397 if ( m_hbrBackground )
398 ::DeleteObject((HBRUSH)m_hbrBackground);
399#endif // wxUSE_UXTHEME
400}
401
88310e2e
VZ
402// ----------------------------------------------------------------------------
403// wxNotebook accessors
404// ----------------------------------------------------------------------------
07b8d7ec 405
8d34bf5c 406size_t wxNotebook::GetPageCount() const
88310e2e
VZ
407{
408 // consistency check
01c8cbf5 409 wxASSERT( (int)m_pages.Count() == TabCtrl_GetItemCount(GetHwnd()) );
88310e2e 410
1e6feb95 411 return m_pages.Count();
88310e2e
VZ
412}
413
414int wxNotebook::GetRowCount() const
415{
01c8cbf5 416 return TabCtrl_GetRowCount(GetHwnd());
88310e2e
VZ
417}
418
8d34bf5c 419int wxNotebook::SetSelection(size_t nPage)
88310e2e 420{
078cf5cb 421 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
88310e2e 422
34a0c9f4 423 if ( int(nPage) != m_nSelection )
2b5f62a0
VZ
424 {
425 wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_windowId);
426 event.SetSelection(nPage);
427 event.SetOldSelection(m_nSelection);
428 event.SetEventObject(this);
429 if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
430 {
431 // program allows the page change
432 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
433 (void)GetEventHandler()->ProcessEvent(event);
434
01c8cbf5 435 TabCtrl_SetCurSel(GetHwnd(), nPage);
2b5f62a0
VZ
436 }
437 }
88310e2e 438
2b5f62a0 439 return m_nSelection;
88310e2e
VZ
440}
441
8d34bf5c 442bool wxNotebook::SetPageText(size_t nPage, const wxString& strText)
88310e2e 443{
b8bdaa7c 444 wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
88310e2e
VZ
445
446 TC_ITEM tcItem;
447 tcItem.mask = TCIF_TEXT;
837e5743 448 tcItem.pszText = (wxChar *)strText.c_str();
88310e2e 449
01c8cbf5 450 return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
88310e2e
VZ
451}
452
8d34bf5c 453wxString wxNotebook::GetPageText(size_t nPage) const
88310e2e 454{
fda7962d 455 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxEmptyString, wxT("notebook page out of range") );
88310e2e 456
837e5743 457 wxChar buf[256];
88310e2e
VZ
458 TC_ITEM tcItem;
459 tcItem.mask = TCIF_TEXT;
460 tcItem.pszText = buf;
461 tcItem.cchTextMax = WXSIZEOF(buf);
462
463 wxString str;
01c8cbf5 464 if ( TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) )
88310e2e
VZ
465 str = tcItem.pszText;
466
467 return str;
468}
469
8d34bf5c 470int wxNotebook::GetPageImage(size_t nPage) const
88310e2e 471{
223d09f6 472 wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") );
88310e2e
VZ
473
474 TC_ITEM tcItem;
475 tcItem.mask = TCIF_IMAGE;
476
01c8cbf5 477 return TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) ? tcItem.iImage : -1;
88310e2e
VZ
478}
479
8d34bf5c 480bool wxNotebook::SetPageImage(size_t nPage, int nImage)
88310e2e 481{
b8bdaa7c 482 wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
88310e2e
VZ
483
484 TC_ITEM tcItem;
485 tcItem.mask = TCIF_IMAGE;
486 tcItem.iImage = nImage;
487
01c8cbf5 488 return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
88310e2e
VZ
489}
490
491void wxNotebook::SetImageList(wxImageList* imageList)
907f37b3 492{
07b8d7ec
VZ
493 wxNotebookBase::SetImageList(imageList);
494
495 if ( imageList )
1e6feb95 496 {
01c8cbf5 497 TabCtrl_SetImageList(GetHwnd(), (HIMAGELIST)imageList->GetHIMAGELIST());
1e6feb95 498 }
b656febd
VS
499}
500
d9506e77
VZ
501// ----------------------------------------------------------------------------
502// wxNotebook size settings
503// ----------------------------------------------------------------------------
504
c3732409
VZ
505wxRect wxNotebook::GetPageSize() const
506{
507 wxRect r;
508
509 RECT rc;
510 ::GetClientRect(GetHwnd(), &rc);
511
512 // This check is to work around a bug in TabCtrl_AdjustRect which will
628eae0b
VZ
513 // cause a crash on win2k or on XP with themes disabled if either
514 // wxNB_MULTILINE is used or tabs are placed on a side, if the rectangle
515 // is too small.
516 //
517 // The value of 20 is chosen arbitrarily but seems to work
518 if ( rc.right > 20 && rc.bottom > 20 )
c3732409 519 {
01c8cbf5 520 TabCtrl_AdjustRect(GetHwnd(), false, &rc);
c3732409
VZ
521
522 wxCopyRECTToRect(rc, r);
523 }
524
525 return r;
526}
527
d9506e77
VZ
528void wxNotebook::SetPageSize(const wxSize& size)
529{
530 // transform the page size into the notebook size
531 RECT rc;
532 rc.left =
533 rc.top = 0;
534 rc.right = size.x;
535 rc.bottom = size.y;
536
b8bdaa7c 537 TabCtrl_AdjustRect(GetHwnd(), true, &rc);
d9506e77
VZ
538
539 // and now set it
540 SetSize(rc.right - rc.left, rc.bottom - rc.top);
541}
542
543void wxNotebook::SetPadding(const wxSize& padding)
544{
545 TabCtrl_SetPadding(GetHwnd(), padding.x, padding.y);
546}
42e69d6b
VZ
547
548// Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
549// style.
550void wxNotebook::SetTabSize(const wxSize& sz)
551{
552 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE, 0, MAKELPARAM(sz.x, sz.y));
553}
554
2ce7af35
JS
555wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
556{
557 wxSize sizeTotal = sizePage;
078cf5cb 558
77ffb593 559 // We need to make getting tab size part of the wxWidgets API.
8b5d5223 560 wxSize tabSize;
2ce7af35
JS
561 if (GetPageCount() > 0)
562 {
563 RECT rect;
564 TabCtrl_GetItemRect((HWND) GetHWND(), 0, & rect);
565 tabSize.x = rect.right - rect.left;
566 tabSize.y = rect.bottom - rect.top;
567 }
568 if ( HasFlag(wxNB_LEFT) || HasFlag(wxNB_RIGHT) )
569 {
570 sizeTotal.x += tabSize.x + 7;
571 sizeTotal.y += 7;
572 }
573 else
574 {
575 sizeTotal.x += 7;
576 sizeTotal.y += tabSize.y + 7;
577 }
578
579 return sizeTotal;
580}
581
2015f2b3
VZ
582void wxNotebook::AdjustPageSize(wxNotebookPage *page)
583{
584 wxCHECK_RET( page, _T("NULL page in wxNotebook::AdjustPageSize") );
585
c3732409
VZ
586 const wxRect r = GetPageSize();
587 if ( !r.IsEmpty() )
14a6b6e5 588 {
c3732409 589 page->SetSize(r);
14a6b6e5 590 }
2015f2b3
VZ
591}
592
88310e2e
VZ
593// ----------------------------------------------------------------------------
594// wxNotebook operations
595// ----------------------------------------------------------------------------
596
621793f4 597// remove one page from the notebook, without deleting
8d34bf5c 598wxNotebookPage *wxNotebook::DoRemovePage(size_t nPage)
621793f4 599{
df7145da
VZ
600 wxNotebookPage *pageRemoved = wxNotebookBase::DoRemovePage(nPage);
601 if ( !pageRemoved )
602 return NULL;
621793f4 603
01c8cbf5 604 TabCtrl_DeleteItem(GetHwnd(), nPage);
621793f4 605
df7145da
VZ
606 if ( m_pages.IsEmpty() )
607 {
608 // no selection any more, the notebook becamse empty
609 m_nSelection = -1;
610 }
611 else // notebook still not empty
612 {
01c8cbf5 613 int selNew = TabCtrl_GetCurSel(GetHwnd());
623f5f70 614 if (selNew != -1)
df7145da 615 {
623f5f70 616 // No selection change, just refresh the current selection.
078cf5cb
WS
617 // Because it could be that the slection index changed
618 // we need to update it.
623f5f70
JS
619 // Note: this does not mean the selection it self changed.
620 m_nSelection = selNew;
621 m_pages[m_nSelection]->Refresh();
df7145da 622 }
623f5f70 623 else if (int(nPage) == m_nSelection)
43a997b6 624 {
623f5f70 625 // The selection was deleted.
078cf5cb 626
623f5f70
JS
627 // Determine new selection.
628 if (m_nSelection == int(GetPageCount()))
629 selNew = m_nSelection - 1;
630 else
631 selNew = m_nSelection;
078cf5cb 632
43a997b6
VZ
633 // m_nSelection must be always valid so reset it before calling
634 // SetSelection()
635 m_nSelection = -1;
636 SetSelection(selNew);
637 }
623f5f70
JS
638 else
639 {
640 wxFAIL; // Windows did not behave ok.
641 }
df7145da 642 }
47f12f58 643
df7145da 644 return pageRemoved;
621793f4
JS
645}
646
88310e2e
VZ
647// remove all pages
648bool wxNotebook::DeleteAllPages()
649{
8d34bf5c
VZ
650 size_t nPageCount = GetPageCount();
651 size_t nPage;
88310e2e 652 for ( nPage = 0; nPage < nPageCount; nPage++ )
1e6feb95 653 delete m_pages[nPage];
88310e2e 654
1e6feb95 655 m_pages.Clear();
88310e2e 656
01c8cbf5 657 TabCtrl_DeleteAllItems(GetHwnd());
907f37b3 658
47f12f58
JS
659 m_nSelection = -1;
660
37144cf0 661 InvalidateBestSize();
b8bdaa7c 662 return true;
88310e2e
VZ
663}
664
88310e2e 665// same as AddPage() but does it at given position
8d34bf5c 666bool wxNotebook::InsertPage(size_t nPage,
88310e2e
VZ
667 wxNotebookPage *pPage,
668 const wxString& strText,
669 bool bSelect,
670 int imageId)
671{
b8bdaa7c
VZ
672 wxCHECK_MSG( pPage != NULL, false, _T("NULL page in wxNotebook::InsertPage") );
673 wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false,
22f3361e 674 _T("invalid index in wxNotebook::InsertPage") );
88310e2e 675
efa14cf2
VZ
676 wxASSERT_MSG( pPage->GetParent() == this,
677 _T("notebook pages must have notebook as parent") );
43427087 678
22f3361e
VZ
679 // add a new tab to the control
680 // ----------------------------
58a8ab88 681
22f3361e
VZ
682 // init all fields to 0
683 TC_ITEM tcItem;
684 wxZeroMemory(tcItem);
58a8ab88 685
22f3361e
VZ
686 // set the image, if any
687 if ( imageId != -1 )
688 {
689 tcItem.mask |= TCIF_IMAGE;
690 tcItem.iImage = imageId;
691 }
88310e2e 692
22f3361e 693 // and the text
8b5d5223 694 if ( !strText.empty() )
22f3361e
VZ
695 {
696 tcItem.mask |= TCIF_TEXT;
697 tcItem.pszText = (wxChar *)strText.c_str(); // const_cast
698 }
43427087 699
e830a6a6
RD
700 // hide the page: unless it is selected, it shouldn't be shown (and if it
701 // is selected it will be shown later)
702 HWND hwnd = GetWinHwnd(pPage);
703 SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);
704
705 // this updates internal flag too -- otherwise it would get out of sync
706 // with the real state
707 pPage->Show(false);
708
709
22f3361e
VZ
710 // fit the notebook page to the tab control's display area: this should be
711 // done before adding it to the notebook or TabCtrl_InsertItem() will
712 // change the notebooks size itself!
2015f2b3 713 AdjustPageSize(pPage);
43427087 714
22f3361e 715 // finally do insert it
01c8cbf5 716 if ( TabCtrl_InsertItem(GetHwnd(), nPage, &tcItem) == -1 )
2015f2b3 717 {
22f3361e 718 wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());
88310e2e 719
b8bdaa7c 720 return false;
22f3361e 721 }
88310e2e 722
22f3361e
VZ
723 // succeeded: save the pointer to the page
724 m_pages.Insert(pPage, nPage);
42e69d6b 725
56b9925b
VZ
726 // we may need to adjust the size again if the notebook size changed:
727 // normally this only happens for the first page we add (the tabs which
728 // hadn't been there before are now shown) but for a multiline notebook it
729 // can happen for any page at all as a new row could have been started
730 if ( m_pages.GetCount() == 1 || HasFlag(wxNB_MULTILINE) )
2015f2b3
VZ
731 {
732 AdjustPageSize(pPage);
733 }
734
22f3361e
VZ
735 // now deal with the selection
736 // ---------------------------
737
738 // if the inserted page is before the selected one, we must update the
739 // index of the selected page
34a0c9f4 740 if ( int(nPage) <= m_nSelection )
22f3361e
VZ
741 {
742 // one extra page added
743 m_nSelection++;
744 }
745
746 // some page should be selected: either this one or the first one if there
747 // is still no selection
748 int selNew = -1;
749 if ( bSelect )
750 selNew = nPage;
751 else if ( m_nSelection == -1 )
752 selNew = 0;
753
754 if ( selNew != -1 )
755 SetSelection(selNew);
756
37144cf0 757 InvalidateBestSize();
25057aba 758
b8bdaa7c 759 return true;
88310e2e
VZ
760}
761
e450aa69 762int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
ef094fa0
JS
763{
764 TC_HITTESTINFO hitTestInfo;
765 hitTestInfo.pt.x = pt.x;
766 hitTestInfo.pt.y = pt.y;
e450aa69 767 int item = TabCtrl_HitTest(GetHwnd(), &hitTestInfo);
ef094fa0 768
e450aa69
VZ
769 if ( flags )
770 {
771 *flags = 0;
772
773 if ((hitTestInfo.flags & TCHT_NOWHERE) == TCHT_NOWHERE)
774 *flags |= wxNB_HITTEST_NOWHERE;
775 if ((hitTestInfo.flags & TCHT_ONITEM) == TCHT_ONITEM)
776 *flags |= wxNB_HITTEST_ONITEM;
777 if ((hitTestInfo.flags & TCHT_ONITEMICON) == TCHT_ONITEMICON)
778 *flags |= wxNB_HITTEST_ONICON;
779 if ((hitTestInfo.flags & TCHT_ONITEMLABEL) == TCHT_ONITEMLABEL)
780 *flags |= wxNB_HITTEST_ONLABEL;
781 }
ef094fa0
JS
782
783 return item;
784}
785
014ee083
VZ
786// ----------------------------------------------------------------------------
787// flicker-less notebook redraw
788// ----------------------------------------------------------------------------
789
790#if USE_NOTEBOOK_ANTIFLICKER
791
792// wnd proc for the spin button
793LRESULT APIENTRY _EXPORT wxNotebookSpinBtnWndProc(HWND hwnd,
794 UINT message,
795 WPARAM wParam,
796 LPARAM lParam)
797{
798 if ( message == WM_ERASEBKGND )
799 return 0;
800
801 return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebookSpinBtn,
802 hwnd, message, wParam, lParam);
803}
804
6143d3b6
VZ
805LRESULT APIENTRY _EXPORT wxNotebookWndProc(HWND hwnd,
806 UINT message,
807 WPARAM wParam,
808 LPARAM lParam)
809{
810 return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebook,
811 hwnd, message, wParam, lParam);
812}
813
814
014ee083
VZ
815
816void wxNotebook::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
817{
818 // do nothing here
819}
820
821void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event))
822{
823 wxPaintDC dc(this);
824 wxMemoryDC memdc;
825 RECT rc;
826 ::GetClientRect(GetHwnd(), &rc);
827 wxBitmap bmp(rc.right, rc.bottom);
828 memdc.SelectObject(bmp);
829
830 // if there is no special brush just use the solid background colour
831 HBRUSH hbr = (HBRUSH)m_hbrBackground;
e32703a9 832 wxBrush brush;
014ee083 833 if ( !hbr )
e32703a9
VZ
834 {
835 brush = wxBrush(GetBackgroundColour());
836 hbr = GetHbrushOf(brush);
837 }
014ee083
VZ
838
839 ::FillRect(GetHdcOf(memdc), &rc, hbr);
840
841 MSWDefWindowProc(WM_PAINT, (WPARAM)memdc.GetHDC(), 0);
842
843 dc.Blit(0, 0, rc.right, rc.bottom, &memdc, 0, 0);
844}
845
846#endif // USE_NOTEBOOK_ANTIFLICKER
e450aa69 847
88310e2e
VZ
848// ----------------------------------------------------------------------------
849// wxNotebook callbacks
850// ----------------------------------------------------------------------------
851
9026ad85 852void wxNotebook::OnSize(wxSizeEvent& event)
88310e2e 853{
7dccdf81 854 if ( GetPageCount() == 0 )
f7eaa62f
JS
855 {
856 // Prevents droppings on resize, but does cause some flicker
857 // when there are no pages.
2aa24b60 858 Refresh();
f7eaa62f
JS
859 event.Skip();
860 return;
861 }
254fbd14
JS
862#ifndef __WXWINCE__
863 else
864 {
865 // Without this, we can sometimes get droppings at the edges
866 // of a notebook, for example a notebook in a splitter window.
867 // This needs to be reconciled with the RefreshRect calls
868 // at the end of this function, which weren't enough to prevent
869 // the droppings.
01c8cbf5 870
254fbd14
JS
871 wxSize sz = GetClientSize();
872
873 // Refresh right side
874 wxRect rect(sz.x-4, 0, 4, sz.y);
875 RefreshRect(rect);
01c8cbf5 876
254fbd14
JS
877 // Refresh bottom side
878 rect = wxRect(0, sz.y-4, sz.x, 4);
879 RefreshRect(rect);
01c8cbf5 880
254fbd14
JS
881 // Refresh left side
882 rect = wxRect(0, 0, 4, sz.y);
883 RefreshRect(rect);
884 }
014ee083 885#endif // !__WXWINCE__
f7eaa62f 886
c1637c89 887 // fit all the notebook pages to the tab control's display area
56b9925b 888
c1637c89
VZ
889 RECT rc;
890 rc.left = rc.top = 0;
891 GetSize((int *)&rc.right, (int *)&rc.bottom);
56b9925b 892
c1637c89
VZ
893 // save the total size, we'll use it below
894 int widthNbook = rc.right - rc.left,
895 heightNbook = rc.bottom - rc.top;
896
897 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
898 // returns completely false values for multiline tab controls after the tabs
899 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
900 //
901 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
902 //
903 // and the only work around I could find was this ugly hack... without it
904 // simply toggling the "multiline" checkbox in the notebook sample resulted
905 // in a noticeable page displacement
906 if ( HasFlag(wxNB_MULTILINE) )
907 {
908 // avoid an infinite recursion: we get another notification too!
909 static bool s_isInOnSize = false;
4b7f2165 910
c1637c89
VZ
911 if ( !s_isInOnSize )
912 {
913 s_isInOnSize = true;
914 SendMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED,
915 MAKELPARAM(rc.right, rc.bottom));
916 s_isInOnSize = false;
917 }
918 }
b5c3b538 919
e2f6f8da
RD
920#if wxUSE_UXTHEME
921 // background bitmap size has changed, update the brush using it too
922 UpdateBgBrush();
923#endif // wxUSE_UXTHEME
924
01c8cbf5 925 TabCtrl_AdjustRect(GetHwnd(), false, &rc);
c1637c89
VZ
926
927 int width = rc.right - rc.left,
928 height = rc.bottom - rc.top;
929 size_t nCount = m_pages.Count();
930 for ( size_t nPage = 0; nPage < nCount; nPage++ ) {
931 wxNotebookPage *pPage = m_pages[nPage];
932 pPage->SetSize(rc.left, rc.top, width, height);
933 }
934
935
936 // unless we had already repainted everything, we now need to refresh
937 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
938 {
939 // invalidate areas not covered by pages
940 RefreshRect(wxRect(0, 0, widthNbook, rc.top), false);
941 RefreshRect(wxRect(0, rc.top, rc.left, height), false);
942 RefreshRect(wxRect(0, rc.bottom, widthNbook, heightNbook - rc.bottom),
943 false);
944 RefreshRect(wxRect(rc.right, rc.top, widthNbook - rc.bottom, height),
945 false);
946 }
947
014ee083
VZ
948#if USE_NOTEBOOK_ANTIFLICKER
949 // subclass the spin control used by the notebook to scroll pages to
950 // prevent it from flickering on resize
dfb47d83 951 if ( !m_hasSubclassedUpdown )
014ee083
VZ
952 {
953 // iterate over all child windows to find spin button
954 for ( HWND child = ::GetWindow(GetHwnd(), GW_CHILD);
955 child;
956 child = ::GetWindow(child, GW_HWNDNEXT) )
957 {
958 wxWindow *childWindow = wxFindWinFromHandle((WXHWND)child);
959
960 // see if it exists, if no wxWindow found then assume it's the spin
961 // btn
962 if ( !childWindow )
963 {
964 // subclass the spin button to override WM_ERASEBKGND
dfb47d83
VZ
965 if ( !gs_wndprocNotebookSpinBtn )
966 gs_wndprocNotebookSpinBtn = (WXFARPROC)wxGetWindowProc(child);
014ee083
VZ
967
968 wxSetWindowProc(child, wxNotebookSpinBtnWndProc);
dfb47d83 969 m_hasSubclassedUpdown = true;
014ee083
VZ
970 break;
971 }
972 }
973 }
974#endif // USE_NOTEBOOK_ANTIFLICKER
975
c1637c89 976 event.Skip();
88310e2e
VZ
977}
978
979void wxNotebook::OnSelChange(wxNotebookEvent& event)
980{
981 // is it our tab control?
982 if ( event.GetEventObject() == this )
5d1d2d46 983 {
5d1d2d46
VZ
984 int sel = event.GetOldSelection();
985 if ( sel != -1 )
b8bdaa7c 986 m_pages[sel]->Show(false);
0398b1d6 987
5d1d2d46
VZ
988 sel = event.GetSelection();
989 if ( sel != -1 )
990 {
1e6feb95 991 wxNotebookPage *pPage = m_pages[sel];
b8bdaa7c 992 pPage->Show(true);
2ff53fd3 993
306302e1
JS
994 // As per bug report:
995 // http://sourceforge.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863,
996 // we should not set the page focus (and thereby the focus for
997 // a child window) since it erroneously selects radio button controls and also
998 // breaks keyboard handling for a notebook's scroll buttons. So
999 // we always focus the notebook and not the page.
1000 SetFocus();
1d5b3bf0
VZ
1001
1002 }
1003 else // no pages in the notebook, give the focus to itself
1004 {
1005 SetFocus();
5d1d2d46 1006 }
0398b1d6 1007
5d1d2d46
VZ
1008 m_nSelection = sel;
1009 }
88310e2e
VZ
1010
1011 // we want to give others a chance to process this message as well
1012 event.Skip();
1013}
1014
b8bdaa7c 1015bool wxNotebook::MSWTranslateMessage(WXMSG *wxmsg)
88310e2e 1016{
b8bdaa7c 1017 const MSG * const msg = (MSG *)wxmsg;
88310e2e 1018
1d5b3bf0
VZ
1019 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
1020 // TAB will be passed to the currently selected page, CTRL+TAB and
1021 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
1022 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
1023 // process it.
b8bdaa7c 1024 if ( msg->message == WM_KEYDOWN && msg->wParam == VK_TAB &&
01c8cbf5 1025 msg->hwnd == GetHwnd() &&
1d5b3bf0 1026 (wxIsCtrlDown() || !wxIsShiftDown()) )
b8bdaa7c
VZ
1027 {
1028 return MSWProcessMessage(wxmsg);
1029 }
d9506e77 1030
b8bdaa7c 1031 return false;
88310e2e
VZ
1032}
1033
1034void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
1035{
d9506e77
VZ
1036 if ( event.IsWindowChange() ) {
1037 // change pages
1038 AdvanceSelection(event.GetDirection());
1039 }
1040 else {
b8bdaa7c 1041 // we get this event in 3 cases
d9506e77
VZ
1042 //
1043 // a) one of our pages might have generated it because the user TABbed
1044 // out from it in which case we should propagate the event upwards and
1045 // our parent will take care of setting the focus to prev/next sibling
1046 //
1047 // or
1048 //
1049 // b) the parent panel wants to give the focus to us so that we
1050 // forward it to our selected page. We can't deal with this in
1051 // OnSetFocus() because we don't know which direction the focus came
1052 // from in this case and so can't choose between setting the focus to
1053 // first or last panel child
b8bdaa7c
VZ
1054 //
1055 // or
1056 //
1057 // c) we ourselves (see MSWTranslateMessage) generated the event
1058 //
1059 wxWindow * const parent = GetParent();
1060
3c99602b
MB
1061 // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
1062 const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
1063 const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
b8bdaa7c
VZ
1064
1065 if ( isFromParent || isFromSelf )
d9506e77 1066 {
b8bdaa7c
VZ
1067 // no, it doesn't come from child, case (b) or (c): forward to a
1068 // page but only if direction is backwards (TAB) or from ourselves,
1069 if ( m_nSelection != -1 &&
1070 (!event.GetDirection() || isFromSelf) )
d9506e77
VZ
1071 {
1072 // so that the page knows that the event comes from it's parent
1073 // and is being propagated downwards
1074 event.SetEventObject(this);
1075
1e6feb95 1076 wxWindow *page = m_pages[m_nSelection];
d9506e77
VZ
1077 if ( !page->GetEventHandler()->ProcessEvent(event) )
1078 {
1079 page->SetFocus();
1080 }
1081 //else: page manages focus inside it itself
1082 }
b8bdaa7c 1083 else // otherwise set the focus to the notebook itself
d9506e77 1084 {
d9506e77
VZ
1085 SetFocus();
1086 }
1087 }
1088 else
1089 {
b8bdaa7c
VZ
1090 // it comes from our child, case (a), pass to the parent, but only
1091 // if the direction is forwards. Otherwise set the focus to the
1092 // notebook itself. The notebook is always the 'first' control of a
1093 // page.
1094 if ( !event.GetDirection() )
1095 {
1096 SetFocus();
1097 }
1098 else if ( parent )
1099 {
d9506e77
VZ
1100 event.SetCurrentFocus(this);
1101 parent->GetEventHandler()->ProcessEvent(event);
1102 }
1103 }
88310e2e 1104 }
88310e2e
VZ
1105}
1106
caf95d2a
VZ
1107#if wxUSE_UXTHEME
1108
c3732409 1109bool wxNotebook::DoDrawBackground(WXHDC hDC, wxWindow *child)
caf95d2a 1110{
c3732409
VZ
1111 wxUxThemeHandle theme(child ? child : this, L"TAB");
1112 if ( !theme )
1113 return false;
1114
1115 // get the notebook client rect (we're not interested in drawing tabs
1116 // themselves)
1117 wxRect r = GetPageSize();
1118 if ( r.IsEmpty() )
1119 return false;
1120
c4a95f6f 1121 RECT rc;
c3732409
VZ
1122 wxCopyRectToRECT(r, rc);
1123
1124 // map rect to the coords of the window we're drawing in
1125 if ( child )
1126 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1127
2ff53fd3
JS
1128 // we have the content area (page size), but we need to draw all of the
1129 // background for it to be aligned correctly
1130 wxUxThemeEngine::Get()->GetThemeBackgroundExtent
1131 (
1132 theme,
1133 (HDC) hDC,
1134 9 /* TABP_PANE */,
1135 0,
1136 &rc,
1137 &rc
1138 );
c3732409
VZ
1139 wxUxThemeEngine::Get()->DrawThemeBackground
1140 (
1141 theme,
92199f4c 1142 (HDC) hDC,
c3732409
VZ
1143 9 /* TABP_PANE */,
1144 0,
1145 &rc,
1146 NULL
1147 );
1148
1149 return true;
1150}
de359565 1151
c3732409
VZ
1152WXHBRUSH wxNotebook::QueryBgBitmap()
1153{
1154 wxRect r = GetPageSize();
1155 if ( r.IsEmpty() )
1156 return 0;
c4a95f6f
VZ
1157
1158 WindowHDC hDC(GetHwnd());
1159 MemoryHDC hDCMem(hDC);
c3732409 1160 CompatibleBitmap hBmp(hDC, r.x + r.width, r.y + r.height);
c4a95f6f
VZ
1161
1162 SelectInHDC selectBmp(hDCMem, hBmp);
caf95d2a 1163
c3732409
VZ
1164 if ( !DoDrawBackground((WXHDC)(HDC)hDCMem) )
1165 return 0;
0f770734 1166
de359565 1167 return (WXHBRUSH)::CreatePatternBrush(hBmp);
c4a95f6f 1168}
caf95d2a 1169
c4a95f6f
VZ
1170void wxNotebook::UpdateBgBrush()
1171{
1172 if ( m_hbrBackground )
1173 ::DeleteObject((HBRUSH)m_hbrBackground);
caf95d2a 1174
c4a95f6f
VZ
1175 if ( !m_hasBgCol && wxUxThemeEngine::GetIfActive() )
1176 {
de359565 1177 m_hbrBackground = QueryBgBitmap();
caf95d2a 1178 }
c3732409 1179 else // no themes or we've got user-defined solid colour
caf95d2a
VZ
1180 {
1181 m_hbrBackground = NULL;
1182 }
1183}
1184
2bae4332 1185WXHBRUSH wxNotebook::MSWGetBgBrushForChild(WXHDC hDC, WXHWND hWnd)
caf95d2a 1186{
caf95d2a
VZ
1187 if ( m_hbrBackground )
1188 {
1189 // before drawing with the background brush, we need to position it
1190 // correctly
caf95d2a 1191 RECT rc;
2bae4332 1192 ::GetWindowRect((HWND)hWnd, &rc);
caf95d2a
VZ
1193
1194 ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
1195
5c836c46 1196 if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
caf95d2a
VZ
1197 {
1198 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
1199 }
c4a95f6f
VZ
1200
1201 return m_hbrBackground;
5c836c46
VZ
1202 }
1203
2bae4332 1204 return wxNotebookBase::MSWGetBgBrushForChild(hDC, hWnd);
5c836c46 1205}
caf95d2a 1206
c3732409 1207bool wxNotebook::MSWPrintChild(WXHDC hDC, wxWindow *child)
07c19327 1208{
c3732409
VZ
1209 // solid background colour overrides themed background drawing
1210 if ( !UseBgCol() && DoDrawBackground(hDC, child) )
1211 return true;
de359565 1212
4dab5279
JS
1213 // If we're using a solid colour (for example if we've switched off
1214 // theming for this notebook), paint it
1215 if (UseBgCol())
1216 {
1217 wxRect r = GetPageSize();
1218 if ( r.IsEmpty() )
1219 return false;
1220
1221 RECT rc;
1222 wxCopyRectToRECT(r, rc);
1223
1224 // map rect to the coords of the window we're drawing in
1225 if ( child )
1226 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1227
1228 wxBrush brush(GetBackgroundColour());
1229 HBRUSH hbr = GetHbrushOf(brush);
01c8cbf5 1230
4dab5279
JS
1231 ::FillRect((HDC) hDC, &rc, hbr);
1232
1233 return true;
1234 }
1235
c3732409 1236 return wxNotebookBase::MSWPrintChild(hDC, child);
07c19327
VZ
1237}
1238
caf95d2a
VZ
1239#endif // wxUSE_UXTHEME
1240
25057aba
JS
1241// Windows only: attempts to get colour for UX theme page background
1242wxColour wxNotebook::GetThemeBackgroundColour() const
1243{
1244#if wxUSE_UXTHEME
1245 if (wxUxThemeEngine::Get())
1246 {
1247 wxUxThemeHandle hTheme((wxNotebook*) this, L"TAB");
1248 if (hTheme)
1249 {
1250 // This is total guesswork.
1251 // See PlatformSDK\Include\Tmschema.h for values
1252 COLORREF themeColor;
1253 wxUxThemeEngine::Get()->GetThemeColor(
1254 hTheme,
1255 10 /* TABP_BODY */,
1256 1 /* NORMAL */,
1257 3821 /* FILLCOLORHINT */,
1258 &themeColor);
1259
1260 /*
1261 [DS] Workaround for WindowBlinds:
1262 Some themes return a near black theme color using FILLCOLORHINT,
1263 this makes notebook pages have an ugly black background and makes
1264 text (usually black) unreadable. Retry again with FILLCOLOR.
1265
1266 This workaround potentially breaks appearance of some themes,
1267 but in practice it already fixes some themes.
1268 */
1269 if (themeColor == 1)
1270 {
1271 wxUxThemeEngine::Get()->GetThemeColor(
1272 hTheme,
1273 10 /* TABP_BODY */,
1274 1 /* NORMAL */,
1275 3802 /* FILLCOLOR */,
1276 &themeColor);
1277 }
1278
7dccdf81 1279 return wxRGBToColour(themeColor);
25057aba
JS
1280 }
1281 }
1282#endif // wxUSE_UXTHEME
1283
1284 return GetBackgroundColour();
1285}
1286
88310e2e
VZ
1287// ----------------------------------------------------------------------------
1288// wxNotebook base class virtuals
1289// ----------------------------------------------------------------------------
b5c3b538 1290
0b481c72
VZ
1291#if wxUSE_CONSTRAINTS
1292
b5c3b538
VZ
1293// override these 2 functions to do nothing: everything is done in OnSize
1294
4b7f2165 1295void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
b5c3b538
VZ
1296{
1297 // don't set the sizes of the pages - their correct size is not yet known
b8bdaa7c 1298 wxControl::SetConstraintSizes(false);
b5c3b538
VZ
1299}
1300
4b7f2165 1301bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
b5c3b538 1302{
b8bdaa7c 1303 return true;
b5c3b538
VZ
1304}
1305
0b481c72
VZ
1306#endif // wxUSE_CONSTRAINTS
1307
0df3fbd7
VZ
1308// ----------------------------------------------------------------------------
1309// wxNotebook Windows message handlers
1310// ----------------------------------------------------------------------------
1311
1312bool wxNotebook::MSWOnScroll(int orientation, WXWORD nSBCode,
1313 WXWORD pos, WXHWND control)
1314{
1315 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1316 // up-down control
1317 if ( control )
b8bdaa7c 1318 return false;
0df3fbd7
VZ
1319
1320 return wxNotebookBase::MSWOnScroll(orientation, nSBCode, pos, control);
1321}
1322
a23fd0e1 1323bool wxNotebook::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
88310e2e 1324{
93a19f17 1325 wxNotebookEvent event(wxEVT_NULL, m_windowId);
88310e2e
VZ
1326
1327 NMHDR* hdr = (NMHDR *)lParam;
1328 switch ( hdr->code ) {
1329 case TCN_SELCHANGE:
1330 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
1331 break;
1332
1333 case TCN_SELCHANGING:
1334 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
1335 break;
1336
fd3f686c 1337 default:
a23fd0e1 1338 return wxControl::MSWOnNotify(idCtrl, lParam, result);
88310e2e
VZ
1339 }
1340
01c8cbf5 1341 event.SetSelection(TabCtrl_GetCurSel(GetHwnd()));
93a19f17 1342 event.SetOldSelection(m_nSelection);
88310e2e 1343 event.SetEventObject(this);
a23fd0e1 1344 event.SetInt(idCtrl);
88310e2e 1345
fd3f686c
VZ
1346 bool processed = GetEventHandler()->ProcessEvent(event);
1347 *result = !event.IsAllowed();
1348 return processed;
88310e2e
VZ
1349}
1350
1e6feb95 1351#endif // wxUSE_NOTEBOOK