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