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