1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: implementation of wxNotebook
4 // Author: David Webster
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
20 #include "wx/dcclient.h"
21 #include "wx/string.h"
22 #include "wx/settings.h"
26 #include "wx/imaglist.h"
28 #include "wx/control.h"
29 #include "wx/notebook.h"
31 #include "wx/os2/private.h"
33 // ----------------------------------------------------------------------------
35 // ----------------------------------------------------------------------------
37 // check that the page index is valid
38 #define IS_VALID_PAGE(nPage) (((nPage) >= 0) && ((nPage) < GetPageCount()))
41 #define m_hWnd (HWND)GetHWND()
43 // ----------------------------------------------------------------------------
45 // ----------------------------------------------------------------------------
47 // ----------------------------------------------------------------------------
49 // ----------------------------------------------------------------------------
51 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
)
52 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
)
54 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
)
55 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange
)
56 EVT_SIZE(wxNotebook::OnSize
)
57 EVT_SET_FOCUS(wxNotebook::OnSetFocus
)
58 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
61 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
)
62 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxNotifyEvent
)
64 // ============================================================================
66 // ============================================================================
68 // ----------------------------------------------------------------------------
69 // wxNotebook construction
70 // ----------------------------------------------------------------------------
73 // Common part of all ctors
75 void wxNotebook::Init()
80 } // end of wxNotebook::Init
83 // Default for dynamic class
85 wxNotebook::wxNotebook()
88 } // end of wxNotebook::wxNotebook
91 // The same arguments as for wxControl
93 wxNotebook::wxNotebook(
99 , const wxString
& rsName
110 } // end of wxNotebook::wxNotebook
115 bool wxNotebook::Create(
118 , const wxPoint
& rPos
119 , const wxSize
& rSize
121 , const wxString
& rsName
127 if (!CreateControl( pParent
138 // Notebook, so explicitly specify 0 as last parameter
140 if (!OS2CreateControl( "NOTEBOOK"
144 ,lStyle
| wxTAB_TRAVERSAL
148 SetBackgroundColour(wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)));
150 } // end of wxNotebook::Create
152 WXDWORD
wxNotebook::OS2GetStyle (
154 , WXDWORD
* pdwExstyle
157 WXDWORD dwTabStyle
= wxControl::OS2GetStyle( lStyle
161 dwTabStyle
|= WS_TABSTOP
| BKS_SOLIDBIND
| BKS_ROUNDEDTABS
| BKS_TABTEXTCENTER
;
163 if (lStyle
& wxNB_BOTTOM
)
164 dwTabStyle
|= BKS_MAJORTABBOTTOM
| BKS_BACKPAGESBL
;
165 else if (lStyle
& wxNB_RIGHT
)
166 dwTabStyle
|= BKS_MAJORTABRIGHT
| BKS_BACKPAGESBR
;
167 else if (lStyle
& wxNB_LEFT
)
168 dwTabStyle
|= BKS_MAJORTABLEFT
| BKS_BACKPAGESTL
;
169 else // default to top
170 dwTabStyle
|= BKS_MAJORTABTOP
| BKS_BACKPAGESTR
;
178 // Note that we never want to have the default WS_EX_CLIENTEDGE style
179 // as it looks too ugly for the notebooks
184 } // end of wxNotebook::OS2GetStyle
186 // ----------------------------------------------------------------------------
187 // wxNotebook accessors
188 // ----------------------------------------------------------------------------
190 size_t wxNotebook::GetPageCount() const
192 int nPageInternal
= m_pages
.Count();
193 int nPageAPI
= (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT
, (MPARAM
)0, (MPARAM
)BKA_END
);
198 wxASSERT((int)m_pages
.Count() == (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT
, (MPARAM
)0, (MPARAM
)BKA_END
));
199 return m_pages
.Count();
200 } // end of wxNotebook::GetPageCount
202 int wxNotebook::GetRowCount() const
204 return (int)::WinSendMsg( GetHWND()
209 } // end of wxNotebook::GetRowCount
211 int wxNotebook::SetSelection(
215 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
217 if (nPage
!= m_nSelection
)
219 wxNotebookEvent
vEvent( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
223 vEvent
.SetSelection(nPage
);
224 vEvent
.SetOldSelection(m_nSelection
);
225 vEvent
.SetEventObject(this);
226 if (!GetEventHandler()->ProcessEvent(vEvent
) || vEvent
.IsAllowed())
230 // Program allows the page change
232 vEvent
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
233 GetEventHandler()->ProcessEvent(vEvent
);
235 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
237 ::WinSendMsg( GetHWND()
239 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
244 m_nSelection
= nPage
;
246 } // end of wxNotebook::SetSelection
248 bool wxNotebook::SetPageText(
250 , const wxString
& rsStrText
253 wxCHECK_MSG( IS_VALID_PAGE(nPage
), FALSE
, wxT("notebook page out of range") );
256 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
258 return (bool)::WinSendMsg( m_hWnd
260 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
261 ,MPFROMP((PSZ
)rsStrText
.c_str())
263 } // end of wxNotebook::SetPageText
265 wxString
wxNotebook::GetPageText (
274 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxT(""), wxT("notebook page out of range") );
277 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
279 memset(&vBookText
, '\0', sizeof(BOOKTEXT
));
280 vBookText
.textLen
= 0; // This will get the length
281 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
283 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
286 if (ulRc
== BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
288 if (ulRc
== BOOKERR_INVALID_PARAMETERS
)
290 wxLogError(wxT("Invalid Page Id for page text querry."));
292 return wxEmptyString
;
294 vBookText
.textLen
= ulRc
+ 1; // To get the null terminator
295 vBookText
.pString
= zBuf
;
298 // Now get the actual text
300 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
302 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
305 if (ulRc
== BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
307 return wxEmptyString
;
312 vBookText
.pString
[ulRc
] = '\0';
313 sStr
= vBookText
.pString
;
315 } // end of wxNotebook::GetPageText
317 int wxNotebook::GetPageImage (
321 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
324 // For OS/2 just return the page
327 } // end of wxNotebook::GetPageImage
329 bool wxNotebook::SetPageImage (
334 wxBitmap
* pBitmap
= (wxBitmap
*)m_imageList
->GetBitmap(nImage
);
337 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
339 return (bool)::WinSendMsg( GetHWND()
341 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
342 ,(MPARAM
)pBitmap
->GetHBITMAP()
344 } // end of wxNotebook::SetPageImage
346 void wxNotebook::SetImageList (
347 wxImageList
* WXUNUSED(pImageList
)
351 // Does nothing under OS/2
353 } // end of wxNotebook::SetImageList
355 // ----------------------------------------------------------------------------
356 // wxNotebook size settings
357 // ----------------------------------------------------------------------------
358 void wxNotebook::SetPageSize (
365 // Transform the page size into the notebook size
367 vRect
.xLeft
= vRect
.yTop
= 0;
368 vRect
.xRight
= rSize
.x
;
369 vRect
.yBottom
= rSize
.y
;
375 SetSize( vRect
.xRight
- vRect
.xLeft
376 ,vRect
.yBottom
- vRect
.yTop
378 } // end of wxNotebook::SetPageSize
380 void wxNotebook::SetPadding (
381 const wxSize
& WXUNUSED(rPadding
)
385 // No padding in OS/2
387 } // end of wxNotebook::SetPadding
389 void wxNotebook::SetTabSize (
393 ::WinSendMsg( GetHWND()
395 ,MPFROM2SHORT( (USHORT
)rSize
.x
398 ,(MPARAM
)BKA_MAJORTAB
400 } // end of wxNotebook::SetTabSize
402 // ----------------------------------------------------------------------------
403 // wxNotebook operations
404 // ----------------------------------------------------------------------------
407 // Remove one page from the notebook, without deleting
409 wxNotebookPage
* wxNotebook::DoRemovePage (
413 wxNotebookPage
* pPageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
419 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
421 ::WinSendMsg( GetHWND()
423 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
426 if (m_pages
.IsEmpty())
429 // No selection any more, the notebook becamse empty
433 else // notebook still not empty
436 // Change the selected page if it was deleted or became invalid
440 if (m_nSelection
== GetPageCount())
443 // Last page deleted, make the new last page the new selection
445 nSelNew
= m_nSelection
- 1;
447 else if (nPage
<= m_nSelection
)
450 // We must show another page, even if it has the same index
452 nSelNew
= m_nSelection
;
454 else // nothing changes for the currently selected page
459 // We still must refresh the current page: this needs to be done
460 // for some unknown reason if the tab control shows the up-down
461 // control (i.e. when there are too many pages) -- otherwise after
462 // deleting a page nothing at all is shown
464 m_pages
[m_nSelection
]->Refresh();
470 // m_nSelection must be always valid so reset it before calling
474 SetSelection(nSelNew
);
478 } // end of wxNotebook::DoRemovePage
483 bool wxNotebook::DeleteAllPages()
485 int nPageCount
= GetPageCount();
488 for (nPage
= 0; nPage
< nPageCount
; nPage
++)
489 delete m_pages
[nPage
];
491 ::WinSendMsg( GetHWND()
498 } // end of wxNotebook::DeleteAllPages
501 // Add a page to the notebook
503 bool wxNotebook::AddPage (
504 wxNotebookPage
* pPage
505 , const wxString
& rStrText
510 return InsertPage( GetPageCount()
516 } // end of wxNotebook::AddPage
519 // Same as AddPage() but does it at given position
521 bool wxNotebook::InsertPage (
523 , wxNotebookPage
* pPage
524 , const wxString
& rsStrText
531 wxASSERT( pPage
!= NULL
);
532 wxCHECK( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), FALSE
);
535 // Under OS/2 we can only insert FIRST, LAST, NEXT or PREV. Requires
536 // two different calls to the API. Page 1 uses the BKA_FIRST. Subsequent
537 // pages use the previous page ID coupled with a BKA_NEXT call. Unlike
538 // Windows, OS/2 uses an internal Page ID to ID the pages.
540 // OS/2 also has a nice auto-size feature that automatically sizes the
541 // the attached window so we don't have to worry about the size of the
542 // window on the page.
546 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
549 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_FIRST
)
556 vError
= ::WinGetLastError(vHabmain
);
557 sError
= wxPMErrorToStr(vError
);
560 m_alPageId
.Insert((long)ulApiPage
, nPage
);
564 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
566 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
- 1])
567 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_NEXT
)
574 vError
= ::WinGetLastError(vHabmain
);
575 sError
= wxPMErrorToStr(vError
);
578 m_alPageId
.Insert((long)ulApiPage
, nPage
);
582 // Associate a window handle with the page
586 if (!::WinSendMsg( GetHWND()
587 ,BKM_SETPAGEWINDOWHWND
588 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
589 ,MPFROMHWND(pPage
->GetHWND())
594 // If the inserted page is before the selected one, we must update the
595 // index of the selected page
597 if (nPage
<= m_nSelection
)
600 // One extra page added
608 // Save the pointer to the page
610 m_pages
.Insert( pPage
616 // Now set TAB dimenstions
619 wxWindowDC
vDC(this);
623 vDC
.GetTextExtent(rsStrText
, &nTextX
, &nTextY
);
626 if (nTextX
> m_nTabSize
)
629 ::WinSendMsg( GetHWND()
631 ,MPFROM2SHORT((USHORT
)m_nTabSize
, (USHORT
)nTextY
)
632 ,(MPARAM
)BKA_MAJORTAB
636 // Now set any TAB text
638 if (!rsStrText
.IsEmpty())
640 if (!SetPageText( nPage
647 // Now set any TAB bitmap image
651 if (!SetPageImage( nPage
660 // Don't show pages by default (we'll need to adjust their size first)
662 HWND hWnd
= GetWinHwnd(pPage
);
664 WinSetWindowULong( hWnd
666 ,WinQueryWindowULong( hWnd
672 // This updates internal flag too - otherwise it will get out of sync
678 // Some page should be selected: either this one or the first one if there is
679 // still no selection
685 else if ( m_nSelection
== -1 )
689 SetSelection(nSelNew
);
691 } // end of wxNotebook::InsertPage
693 // ----------------------------------------------------------------------------
694 // wxNotebook callbacks
695 // ----------------------------------------------------------------------------
696 void wxNotebook::OnSize(
701 int nCount
= (int)m_pages
.Count();
703 for (nPage
= 0; nPage
< nCount
; nPage
++)
705 if (m_nSelection
== nPage
)
706 m_pages
[nPage
]->Refresh();
708 ::WinSetWindowPos(m_pages
[nPage
]->GetHWND()
715 } // end of wxNotebook::OnSize
717 void wxNotebook::OnSelChange (
718 wxNotebookEvent
& rEvent
722 // Is it our tab control?
724 if (rEvent
.GetEventObject() == this)
726 int nPageCount
= GetPageCount();
728 ULONG ulOS2Sel
= (ULONG
)rEvent
.GetOldSelection();
731 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
733 if (ulOS2Sel
== m_alPageId
[nSel
])
743 m_pages
[nSel
]->Show(FALSE
);
745 ulOS2Sel
= (ULONG
)rEvent
.GetSelection();
749 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
751 if (ulOS2Sel
== m_alPageId
[nSel
])
761 wxNotebookPage
* pPage
= m_pages
[nSel
];
768 // We want to give others a chance to process this message as well
771 } // end of wxNotebook::OnSelChange
773 void wxNotebook::OnSetFocus (
778 // This function is only called when the focus is explicitly set (i.e. from
779 // the program) to the notebook - in this case we don't need the
780 // complicated OnNavigationKey() logic because the programmer knows better
783 // set focus to the currently selected page if any
785 if (m_nSelection
!= -1)
786 m_pages
[m_nSelection
]->SetFocus();
788 } // end of wxNotebook::OnSetFocus
790 void wxNotebook::OnNavigationKey (
791 wxNavigationKeyEvent
& rEvent
794 if (rEvent
.IsWindowChange())
799 AdvanceSelection(rEvent
.GetDirection());
804 // We get this event in 2 cases
806 // a) one of our pages might have generated it because the user TABbed
807 // out from it in which case we should propagate the event upwards and
808 // our parent will take care of setting the focus to prev/next sibling
812 // b) the parent panel wants to give the focus to us so that we
813 // forward it to our selected page. We can't deal with this in
814 // OnSetFocus() because we don't know which direction the focus came
815 // from in this case and so can't choose between setting the focus to
816 // first or last panel child
818 wxWindow
* pParent
= GetParent();
820 if (rEvent
.GetEventObject() == pParent
)
823 // No, it doesn't come from child, case (b): forward to a page
825 if (m_nSelection
!= -1)
828 // So that the page knows that the event comes from it's parent
829 // and is being propagated downwards
831 rEvent
.SetEventObject(this);
833 wxWindow
* pPage
= m_pages
[m_nSelection
];
835 if (!pPage
->GetEventHandler()->ProcessEvent(rEvent
))
839 //else: page manages focus inside it itself
844 // We have no pages - still have to give focus to _something_
852 // It comes from our child, case (a), pass to the parent
856 rEvent
.SetCurrentFocus(this);
857 pParent
->GetEventHandler()->ProcessEvent(rEvent
);
861 } // end of wxNotebook::OnNavigationKey
863 // ----------------------------------------------------------------------------
864 // wxNotebook base class virtuals
865 // ----------------------------------------------------------------------------
868 // Override these 2 functions to do nothing: everything is done in OnSize
870 void wxNotebook::SetConstraintSizes(
871 bool WXUNUSED(bRecurse
)
875 // Don't set the sizes of the pages - their correct size is not yet known
877 wxControl::SetConstraintSizes(FALSE
);
878 } // end of wxNotebook::SetConstraintSizes
880 bool wxNotebook::DoPhase (
885 } // end of wxNotebook::DoPhase
887 // ----------------------------------------------------------------------------
888 // wxNotebook Windows message handlers
889 // ----------------------------------------------------------------------------
890 bool wxNotebook::OS2OnScroll (
898 // Don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
903 return wxNotebookBase::OS2OnScroll( nOrientation
908 } // end of wxNotebook::OS2OnScroll
910 #endif // wxUSE_NOTEBOOK