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