]> git.saurik.com Git - wxWidgets.git/blob - src/msw/notebook.cpp
53046b87daf55ea2481abf1e6c2b4533e0b4fa9f
[wxWidgets.git] / src / msw / notebook.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/notebook.cpp
3 // Purpose: implementation of wxNotebook
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 11.06.98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_NOTEBOOK
20
21 // wxWidgets
22 #ifndef WX_PRECOMP
23 #include "wx/string.h"
24 #include "wx/dc.h"
25 #endif // WX_PRECOMP
26
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"
32 #include "wx/app.h"
33 #include "wx/sysopt.h"
34 #include "wx/dcclient.h"
35 #include "wx/dcmemory.h"
36
37 #include "wx/msw/private.h"
38
39 #include <windowsx.h>
40
41 #include <commctrl.h>
42
43 #include "wx/msw/winundef.h"
44
45 #if wxUSE_UXTHEME
46 #include "wx/msw/uxtheme.h"
47 #endif
48
49 // ----------------------------------------------------------------------------
50 // macros
51 // ----------------------------------------------------------------------------
52
53 // check that the page index is valid
54 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount())
55
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
59 #ifdef __WXWINCE__
60 // notebooks are never resized under CE anyhow
61 #define USE_NOTEBOOK_ANTIFLICKER 0
62 #else
63 #define USE_NOTEBOOK_ANTIFLICKER 1
64 #endif
65
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
83 // ----------------------------------------------------------------------------
84 // global variables
85 // ----------------------------------------------------------------------------
86
87 #if USE_NOTEBOOK_ANTIFLICKER
88
89 // the pointer to standard spin button wnd proc
90 static WXFARPROC gs_wndprocNotebookSpinBtn = (WXFARPROC)NULL;
91
92 // the pointer to standard tab control wnd proc
93 static WXFARPROC gs_wndprocNotebook = (WXFARPROC)NULL;
94
95 LRESULT APIENTRY _EXPORT wxNotebookWndProc(HWND hwnd,
96 UINT message,
97 WPARAM wParam,
98 LPARAM lParam);
99
100 #endif // USE_NOTEBOOK_ANTIFLICKER
101
102 // ----------------------------------------------------------------------------
103 // event table
104 // ----------------------------------------------------------------------------
105
106 #include "wx/listimpl.cpp"
107
108 WX_DEFINE_LIST( wxNotebookPageInfoList )
109
110 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED)
111 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING)
112
113 BEGIN_EVENT_TABLE(wxNotebook, wxControl)
114 EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, wxNotebook::OnSelChange)
115 EVT_SIZE(wxNotebook::OnSize)
116 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
117
118 #if USE_NOTEBOOK_ANTIFLICKER
119 EVT_ERASE_BACKGROUND(wxNotebook::OnEraseBackground)
120 EVT_PAINT(wxNotebook::OnPaint)
121 #endif // USE_NOTEBOOK_ANTIFLICKER
122 END_EVENT_TABLE()
123
124 #if wxUSE_EXTENDED_RTTI
125 WX_DEFINE_FLAGS( wxNotebookStyle )
126
127 wxBEGIN_FLAGS( wxNotebookStyle )
128 // new style border flags, we put them first to
129 // use them for streaming out
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)
136
137 // old style border flags
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)
143 wxFLAGS_MEMBER(wxBORDER)
144
145 // standard window styles
146 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
147 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
148 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
149 wxFLAGS_MEMBER(wxWANTS_CHARS)
150 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
151 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
152 wxFLAGS_MEMBER(wxVSCROLL)
153 wxFLAGS_MEMBER(wxHSCROLL)
154
155 wxFLAGS_MEMBER(wxNB_FIXEDWIDTH)
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)
161 wxFLAGS_MEMBER(wxNB_NOPAGETHEME)
162 wxFLAGS_MEMBER(wxNB_FLAT)
163
164 wxEND_FLAGS( wxNotebookStyle )
165
166 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebook, wxControl,"wx/notebook.h")
167 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebookPageInfo, wxObject , "wx/notebook.h" )
168
169 wxCOLLECTION_TYPE_INFO( wxNotebookPageInfo * , wxNotebookPageInfoList ) ;
170
171 template<> void wxCollectionToVariantArray( wxNotebookPageInfoList const &theList, wxxVariantArray &value)
172 {
173 wxListCollectionToVariantArray<wxNotebookPageInfoList::compatibility_iterator>( theList , value ) ;
174 }
175
176 wxBEGIN_PROPERTIES_TABLE(wxNotebook)
177 wxEVENT_PROPERTY( PageChanging , wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING , wxNotebookEvent )
178 wxEVENT_PROPERTY( PageChanged , wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED , wxNotebookEvent )
179
180 wxPROPERTY_COLLECTION( PageInfos , wxNotebookPageInfoList , wxNotebookPageInfo* , AddPageInfo , GetPageInfos , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
181 wxPROPERTY_FLAGS( WindowStyle , wxNotebookStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
182 wxEND_PROPERTIES_TABLE()
183
184 wxBEGIN_HANDLERS_TABLE(wxNotebook)
185 wxEND_HANDLERS_TABLE()
186
187 wxCONSTRUCTOR_5( wxNotebook , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle)
188
189
190 wxBEGIN_PROPERTIES_TABLE(wxNotebookPageInfo)
191 wxREADONLY_PROPERTY( Page , wxNotebookPage* , GetPage , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
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"))
195 wxEND_PROPERTIES_TABLE()
196
197 wxBEGIN_HANDLERS_TABLE(wxNotebookPageInfo)
198 wxEND_HANDLERS_TABLE()
199
200 wxCONSTRUCTOR_4( wxNotebookPageInfo , wxNotebookPage* , Page , wxString , Text , bool , Selected , int , ImageId )
201
202 #else
203 IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
204 IMPLEMENT_DYNAMIC_CLASS(wxNotebookPageInfo, wxObject )
205 #endif
206 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxNotifyEvent)
207
208 // ============================================================================
209 // implementation
210 // ============================================================================
211
212 // ----------------------------------------------------------------------------
213 // wxNotebook construction
214 // ----------------------------------------------------------------------------
215
216 const wxNotebookPageInfoList& wxNotebook::GetPageInfos() const
217 {
218 wxNotebookPageInfoList* list = const_cast< wxNotebookPageInfoList* >( &m_pageInfos ) ;
219 WX_CLEAR_LIST( wxNotebookPageInfoList , *list ) ;
220 for( size_t i = 0 ; i < GetPageCount() ; ++i )
221 {
222 wxNotebookPageInfo *info = new wxNotebookPageInfo() ;
223 info->Create( const_cast<wxNotebook*>(this)->GetPage(i) , GetPageText(i) , GetSelection() == int(i) , GetPageImage(i) ) ;
224 list->Append( info ) ;
225 }
226 return m_pageInfos ;
227 }
228
229 // common part of all ctors
230 void wxNotebook::Init()
231 {
232 m_imageList = NULL;
233 m_nSelection = -1;
234
235 #if wxUSE_UXTHEME
236 m_hbrBackground = NULL;
237 #endif // wxUSE_UXTHEME
238
239 #if USE_NOTEBOOK_ANTIFLICKER
240 m_hasSubclassedUpdown = false;
241 #endif // USE_NOTEBOOK_ANTIFLICKER
242 }
243
244 // default for dynamic class
245 wxNotebook::wxNotebook()
246 {
247 Init();
248 }
249
250 // the same arguments as for wxControl
251 wxNotebook::wxNotebook(wxWindow *parent,
252 wxWindowID id,
253 const wxPoint& pos,
254 const wxSize& size,
255 long style,
256 const wxString& name)
257 {
258 Init();
259
260 Create(parent, id, pos, size, style, name);
261 }
262
263 // Create() function
264 bool wxNotebook::Create(wxWindow *parent,
265 wxWindowID id,
266 const wxPoint& pos,
267 const wxSize& size,
268 long style,
269 const wxString& name)
270 {
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
277
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 )
282 {
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 {
288 style &= ~(wxBK_BOTTOM | wxBK_LEFT | wxBK_RIGHT);
289 }
290 }
291
292 LPCTSTR className = WC_TABCONTROL;
293
294 #if USE_NOTEBOOK_ANTIFLICKER
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
306 if ( ::GetClassInfo(NULL, WC_TABCONTROL, &wc) )
307 {
308 gs_wndprocNotebook =
309 wx_reinterpret_cast(WXFARPROC, wc.lpfnWndProc);
310 wc.lpszClassName = wxT("_wx_SysTabCtl32");
311 wc.style &= ~(CS_HREDRAW | CS_VREDRAW);
312 wc.hInstance = wxGetInstance();
313 wc.lpfnWndProc = wxNotebookWndProc;
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 }
331 #endif // USE_NOTEBOOK_ANTIFLICKER
332
333 if ( !CreateControl(parent, id, pos, size, style | wxTAB_TRAVERSAL,
334 wxDefaultValidator, name) )
335 return false;
336
337 if ( !MSWCreateControl(className, wxEmptyString, pos, size) )
338 return false;
339
340 #if wxUSE_UXTHEME
341 if ( HasFlag(wxNB_NOPAGETHEME) ||
342 wxSystemOptions::IsFalse(wxT("msw.notebook.themed-background")) )
343 {
344 SetBackgroundColour(GetThemeBackgroundColour());
345 }
346 else // use themed background by default
347 {
348 // create backing store
349 UpdateBgBrush();
350 }
351 #endif // wxUSE_UXTHEME
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 {
360 SendMessage(GetHwnd(), CCM_SETVERSION, COMCTL32_VERSION, 0);
361 if (!m_hasBgCol)
362 SetBackgroundColour(*wxWHITE);
363 }
364 #endif
365 return true;
366 }
367
368 WXDWORD wxNotebook::MSWGetStyle(long style, WXDWORD *exstyle) const
369 {
370 WXDWORD tabStyle = wxControl::MSWGetStyle(style, exstyle);
371
372 tabStyle |= WS_TABSTOP | TCS_TABS;
373
374 if ( style & wxNB_MULTILINE )
375 tabStyle |= TCS_MULTILINE;
376 if ( style & wxNB_FIXEDWIDTH )
377 tabStyle |= TCS_FIXEDWIDTH;
378
379 if ( style & wxBK_BOTTOM )
380 tabStyle |= TCS_RIGHT;
381 else if ( style & wxBK_LEFT )
382 tabStyle |= TCS_VERTICAL;
383 else if ( style & wxBK_RIGHT )
384 tabStyle |= TCS_VERTICAL | TCS_RIGHT;
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;
395 }
396
397 wxNotebook::~wxNotebook()
398 {
399 #if wxUSE_UXTHEME
400 if ( m_hbrBackground )
401 ::DeleteObject((HBRUSH)m_hbrBackground);
402 #endif // wxUSE_UXTHEME
403 }
404
405 // ----------------------------------------------------------------------------
406 // wxNotebook accessors
407 // ----------------------------------------------------------------------------
408
409 size_t wxNotebook::GetPageCount() const
410 {
411 // consistency check
412 wxASSERT( (int)m_pages.Count() == TabCtrl_GetItemCount(GetHwnd()) );
413
414 return m_pages.Count();
415 }
416
417 int wxNotebook::GetRowCount() const
418 {
419 return TabCtrl_GetRowCount(GetHwnd());
420 }
421
422 int wxNotebook::SetSelection(size_t nPage)
423 {
424 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
425
426 if ( int(nPage) != m_nSelection )
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
438 TabCtrl_SetCurSel(GetHwnd(), nPage);
439 }
440 }
441
442 return m_nSelection;
443 }
444
445 bool wxNotebook::SetPageText(size_t nPage, const wxString& strText)
446 {
447 wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
448
449 TC_ITEM tcItem;
450 tcItem.mask = TCIF_TEXT;
451 tcItem.pszText = (wxChar *)strText.c_str();
452
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;
469 }
470
471 wxString wxNotebook::GetPageText(size_t nPage) const
472 {
473 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxEmptyString, wxT("notebook page out of range") );
474
475 wxChar buf[256];
476 TC_ITEM tcItem;
477 tcItem.mask = TCIF_TEXT;
478 tcItem.pszText = buf;
479 tcItem.cchTextMax = WXSIZEOF(buf);
480
481 wxString str;
482 if ( TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) )
483 str = tcItem.pszText;
484
485 return str;
486 }
487
488 int wxNotebook::GetPageImage(size_t nPage) const
489 {
490 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
491
492 TC_ITEM tcItem;
493 tcItem.mask = TCIF_IMAGE;
494
495 return TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) ? tcItem.iImage : wxNOT_FOUND;
496 }
497
498 bool wxNotebook::SetPageImage(size_t nPage, int nImage)
499 {
500 wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
501
502 TC_ITEM tcItem;
503 tcItem.mask = TCIF_IMAGE;
504 tcItem.iImage = nImage;
505
506 return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
507 }
508
509 void wxNotebook::SetImageList(wxImageList* imageList)
510 {
511 wxNotebookBase::SetImageList(imageList);
512
513 if ( imageList )
514 {
515 (void) TabCtrl_SetImageList(GetHwnd(), (HIMAGELIST)imageList->GetHIMAGELIST());
516 }
517 }
518
519 // ----------------------------------------------------------------------------
520 // wxNotebook size settings
521 // ----------------------------------------------------------------------------
522
523 wxRect 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
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 )
537 {
538 TabCtrl_AdjustRect(GetHwnd(), false, &rc);
539
540 wxCopyRECTToRect(rc, r);
541 }
542
543 return r;
544 }
545
546 void 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
555 TabCtrl_AdjustRect(GetHwnd(), true, &rc);
556
557 // and now set it
558 SetSize(rc.right - rc.left, rc.bottom - rc.top);
559 }
560
561 void wxNotebook::SetPadding(const wxSize& padding)
562 {
563 TabCtrl_SetPadding(GetHwnd(), padding.x, padding.y);
564 }
565
566 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
567 // style.
568 void wxNotebook::SetTabSize(const wxSize& sz)
569 {
570 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE, 0, MAKELPARAM(sz.x, sz.y));
571 }
572
573 wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
574 {
575 wxSize sizeTotal = sizePage;
576
577 // We need to make getting tab size part of the wxWidgets API.
578 wxSize tabSize;
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 }
586 if ( HasFlag(wxBK_LEFT) || HasFlag(wxBK_RIGHT) )
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
600 void wxNotebook::AdjustPageSize(wxNotebookPage *page)
601 {
602 wxCHECK_RET( page, _T("NULL page in wxNotebook::AdjustPageSize") );
603
604 const wxRect r = GetPageSize();
605 if ( !r.IsEmpty() )
606 {
607 page->SetSize(r);
608 }
609 }
610
611 // ----------------------------------------------------------------------------
612 // wxNotebook operations
613 // ----------------------------------------------------------------------------
614
615 // remove one page from the notebook, without deleting
616 wxNotebookPage *wxNotebook::DoRemovePage(size_t nPage)
617 {
618 wxNotebookPage *pageRemoved = wxNotebookBase::DoRemovePage(nPage);
619 if ( !pageRemoved )
620 return NULL;
621
622 TabCtrl_DeleteItem(GetHwnd(), nPage);
623
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 {
631 int selNew = TabCtrl_GetCurSel(GetHwnd());
632 if (selNew != -1)
633 {
634 // No selection change, just refresh the current selection.
635 // Because it could be that the slection index changed
636 // we need to update it.
637 // Note: this does not mean the selection it self changed.
638 m_nSelection = selNew;
639 m_pages[m_nSelection]->Refresh();
640 }
641 else if (int(nPage) == m_nSelection)
642 {
643 // The selection was deleted.
644
645 // Determine new selection.
646 if (m_nSelection == int(GetPageCount()))
647 selNew = m_nSelection - 1;
648 else
649 selNew = m_nSelection;
650
651 // m_nSelection must be always valid so reset it before calling
652 // SetSelection()
653 m_nSelection = -1;
654 SetSelection(selNew);
655 }
656 else
657 {
658 wxFAIL; // Windows did not behave ok.
659 }
660 }
661
662 return pageRemoved;
663 }
664
665 // remove all pages
666 bool wxNotebook::DeleteAllPages()
667 {
668 size_t nPageCount = GetPageCount();
669 size_t nPage;
670 for ( nPage = 0; nPage < nPageCount; nPage++ )
671 delete m_pages[nPage];
672
673 m_pages.Clear();
674
675 TabCtrl_DeleteAllItems(GetHwnd());
676
677 m_nSelection = -1;
678
679 InvalidateBestSize();
680 return true;
681 }
682
683 // same as AddPage() but does it at given position
684 bool wxNotebook::InsertPage(size_t nPage,
685 wxNotebookPage *pPage,
686 const wxString& strText,
687 bool bSelect,
688 int imageId)
689 {
690 wxCHECK_MSG( pPage != NULL, false, _T("NULL page in wxNotebook::InsertPage") );
691 wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false,
692 _T("invalid index in wxNotebook::InsertPage") );
693
694 wxASSERT_MSG( pPage->GetParent() == this,
695 _T("notebook pages must have notebook as parent") );
696
697 // add a new tab to the control
698 // ----------------------------
699
700 // init all fields to 0
701 TC_ITEM tcItem;
702 wxZeroMemory(tcItem);
703
704 // set the image, if any
705 if ( imageId != -1 )
706 {
707 tcItem.mask |= TCIF_IMAGE;
708 tcItem.iImage = imageId;
709 }
710
711 // and the text
712 if ( !strText.empty() )
713 {
714 tcItem.mask |= TCIF_TEXT;
715 tcItem.pszText = (wxChar *)strText.c_str(); // const_cast
716 }
717
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
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!
731 AdjustPageSize(pPage);
732
733 // finally do insert it
734 if ( TabCtrl_InsertItem(GetHwnd(), nPage, &tcItem) == -1 )
735 {
736 wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());
737
738 return false;
739 }
740
741 // succeeded: save the pointer to the page
742 m_pages.Insert(pPage, nPage);
743
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) )
749 {
750 AdjustPageSize(pPage);
751 }
752
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
758 if ( int(nPage) <= m_nSelection )
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
775 InvalidateBestSize();
776
777 return true;
778 }
779
780 int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
781 {
782 TC_HITTESTINFO hitTestInfo;
783 hitTestInfo.pt.x = pt.x;
784 hitTestInfo.pt.y = pt.y;
785 int item = TabCtrl_HitTest(GetHwnd(), &hitTestInfo);
786
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 }
800
801 return item;
802 }
803
804 // ----------------------------------------------------------------------------
805 // flicker-less notebook redraw
806 // ----------------------------------------------------------------------------
807
808 #if USE_NOTEBOOK_ANTIFLICKER
809
810 // wnd proc for the spin button
811 LRESULT 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
823 LRESULT 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
832 void wxNotebook::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
833 {
834 // do nothing here
835 }
836
837 void 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
847 HBRUSH hbr = (HBRUSH)m_hbrBackground;
848 wxBrush brush;
849 if ( !hbr )
850 {
851 brush = wxBrush(GetBackgroundColour());
852 hbr = GetHbrushOf(brush);
853 }
854
855 ::FillRect(GetHdcOf(memdc), &rc, hbr);
856
857 MSWDefWindowProc(WM_PAINT, (WPARAM)memdc.GetHDC(), 0);
858
859 dc.Blit(0, 0, rc.right, rc.bottom, &memdc, 0, 0);
860 }
861
862 #endif // USE_NOTEBOOK_ANTIFLICKER
863
864 // ----------------------------------------------------------------------------
865 // wxNotebook callbacks
866 // ----------------------------------------------------------------------------
867
868 void wxNotebook::OnSize(wxSizeEvent& event)
869 {
870 if ( GetPageCount() == 0 )
871 {
872 // Prevents droppings on resize, but does cause some flicker
873 // when there are no pages.
874 Refresh();
875 event.Skip();
876 return;
877 }
878 #ifndef __WXWINCE__
879 else
880 {
881 // Without this, we can sometimes get droppings at the edges
882 // of a notebook, for example a notebook in a splitter window.
883 // This needs to be reconciled with the RefreshRect calls
884 // at the end of this function, which weren't enough to prevent
885 // the droppings.
886
887 wxSize sz = GetClientSize();
888
889 // Refresh right side
890 wxRect rect(sz.x-4, 0, 4, sz.y);
891 RefreshRect(rect);
892
893 // Refresh bottom side
894 rect = wxRect(0, sz.y-4, sz.x, 4);
895 RefreshRect(rect);
896
897 // Refresh left side
898 rect = wxRect(0, 0, 4, sz.y);
899 RefreshRect(rect);
900 }
901 #endif // !__WXWINCE__
902
903 // fit all the notebook pages to the tab control's display area
904
905 RECT rc;
906 rc.left = rc.top = 0;
907 GetSize((int *)&rc.right, (int *)&rc.bottom);
908
909 // save the total size, we'll use it below
910 int widthNbook = rc.right - rc.left,
911 heightNbook = rc.bottom - rc.top;
912
913 // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
914 // returns completely false values for multiline tab controls after the tabs
915 // are added but before getting the first WM_SIZE (off by ~50 pixels, see
916 //
917 // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
918 //
919 // and the only work around I could find was this ugly hack... without it
920 // simply toggling the "multiline" checkbox in the notebook sample resulted
921 // in a noticeable page displacement
922 if ( HasFlag(wxNB_MULTILINE) )
923 {
924 // avoid an infinite recursion: we get another notification too!
925 static bool s_isInOnSize = false;
926
927 if ( !s_isInOnSize )
928 {
929 s_isInOnSize = true;
930 SendMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED,
931 MAKELPARAM(rc.right, rc.bottom));
932 s_isInOnSize = false;
933 }
934 }
935
936 #if wxUSE_UXTHEME
937 // background bitmap size has changed, update the brush using it too
938 UpdateBgBrush();
939 #endif // wxUSE_UXTHEME
940
941 TabCtrl_AdjustRect(GetHwnd(), false, &rc);
942
943 int width = rc.right - rc.left,
944 height = rc.bottom - rc.top;
945 size_t nCount = m_pages.Count();
946 for ( size_t nPage = 0; nPage < nCount; nPage++ ) {
947 wxNotebookPage *pPage = m_pages[nPage];
948 pPage->SetSize(rc.left, rc.top, width, height);
949 }
950
951
952 // unless we had already repainted everything, we now need to refresh
953 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
954 {
955 // invalidate areas not covered by pages
956 RefreshRect(wxRect(0, 0, widthNbook, rc.top), false);
957 RefreshRect(wxRect(0, rc.top, rc.left, height), false);
958 RefreshRect(wxRect(0, rc.bottom, widthNbook, heightNbook - rc.bottom),
959 false);
960 RefreshRect(wxRect(rc.right, rc.top, widthNbook - rc.right, height),
961 false);
962 }
963
964 #if USE_NOTEBOOK_ANTIFLICKER
965 // subclass the spin control used by the notebook to scroll pages to
966 // prevent it from flickering on resize
967 if ( !m_hasSubclassedUpdown )
968 {
969 // iterate over all child windows to find spin button
970 for ( HWND child = ::GetWindow(GetHwnd(), GW_CHILD);
971 child;
972 child = ::GetWindow(child, GW_HWNDNEXT) )
973 {
974 wxWindow *childWindow = wxFindWinFromHandle((WXHWND)child);
975
976 // see if it exists, if no wxWindow found then assume it's the spin
977 // btn
978 if ( !childWindow )
979 {
980 // subclass the spin button to override WM_ERASEBKGND
981 if ( !gs_wndprocNotebookSpinBtn )
982 gs_wndprocNotebookSpinBtn = (WXFARPROC)wxGetWindowProc(child);
983
984 wxSetWindowProc(child, wxNotebookSpinBtnWndProc);
985 m_hasSubclassedUpdown = true;
986 break;
987 }
988 }
989 }
990 #endif // USE_NOTEBOOK_ANTIFLICKER
991
992 event.Skip();
993 }
994
995 void wxNotebook::OnSelChange(wxNotebookEvent& event)
996 {
997 // is it our tab control?
998 if ( event.GetEventObject() == this )
999 {
1000 int sel = event.GetOldSelection();
1001 if ( sel != -1 )
1002 m_pages[sel]->Show(false);
1003
1004 sel = event.GetSelection();
1005 if ( sel != -1 )
1006 {
1007 wxNotebookPage *pPage = m_pages[sel];
1008 pPage->Show(true);
1009 }
1010
1011 // Changing the page should give the focus to it but, as per bug report
1012 // http://sf.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863,
1013 // we should not set the focus to it directly since it erroneously
1014 // selects radio buttons and breaks keyboard handling for a notebook's
1015 // scroll buttons. So give focus to the notebook and not the page.
1016
1017 // but don't do this is the notebook is hidden
1018 if ( ::IsWindowVisible(GetHwnd()) )
1019 SetFocus();
1020
1021 m_nSelection = sel;
1022 }
1023
1024 // we want to give others a chance to process this message as well
1025 event.Skip();
1026 }
1027
1028 bool wxNotebook::MSWTranslateMessage(WXMSG *wxmsg)
1029 {
1030 const MSG * const msg = (MSG *)wxmsg;
1031
1032 // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
1033 // TAB will be passed to the currently selected page, CTRL+TAB and
1034 // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
1035 // intercept SHIFT+TAB. This goes to the parent of the notebook which will
1036 // process it.
1037 if ( msg->message == WM_KEYDOWN && msg->wParam == VK_TAB &&
1038 msg->hwnd == GetHwnd() &&
1039 (wxIsCtrlDown() || !wxIsShiftDown()) )
1040 {
1041 return MSWProcessMessage(wxmsg);
1042 }
1043
1044 return false;
1045 }
1046
1047 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
1048 {
1049 if ( event.IsWindowChange() ) {
1050 // change pages
1051 AdvanceSelection(event.GetDirection());
1052 }
1053 else {
1054 // we get this event in 3 cases
1055 //
1056 // a) one of our pages might have generated it because the user TABbed
1057 // out from it in which case we should propagate the event upwards and
1058 // our parent will take care of setting the focus to prev/next sibling
1059 //
1060 // or
1061 //
1062 // b) the parent panel wants to give the focus to us so that we
1063 // forward it to our selected page. We can't deal with this in
1064 // OnSetFocus() because we don't know which direction the focus came
1065 // from in this case and so can't choose between setting the focus to
1066 // first or last panel child
1067 //
1068 // or
1069 //
1070 // c) we ourselves (see MSWTranslateMessage) generated the event
1071 //
1072 wxWindow * const parent = GetParent();
1073
1074 // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
1075 const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
1076 const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
1077
1078 if ( isFromParent || isFromSelf )
1079 {
1080 // no, it doesn't come from child, case (b) or (c): forward to a
1081 // page but only if direction is backwards (TAB) or from ourselves,
1082 if ( m_nSelection != -1 &&
1083 (!event.GetDirection() || isFromSelf) )
1084 {
1085 // so that the page knows that the event comes from it's parent
1086 // and is being propagated downwards
1087 event.SetEventObject(this);
1088
1089 wxWindow *page = m_pages[m_nSelection];
1090 if ( !page->GetEventHandler()->ProcessEvent(event) )
1091 {
1092 page->SetFocus();
1093 }
1094 //else: page manages focus inside it itself
1095 }
1096 else // otherwise set the focus to the notebook itself
1097 {
1098 SetFocus();
1099 }
1100 }
1101 else
1102 {
1103 // it comes from our child, case (a), pass to the parent, but only
1104 // if the direction is forwards. Otherwise set the focus to the
1105 // notebook itself. The notebook is always the 'first' control of a
1106 // page.
1107 if ( !event.GetDirection() )
1108 {
1109 SetFocus();
1110 }
1111 else if ( parent )
1112 {
1113 event.SetCurrentFocus(this);
1114 parent->GetEventHandler()->ProcessEvent(event);
1115 }
1116 }
1117 }
1118 }
1119
1120 #if wxUSE_UXTHEME
1121
1122 bool wxNotebook::DoDrawBackground(WXHDC hDC, wxWindow *child)
1123 {
1124 wxUxThemeHandle theme(child ? child : this, L"TAB");
1125 if ( !theme )
1126 return false;
1127
1128 // get the notebook client rect (we're not interested in drawing tabs
1129 // themselves)
1130 wxRect r = GetPageSize();
1131 if ( r.IsEmpty() )
1132 return false;
1133
1134 RECT rc;
1135 wxCopyRectToRECT(r, rc);
1136
1137 // map rect to the coords of the window we're drawing in
1138 if ( child )
1139 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1140
1141 // we have the content area (page size), but we need to draw all of the
1142 // background for it to be aligned correctly
1143 wxUxThemeEngine::Get()->GetThemeBackgroundExtent
1144 (
1145 theme,
1146 (HDC) hDC,
1147 9 /* TABP_PANE */,
1148 0,
1149 &rc,
1150 &rc
1151 );
1152 wxUxThemeEngine::Get()->DrawThemeBackground
1153 (
1154 theme,
1155 (HDC) hDC,
1156 9 /* TABP_PANE */,
1157 0,
1158 &rc,
1159 NULL
1160 );
1161
1162 return true;
1163 }
1164
1165 WXHBRUSH wxNotebook::QueryBgBitmap()
1166 {
1167 wxRect r = GetPageSize();
1168 if ( r.IsEmpty() )
1169 return 0;
1170
1171 WindowHDC hDC(GetHwnd());
1172 MemoryHDC hDCMem(hDC);
1173 CompatibleBitmap hBmp(hDC, r.x + r.width, r.y + r.height);
1174
1175 SelectInHDC selectBmp(hDCMem, hBmp);
1176
1177 if ( !DoDrawBackground((WXHDC)(HDC)hDCMem) )
1178 return 0;
1179
1180 return (WXHBRUSH)::CreatePatternBrush(hBmp);
1181 }
1182
1183 void wxNotebook::UpdateBgBrush()
1184 {
1185 if ( m_hbrBackground )
1186 ::DeleteObject((HBRUSH)m_hbrBackground);
1187
1188 if ( !m_hasBgCol && wxUxThemeEngine::GetIfActive() )
1189 {
1190 m_hbrBackground = QueryBgBitmap();
1191 }
1192 else // no themes or we've got user-defined solid colour
1193 {
1194 m_hbrBackground = NULL;
1195 }
1196 }
1197
1198 WXHBRUSH wxNotebook::MSWGetBgBrushForChild(WXHDC hDC, WXHWND hWnd)
1199 {
1200 if ( m_hbrBackground )
1201 {
1202 // before drawing with the background brush, we need to position it
1203 // correctly
1204 RECT rc;
1205 ::GetWindowRect((HWND)hWnd, &rc);
1206
1207 ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
1208
1209 if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
1210 {
1211 wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
1212 }
1213
1214 return m_hbrBackground;
1215 }
1216
1217 return wxNotebookBase::MSWGetBgBrushForChild(hDC, hWnd);
1218 }
1219
1220 bool wxNotebook::MSWPrintChild(WXHDC hDC, wxWindow *child)
1221 {
1222 // solid background colour overrides themed background drawing
1223 if ( !UseBgCol() && DoDrawBackground(hDC, child) )
1224 return true;
1225
1226 // If we're using a solid colour (for example if we've switched off
1227 // theming for this notebook), paint it
1228 if (UseBgCol())
1229 {
1230 wxRect r = GetPageSize();
1231 if ( r.IsEmpty() )
1232 return false;
1233
1234 RECT rc;
1235 wxCopyRectToRECT(r, rc);
1236
1237 // map rect to the coords of the window we're drawing in
1238 if ( child )
1239 ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
1240
1241 wxBrush brush(GetBackgroundColour());
1242 HBRUSH hbr = GetHbrushOf(brush);
1243
1244 ::FillRect((HDC) hDC, &rc, hbr);
1245
1246 return true;
1247 }
1248
1249 return wxNotebookBase::MSWPrintChild(hDC, child);
1250 }
1251
1252 #endif // wxUSE_UXTHEME
1253
1254 // Windows only: attempts to get colour for UX theme page background
1255 wxColour wxNotebook::GetThemeBackgroundColour() const
1256 {
1257 #if wxUSE_UXTHEME
1258 if (wxUxThemeEngine::Get())
1259 {
1260 wxUxThemeHandle hTheme((wxNotebook*) this, L"TAB");
1261 if (hTheme)
1262 {
1263 // This is total guesswork.
1264 // See PlatformSDK\Include\Tmschema.h for values
1265 COLORREF themeColor;
1266 wxUxThemeEngine::Get()->GetThemeColor(
1267 hTheme,
1268 10 /* TABP_BODY */,
1269 1 /* NORMAL */,
1270 3821 /* FILLCOLORHINT */,
1271 &themeColor);
1272
1273 /*
1274 [DS] Workaround for WindowBlinds:
1275 Some themes return a near black theme color using FILLCOLORHINT,
1276 this makes notebook pages have an ugly black background and makes
1277 text (usually black) unreadable. Retry again with FILLCOLOR.
1278
1279 This workaround potentially breaks appearance of some themes,
1280 but in practice it already fixes some themes.
1281 */
1282 if (themeColor == 1)
1283 {
1284 wxUxThemeEngine::Get()->GetThemeColor(
1285 hTheme,
1286 10 /* TABP_BODY */,
1287 1 /* NORMAL */,
1288 3802 /* FILLCOLOR */,
1289 &themeColor);
1290 }
1291
1292 return wxRGBToColour(themeColor);
1293 }
1294 }
1295 #endif // wxUSE_UXTHEME
1296
1297 return GetBackgroundColour();
1298 }
1299
1300 // ----------------------------------------------------------------------------
1301 // wxNotebook base class virtuals
1302 // ----------------------------------------------------------------------------
1303
1304 #if wxUSE_CONSTRAINTS
1305
1306 // override these 2 functions to do nothing: everything is done in OnSize
1307
1308 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
1309 {
1310 // don't set the sizes of the pages - their correct size is not yet known
1311 wxControl::SetConstraintSizes(false);
1312 }
1313
1314 bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
1315 {
1316 return true;
1317 }
1318
1319 #endif // wxUSE_CONSTRAINTS
1320
1321 // ----------------------------------------------------------------------------
1322 // wxNotebook Windows message handlers
1323 // ----------------------------------------------------------------------------
1324
1325 bool wxNotebook::MSWOnScroll(int orientation, WXWORD nSBCode,
1326 WXWORD pos, WXHWND control)
1327 {
1328 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
1329 // up-down control
1330 if ( control )
1331 return false;
1332
1333 return wxNotebookBase::MSWOnScroll(orientation, nSBCode, pos, control);
1334 }
1335
1336 bool wxNotebook::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
1337 {
1338 wxNotebookEvent event(wxEVT_NULL, m_windowId);
1339
1340 NMHDR* hdr = (NMHDR *)lParam;
1341 switch ( hdr->code ) {
1342 case TCN_SELCHANGE:
1343 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
1344 break;
1345
1346 case TCN_SELCHANGING:
1347 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
1348 break;
1349
1350 default:
1351 return wxControl::MSWOnNotify(idCtrl, lParam, result);
1352 }
1353
1354 event.SetSelection(TabCtrl_GetCurSel(GetHwnd()));
1355 event.SetOldSelection(m_nSelection);
1356 event.SetEventObject(this);
1357 event.SetInt(idCtrl);
1358
1359 bool processed = GetEventHandler()->ProcessEvent(event);
1360 *result = !event.IsAllowed();
1361 return processed;
1362 }
1363
1364 #endif // wxUSE_NOTEBOOK