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