]> git.saurik.com Git - wxWidgets.git/blob - src/msw/notebook.cpp
7e4f7772c682a6771100af79d9573b2877526747
[wxWidgets.git] / src / msw / notebook.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "notebook.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #if wxUSE_NOTEBOOK
24
25 // wxWindows
26 #ifndef WX_PRECOMP
27 #include "wx/string.h"
28 #endif // WX_PRECOMP
29
30 #include "wx/log.h"
31 #include "wx/imaglist.h"
32 #include "wx/event.h"
33 #include "wx/control.h"
34 #include "wx/notebook.h"
35 #include "wx/app.h"
36
37 #include "wx/msw/private.h"
38
39 // Windows standard headers
40 #ifndef __WIN95__
41 #error "wxNotebook is only supported Windows 95 and above"
42 #endif //Win95
43
44 #include <windowsx.h> // for SetWindowFont
45
46 #ifdef __GNUWIN32_OLD__
47 #include "wx/msw/gnuwin32/extra.h"
48 #endif
49
50 #if defined(__WIN95__) && !(defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__))
51 #include <commctrl.h>
52 #endif
53
54 #include "wx/msw/winundef.h"
55
56 #if wxUSE_UXTHEME
57 #include "wx/msw/uxtheme.h"
58
59 #include "wx/radiobut.h"
60 #include "wx/radiobox.h"
61 #include "wx/checkbox.h"
62 #include "wx/bmpbuttn.h"
63 #include "wx/statline.h"
64 #include "wx/statbox.h"
65 #include "wx/stattext.h"
66 #include "wx/slider.h"
67 #include "wx/scrolwin.h"
68 #include "wx/panel.h"
69 #endif
70
71 // ----------------------------------------------------------------------------
72 // macros
73 // ----------------------------------------------------------------------------
74
75 // check that the page index is valid
76 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount())
77
78 // hide the ugly cast
79 #define m_hwnd (HWND)GetHWND()
80
81 // ----------------------------------------------------------------------------
82 // constants
83 // ----------------------------------------------------------------------------
84
85 // This is a work-around for missing defines in gcc-2.95 headers
86 #ifndef TCS_RIGHT
87 #define TCS_RIGHT 0x0002
88 #endif
89
90 #ifndef TCS_VERTICAL
91 #define TCS_VERTICAL 0x0080
92 #endif
93
94 #ifndef TCS_BOTTOM
95 #define TCS_BOTTOM TCS_RIGHT
96 #endif
97
98 // ----------------------------------------------------------------------------
99 // event table
100 // ----------------------------------------------------------------------------
101
102 #include <wx/listimpl.cpp>
103
104 WX_DEFINE_LIST( wxNotebookPageInfoList ) ;
105
106 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED)
107 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING)
108
109 BEGIN_EVENT_TABLE(wxNotebook, wxControl)
110 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange)
111
112 EVT_SIZE(wxNotebook::OnSize)
113
114 EVT_SET_FOCUS(wxNotebook::OnSetFocus)
115
116 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
117 END_EVENT_TABLE()
118
119 #if wxUSE_EXTENDED_RTTI
120 WX_DEFINE_FLAGS( wxNotebookStyle )
121
122 WX_BEGIN_FLAGS( wxNotebookStyle )
123 // new style border flags, we put them first to
124 // use them for streaming out
125 WX_FLAGS_MEMBER(wxBORDER_SIMPLE)
126 WX_FLAGS_MEMBER(wxBORDER_SUNKEN)
127 WX_FLAGS_MEMBER(wxBORDER_DOUBLE)
128 WX_FLAGS_MEMBER(wxBORDER_RAISED)
129 WX_FLAGS_MEMBER(wxBORDER_STATIC)
130 WX_FLAGS_MEMBER(wxBORDER_NONE)
131
132 // old style border flags
133 WX_FLAGS_MEMBER(wxSIMPLE_BORDER)
134 WX_FLAGS_MEMBER(wxSUNKEN_BORDER)
135 WX_FLAGS_MEMBER(wxDOUBLE_BORDER)
136 WX_FLAGS_MEMBER(wxRAISED_BORDER)
137 WX_FLAGS_MEMBER(wxSTATIC_BORDER)
138 WX_FLAGS_MEMBER(wxNO_BORDER)
139
140 // standard window styles
141 WX_FLAGS_MEMBER(wxTAB_TRAVERSAL)
142 WX_FLAGS_MEMBER(wxCLIP_CHILDREN)
143 WX_FLAGS_MEMBER(wxTRANSPARENT_WINDOW)
144 WX_FLAGS_MEMBER(wxWANTS_CHARS)
145 WX_FLAGS_MEMBER(wxNO_FULL_REPAINT_ON_RESIZE)
146 WX_FLAGS_MEMBER(wxALWAYS_SHOW_SB )
147 WX_FLAGS_MEMBER(wxVSCROLL)
148 WX_FLAGS_MEMBER(wxHSCROLL)
149
150 WX_FLAGS_MEMBER(wxNB_FIXEDWIDTH)
151 WX_FLAGS_MEMBER(wxNB_LEFT)
152 WX_FLAGS_MEMBER(wxNB_RIGHT)
153 WX_FLAGS_MEMBER(wxNB_BOTTOM)
154
155 WX_END_FLAGS( wxNotebookStyle )
156
157 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebook, wxControl,"wx/notebook.h")
158 IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebookPageInfo, wxObject , "wx/notebook.h" )
159
160 WX_COLLECTION_TYPE_INFO( wxNotebookPageInfo * , wxNotebookPageInfoList ) ;
161
162 template<> void wxCollectionToVariantArray( wxNotebookPageInfoList const &theList, wxxVariantArray &value)
163 {
164 wxListCollectionToVariantArray<wxNotebookPageInfoList::compatibility_iterator>( theList , value ) ;
165 }
166
167 WX_BEGIN_PROPERTIES_TABLE(wxNotebook)
168 WX_PROPERTY_COLLECTION( PageInfos , wxNotebookPageInfoList , wxNotebookPageInfo* , AddPageInfo , GetPageInfos , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
169 WX_PROPERTY_FLAGS( WindowStyle , wxNotebookStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
170 /*
171 notebookpage
172 object
173 object_ref
174 label
175 selected
176 style
177 usenotebooksizer
178 */
179 WX_END_PROPERTIES_TABLE()
180
181 WX_BEGIN_HANDLERS_TABLE(wxNotebook)
182 WX_END_HANDLERS_TABLE()
183
184 WX_CONSTRUCTOR_5( wxNotebook , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle)
185
186
187 WX_BEGIN_PROPERTIES_TABLE(wxNotebookPageInfo)
188 WX_READONLY_PROPERTY( Page , wxNotebookPage* , GetPage , , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
189 WX_READONLY_PROPERTY( Text , wxString , GetText , wxEmptyString , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
190 WX_READONLY_PROPERTY( Selected , bool , GetSelected , false, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
191 WX_READONLY_PROPERTY( ImageId , int , GetImageId , -1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
192 WX_END_PROPERTIES_TABLE()
193
194 WX_BEGIN_HANDLERS_TABLE(wxNotebookPageInfo)
195 WX_END_HANDLERS_TABLE()
196
197 WX_CONSTRUCTOR_4( wxNotebookPageInfo , wxNotebookPage* , Page , wxString , Text , bool , Selected , int , ImageId )
198
199 #else
200 IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
201 IMPLEMENT_DYNAMIC_CLASS(wxNotebookPageInfo, wxObject )
202 #endif
203 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxNotifyEvent)
204
205 // ============================================================================
206 // implementation
207 // ============================================================================
208
209 // ----------------------------------------------------------------------------
210 // wxNotebook construction
211 // ----------------------------------------------------------------------------
212
213 const wxNotebookPageInfoList& wxNotebook::GetPageInfos() const
214 {
215 wxNotebookPageInfoList* list = const_cast< wxNotebookPageInfoList* >( &m_pageInfos ) ;
216 WX_CLEAR_LIST( wxNotebookPageInfoList , *list ) ;
217 for( size_t i = 0 ; i < GetPageCount() ; ++i )
218 {
219 wxNotebookPageInfo *info = new wxNotebookPageInfo() ;
220 info->Create( const_cast<wxNotebook*>(this)->GetPage(i) , GetPageText(i) , GetSelection() == int(i) , GetPageImage(i) ) ;
221 list->Append( info ) ;
222 }
223 return m_pageInfos ;
224 }
225
226 // common part of all ctors
227 void wxNotebook::Init()
228 {
229 m_imageList = NULL;
230 m_nSelection = -1;
231 }
232
233 // default for dynamic class
234 wxNotebook::wxNotebook()
235 {
236 Init();
237 }
238
239 // the same arguments as for wxControl
240 wxNotebook::wxNotebook(wxWindow *parent,
241 wxWindowID id,
242 const wxPoint& pos,
243 const wxSize& size,
244 long style,
245 const wxString& name)
246 {
247 Init();
248
249 Create(parent, id, pos, size, style, name);
250 }
251
252 // Create() function
253 bool wxNotebook::Create(wxWindow *parent,
254 wxWindowID id,
255 const wxPoint& pos,
256 const wxSize& size,
257 long style,
258 const wxString& name)
259 {
260 // Does ComCtl32 support non-top tabs?
261 int verComCtl32 = wxApp::GetComCtl32Version();
262 if ( verComCtl32 < 470 || verComCtl32 >= 600 )
263 {
264 if (style & wxNB_BOTTOM)
265 style &= ~wxNB_BOTTOM;
266
267 if (style & wxNB_LEFT)
268 style &= ~wxNB_LEFT;
269
270 if (style & wxNB_RIGHT)
271 style &= ~wxNB_RIGHT;
272 }
273
274 if ( !CreateControl(parent, id, pos, size, style | wxTAB_TRAVERSAL,
275 wxDefaultValidator, name) )
276 return FALSE;
277
278 if ( !MSWCreateControl(WC_TABCONTROL, wxEmptyString, pos, size) )
279 return FALSE;
280
281 SetBackgroundColour(wxColour(::GetSysColor(COLOR_BTNFACE)));
282
283 return TRUE;
284 }
285
286 WXDWORD wxNotebook::MSWGetStyle(long style, WXDWORD *exstyle) const
287 {
288 WXDWORD tabStyle = wxControl::MSWGetStyle(style, exstyle);
289
290 tabStyle |= WS_TABSTOP | TCS_TABS;
291
292 if ( style & wxNB_MULTILINE )
293 tabStyle |= TCS_MULTILINE;
294 if ( style & wxNB_FIXEDWIDTH )
295 tabStyle |= TCS_FIXEDWIDTH;
296
297 if ( style & wxNB_BOTTOM )
298 tabStyle |= TCS_RIGHT;
299 else if ( style & wxNB_LEFT )
300 tabStyle |= TCS_VERTICAL;
301 else if ( style & wxNB_RIGHT )
302 tabStyle |= TCS_VERTICAL | TCS_RIGHT;
303
304 // ex style
305 if ( exstyle )
306 {
307 // note that we never want to have the default WS_EX_CLIENTEDGE style
308 // as it looks too ugly for the notebooks
309 *exstyle = 0;
310 }
311
312 return tabStyle;
313 }
314
315 // ----------------------------------------------------------------------------
316 // wxNotebook accessors
317 // ----------------------------------------------------------------------------
318
319 size_t wxNotebook::GetPageCount() const
320 {
321 // consistency check
322 wxASSERT( (int)m_pages.Count() == TabCtrl_GetItemCount(m_hwnd) );
323
324 return m_pages.Count();
325 }
326
327 int wxNotebook::GetRowCount() const
328 {
329 return TabCtrl_GetRowCount(m_hwnd);
330 }
331
332 int wxNotebook::SetSelection(size_t nPage)
333 {
334 wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") );
335
336 if ( int(nPage) != m_nSelection )
337 {
338 wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_windowId);
339 event.SetSelection(nPage);
340 event.SetOldSelection(m_nSelection);
341 event.SetEventObject(this);
342 if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
343 {
344 // program allows the page change
345 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
346 (void)GetEventHandler()->ProcessEvent(event);
347
348 TabCtrl_SetCurSel(m_hwnd, nPage);
349 }
350 }
351
352 return m_nSelection;
353 }
354
355 bool wxNotebook::SetPageText(size_t nPage, const wxString& strText)
356 {
357 wxCHECK_MSG( IS_VALID_PAGE(nPage), FALSE, wxT("notebook page out of range") );
358
359 TC_ITEM tcItem;
360 tcItem.mask = TCIF_TEXT;
361 tcItem.pszText = (wxChar *)strText.c_str();
362
363 return TabCtrl_SetItem(m_hwnd, nPage, &tcItem) != 0;
364 }
365
366 wxString wxNotebook::GetPageText(size_t nPage) const
367 {
368 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxEmptyString, wxT("notebook page out of range") );
369
370 wxChar buf[256];
371 TC_ITEM tcItem;
372 tcItem.mask = TCIF_TEXT;
373 tcItem.pszText = buf;
374 tcItem.cchTextMax = WXSIZEOF(buf);
375
376 wxString str;
377 if ( TabCtrl_GetItem(m_hwnd, nPage, &tcItem) )
378 str = tcItem.pszText;
379
380 return str;
381 }
382
383 int wxNotebook::GetPageImage(size_t nPage) const
384 {
385 wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") );
386
387 TC_ITEM tcItem;
388 tcItem.mask = TCIF_IMAGE;
389
390 return TabCtrl_GetItem(m_hwnd, nPage, &tcItem) ? tcItem.iImage : -1;
391 }
392
393 bool wxNotebook::SetPageImage(size_t nPage, int nImage)
394 {
395 wxCHECK_MSG( IS_VALID_PAGE(nPage), FALSE, wxT("notebook page out of range") );
396
397 TC_ITEM tcItem;
398 tcItem.mask = TCIF_IMAGE;
399 tcItem.iImage = nImage;
400
401 return TabCtrl_SetItem(m_hwnd, nPage, &tcItem) != 0;
402 }
403
404 void wxNotebook::SetImageList(wxImageList* imageList)
405 {
406 wxNotebookBase::SetImageList(imageList);
407
408 if ( imageList )
409 {
410 TabCtrl_SetImageList(m_hwnd, (HIMAGELIST)imageList->GetHIMAGELIST());
411 }
412 }
413
414 // ----------------------------------------------------------------------------
415 // wxNotebook size settings
416 // ----------------------------------------------------------------------------
417
418 void wxNotebook::SetPageSize(const wxSize& size)
419 {
420 // transform the page size into the notebook size
421 RECT rc;
422 rc.left =
423 rc.top = 0;
424 rc.right = size.x;
425 rc.bottom = size.y;
426
427 TabCtrl_AdjustRect(GetHwnd(), TRUE, &rc);
428
429 // and now set it
430 SetSize(rc.right - rc.left, rc.bottom - rc.top);
431 }
432
433 void wxNotebook::SetPadding(const wxSize& padding)
434 {
435 TabCtrl_SetPadding(GetHwnd(), padding.x, padding.y);
436 }
437
438 // Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
439 // style.
440 void wxNotebook::SetTabSize(const wxSize& sz)
441 {
442 ::SendMessage(GetHwnd(), TCM_SETITEMSIZE, 0, MAKELPARAM(sz.x, sz.y));
443 }
444
445 wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
446 {
447 wxSize sizeTotal = sizePage;
448
449 // We need to make getting tab size part of the wxWindows API.
450 wxSize tabSize(0, 0);
451 if (GetPageCount() > 0)
452 {
453 RECT rect;
454 TabCtrl_GetItemRect((HWND) GetHWND(), 0, & rect);
455 tabSize.x = rect.right - rect.left;
456 tabSize.y = rect.bottom - rect.top;
457 }
458 if ( HasFlag(wxNB_LEFT) || HasFlag(wxNB_RIGHT) )
459 {
460 sizeTotal.x += tabSize.x + 7;
461 sizeTotal.y += 7;
462 }
463 else
464 {
465 sizeTotal.x += 7;
466 sizeTotal.y += tabSize.y + 7;
467 }
468
469 return sizeTotal;
470 }
471
472 void wxNotebook::AdjustPageSize(wxNotebookPage *page)
473 {
474 wxCHECK_RET( page, _T("NULL page in wxNotebook::AdjustPageSize") );
475
476 RECT rc;
477 rc.left =
478 rc.top = 0;
479
480 // get the page size from the notebook size
481 GetSize((int *)&rc.right, (int *)&rc.bottom);
482 TabCtrl_AdjustRect(m_hwnd, FALSE, &rc);
483
484 page->SetSize(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
485 }
486
487 // ----------------------------------------------------------------------------
488 // wxNotebook operations
489 // ----------------------------------------------------------------------------
490
491 // remove one page from the notebook, without deleting
492 wxNotebookPage *wxNotebook::DoRemovePage(size_t nPage)
493 {
494 wxNotebookPage *pageRemoved = wxNotebookBase::DoRemovePage(nPage);
495 if ( !pageRemoved )
496 return NULL;
497
498 TabCtrl_DeleteItem(m_hwnd, nPage);
499
500 if ( m_pages.IsEmpty() )
501 {
502 // no selection any more, the notebook becamse empty
503 m_nSelection = -1;
504 }
505 else // notebook still not empty
506 {
507 // change the selected page if it was deleted or became invalid
508 int selNew;
509 if ( m_nSelection == int(GetPageCount()) )
510 {
511 // last page deleted, make the new last page the new selection
512 selNew = m_nSelection - 1;
513 }
514 else if ( int(nPage) <= m_nSelection )
515 {
516 // we must show another page, even if it has the same index
517 selNew = m_nSelection;
518 }
519 else // nothing changes for the currently selected page
520 {
521 selNew = -1;
522
523 // we still must refresh the current page: this needs to be done
524 // for some unknown reason if the tab control shows the up-down
525 // control (i.e. when there are too many pages) -- otherwise after
526 // deleting a page nothing at all is shown
527 if (m_nSelection >= 0)
528 m_pages[m_nSelection]->Refresh();
529 }
530
531 if ( selNew != -1 )
532 {
533 // m_nSelection must be always valid so reset it before calling
534 // SetSelection()
535 m_nSelection = -1;
536 SetSelection(selNew);
537 }
538 }
539
540 return pageRemoved;
541 }
542
543 // remove all pages
544 bool wxNotebook::DeleteAllPages()
545 {
546 size_t nPageCount = GetPageCount();
547 size_t nPage;
548 for ( nPage = 0; nPage < nPageCount; nPage++ )
549 delete m_pages[nPage];
550
551 m_pages.Clear();
552
553 TabCtrl_DeleteAllItems(m_hwnd);
554
555 m_nSelection = -1;
556
557 return TRUE;
558 }
559
560 // same as AddPage() but does it at given position
561 bool wxNotebook::InsertPage(size_t nPage,
562 wxNotebookPage *pPage,
563 const wxString& strText,
564 bool bSelect,
565 int imageId)
566 {
567 wxCHECK_MSG( pPage != NULL, FALSE, _T("NULL page in wxNotebook::InsertPage") );
568 wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), FALSE,
569 _T("invalid index in wxNotebook::InsertPage") );
570
571 wxASSERT_MSG( pPage->GetParent() == this,
572 _T("notebook pages must have notebook as parent") );
573
574 #if wxUSE_UXTHEME && wxUSE_UXTHEME_AUTO
575 static bool g_TestedForTheme = FALSE;
576 static bool g_UseTheme = FALSE;
577 if (!g_TestedForTheme)
578 {
579 int commCtrlVersion = wxTheApp->GetComCtl32Version() ;
580
581 g_UseTheme = (commCtrlVersion >= 600);
582 g_TestedForTheme = TRUE;
583 }
584
585 // Automatically apply the theme background,
586 // changing the colour of the panel to match the
587 // tab page colour. This won't work well with all
588 // themes but it's a start.
589 if (g_UseTheme && wxUxThemeEngine::Get() && pPage->IsKindOf(CLASSINFO(wxPanel)))
590 {
591 ApplyThemeBackground(pPage, GetThemeBackgroundColour());
592 }
593 #endif
594
595 // add a new tab to the control
596 // ----------------------------
597
598 // init all fields to 0
599 TC_ITEM tcItem;
600 wxZeroMemory(tcItem);
601
602 // set the image, if any
603 if ( imageId != -1 )
604 {
605 tcItem.mask |= TCIF_IMAGE;
606 tcItem.iImage = imageId;
607 }
608
609 // and the text
610 if ( !strText.IsEmpty() )
611 {
612 tcItem.mask |= TCIF_TEXT;
613 tcItem.pszText = (wxChar *)strText.c_str(); // const_cast
614 }
615
616 // fit the notebook page to the tab control's display area: this should be
617 // done before adding it to the notebook or TabCtrl_InsertItem() will
618 // change the notebooks size itself!
619 AdjustPageSize(pPage);
620
621 // finally do insert it
622 if ( TabCtrl_InsertItem(m_hwnd, nPage, &tcItem) == -1 )
623 {
624 wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());
625
626 return FALSE;
627 }
628
629 // succeeded: save the pointer to the page
630 m_pages.Insert(pPage, nPage);
631
632 // for the first page (only) we need to adjust the size again because the
633 // notebook size changed: the tabs which hadn't been there before are now
634 // shown
635 if ( m_pages.GetCount() == 1 )
636 {
637 AdjustPageSize(pPage);
638 }
639
640 // hide the page: unless it is selected, it shouldn't be shown (and if it
641 // is selected it will be shown later)
642 HWND hwnd = GetWinHwnd(pPage);
643 SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);
644
645 // this updates internal flag too -- otherwise it would get out of sync
646 // with the real state
647 pPage->Show(FALSE);
648
649
650 // now deal with the selection
651 // ---------------------------
652
653 // if the inserted page is before the selected one, we must update the
654 // index of the selected page
655 if ( int(nPage) <= m_nSelection )
656 {
657 // one extra page added
658 m_nSelection++;
659 }
660
661 // some page should be selected: either this one or the first one if there
662 // is still no selection
663 int selNew = -1;
664 if ( bSelect )
665 selNew = nPage;
666 else if ( m_nSelection == -1 )
667 selNew = 0;
668
669 if ( selNew != -1 )
670 SetSelection(selNew);
671
672 return TRUE;
673 }
674
675 int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
676 {
677 TC_HITTESTINFO hitTestInfo;
678 hitTestInfo.pt.x = pt.x;
679 hitTestInfo.pt.y = pt.y;
680 int item = TabCtrl_HitTest(GetHwnd(), &hitTestInfo);
681
682 if ( flags )
683 {
684 *flags = 0;
685
686 if ((hitTestInfo.flags & TCHT_NOWHERE) == TCHT_NOWHERE)
687 *flags |= wxNB_HITTEST_NOWHERE;
688 if ((hitTestInfo.flags & TCHT_ONITEM) == TCHT_ONITEM)
689 *flags |= wxNB_HITTEST_ONITEM;
690 if ((hitTestInfo.flags & TCHT_ONITEMICON) == TCHT_ONITEMICON)
691 *flags |= wxNB_HITTEST_ONICON;
692 if ((hitTestInfo.flags & TCHT_ONITEMLABEL) == TCHT_ONITEMLABEL)
693 *flags |= wxNB_HITTEST_ONLABEL;
694 }
695
696 return item;
697 }
698
699
700 // ----------------------------------------------------------------------------
701 // wxNotebook callbacks
702 // ----------------------------------------------------------------------------
703
704 void wxNotebook::OnSize(wxSizeEvent& event)
705 {
706 // fit the notebook page to the tab control's display area
707 RECT rc;
708 rc.left = rc.top = 0;
709 GetSize((int *)&rc.right, (int *)&rc.bottom);
710
711 TabCtrl_AdjustRect(m_hwnd, FALSE, &rc);
712
713 int width = rc.right - rc.left,
714 height = rc.bottom - rc.top;
715 size_t nCount = m_pages.Count();
716 for ( size_t nPage = 0; nPage < nCount; nPage++ ) {
717 wxNotebookPage *pPage = m_pages[nPage];
718 pPage->SetSize(rc.left, rc.top, width, height);
719 }
720
721 event.Skip();
722 }
723
724 void wxNotebook::OnSelChange(wxNotebookEvent& event)
725 {
726 // is it our tab control?
727 if ( event.GetEventObject() == this )
728 {
729 int sel = event.GetOldSelection();
730 if ( sel != -1 )
731 m_pages[sel]->Show(FALSE);
732
733 sel = event.GetSelection();
734 if ( sel != -1 )
735 {
736 wxNotebookPage *pPage = m_pages[sel];
737 pPage->Show(TRUE);
738 pPage->SetFocus();
739 }
740
741 m_nSelection = sel;
742 }
743
744 // we want to give others a chance to process this message as well
745 event.Skip();
746 }
747
748 void wxNotebook::OnSetFocus(wxFocusEvent& event)
749 {
750 // this function is only called when the focus is explicitly set (i.e. from
751 // the program) to the notebook - in this case we don't need the
752 // complicated OnNavigationKey() logic because the programmer knows better
753 // what [s]he wants
754
755 // set focus to the currently selected page if any
756 if ( m_nSelection != -1 )
757 m_pages[m_nSelection]->SetFocus();
758
759 event.Skip();
760 }
761
762 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
763 {
764 if ( event.IsWindowChange() ) {
765 // change pages
766 AdvanceSelection(event.GetDirection());
767 }
768 else {
769 // we get this event in 2 cases
770 //
771 // a) one of our pages might have generated it because the user TABbed
772 // out from it in which case we should propagate the event upwards and
773 // our parent will take care of setting the focus to prev/next sibling
774 //
775 // or
776 //
777 // b) the parent panel wants to give the focus to us so that we
778 // forward it to our selected page. We can't deal with this in
779 // OnSetFocus() because we don't know which direction the focus came
780 // from in this case and so can't choose between setting the focus to
781 // first or last panel child
782 wxWindow *parent = GetParent();
783 // the cast is here to fic a GCC ICE
784 if ( ((wxWindow*)event.GetEventObject()) == parent )
785 {
786 // no, it doesn't come from child, case (b): forward to a page
787 if ( m_nSelection != -1 )
788 {
789 // so that the page knows that the event comes from it's parent
790 // and is being propagated downwards
791 event.SetEventObject(this);
792
793 wxWindow *page = m_pages[m_nSelection];
794 if ( !page->GetEventHandler()->ProcessEvent(event) )
795 {
796 page->SetFocus();
797 }
798 //else: page manages focus inside it itself
799 }
800 else
801 {
802 // we have no pages - still have to give focus to _something_
803 SetFocus();
804 }
805 }
806 else
807 {
808 // it comes from our child, case (a), pass to the parent
809 if ( parent ) {
810 event.SetCurrentFocus(this);
811 parent->GetEventHandler()->ProcessEvent(event);
812 }
813 }
814 }
815 }
816
817 // ----------------------------------------------------------------------------
818 // wxNotebook base class virtuals
819 // ----------------------------------------------------------------------------
820
821 #if wxUSE_CONSTRAINTS
822
823 // override these 2 functions to do nothing: everything is done in OnSize
824
825 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
826 {
827 // don't set the sizes of the pages - their correct size is not yet known
828 wxControl::SetConstraintSizes(FALSE);
829 }
830
831 bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
832 {
833 return TRUE;
834 }
835
836 #endif // wxUSE_CONSTRAINTS
837
838 // ----------------------------------------------------------------------------
839 // wxNotebook Windows message handlers
840 // ----------------------------------------------------------------------------
841
842 bool wxNotebook::MSWOnScroll(int orientation, WXWORD nSBCode,
843 WXWORD pos, WXHWND control)
844 {
845 // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
846 // up-down control
847 if ( control )
848 return FALSE;
849
850 return wxNotebookBase::MSWOnScroll(orientation, nSBCode, pos, control);
851 }
852
853 bool wxNotebook::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
854 {
855 wxNotebookEvent event(wxEVT_NULL, m_windowId);
856
857 NMHDR* hdr = (NMHDR *)lParam;
858 switch ( hdr->code ) {
859 case TCN_SELCHANGE:
860 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
861 break;
862
863 case TCN_SELCHANGING:
864 event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
865 break;
866
867 default:
868 return wxControl::MSWOnNotify(idCtrl, lParam, result);
869 }
870
871 event.SetSelection(TabCtrl_GetCurSel(m_hwnd));
872 event.SetOldSelection(m_nSelection);
873 event.SetEventObject(this);
874 event.SetInt(idCtrl);
875
876 bool processed = GetEventHandler()->ProcessEvent(event);
877 *result = !event.IsAllowed();
878 return processed;
879 }
880
881 // Windows only: attempts to get colour for UX theme page background
882 wxColour wxNotebook::GetThemeBackgroundColour()
883 {
884 #if wxUSE_UXTHEME
885 if (wxUxThemeEngine::Get())
886 {
887 wxUxThemeHandle hTheme(this, L"TAB");
888 if (hTheme)
889 {
890 // This is total guesswork.
891 // See PlatformSDK\Include\Tmschema.h for values
892 COLORREF themeColor;
893 wxUxThemeEngine::Get()->GetThemeColor
894 (
895 hTheme,
896 10 /* TABP_BODY */,
897 1 /* NORMAL */,
898 3821, /* FILLCOLORHINT */
899 & themeColor
900 );
901
902 wxColour colour(GetRValue(themeColor), GetGValue(themeColor), GetBValue(themeColor));
903 return colour;
904 }
905 }
906 #endif // wxUSE_UXTHEME
907
908 return GetBackgroundColour();
909 }
910
911 // Windows only: attempts to apply the UX theme page background to this page
912 #if wxUSE_UXTHEME
913 void wxNotebook::ApplyThemeBackground(wxWindow* window, const wxColour& colour)
914 #else
915 void wxNotebook::ApplyThemeBackground(wxWindow*, const wxColour&)
916 #endif
917 {
918 #if wxUSE_UXTHEME
919 // Don't set the background for buttons since this will
920 // switch it into ownerdraw mode
921 if (window->IsKindOf(CLASSINFO(wxButton)) && !window->IsKindOf(CLASSINFO(wxBitmapButton)))
922 // This is essential, otherwise you'll see dark grey
923 // corners in the buttons.
924 ((wxButton*)window)->wxControl::SetBackgroundColour(colour);
925 else if (window->IsKindOf(CLASSINFO(wxStaticText)) ||
926 window->IsKindOf(CLASSINFO(wxStaticBox)) ||
927 window->IsKindOf(CLASSINFO(wxStaticLine)) ||
928 window->IsKindOf(CLASSINFO(wxRadioButton)) ||
929 window->IsKindOf(CLASSINFO(wxRadioBox)) ||
930 window->IsKindOf(CLASSINFO(wxCheckBox)) ||
931 window->IsKindOf(CLASSINFO(wxBitmapButton)) ||
932 window->IsKindOf(CLASSINFO(wxSlider)) ||
933 window->IsKindOf(CLASSINFO(wxPanel)) ||
934 (window->IsKindOf(CLASSINFO(wxNotebook)) && (window != this)) ||
935 window->IsKindOf(CLASSINFO(wxScrolledWindow))
936 )
937 {
938 window->SetBackgroundColour(colour);
939 }
940
941 for ( wxWindowList::compatibility_iterator node = window->GetChildren().GetFirst(); node; node = node->GetNext() )
942 {
943 wxWindow *child = node->GetData();
944 ApplyThemeBackground(child, colour);
945 }
946 #endif
947 }
948
949 long wxNotebook::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
950 {
951 static bool g_TestedForTheme = FALSE;
952 static bool g_UseTheme = FALSE;
953 switch ( nMsg )
954 {
955 case WM_ERASEBKGND:
956 {
957 if (!g_TestedForTheme)
958 {
959 int commCtrlVersion = wxTheApp->GetComCtl32Version() ;
960
961 g_UseTheme = (commCtrlVersion >= 600);
962 g_TestedForTheme = TRUE;
963 }
964
965 // If using XP themes, it seems we can get away
966 // with not drawing a background, which reduces flicker.
967 if (g_UseTheme)
968 return TRUE;
969 }
970 }
971
972 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
973 }
974
975
976 #endif // wxUSE_NOTEBOOK