1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/os2/notebook.cpp
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"
17 #include "wx/notebook.h"
22 #include "wx/dcclient.h"
23 #include "wx/string.h"
24 #include "wx/settings.h"
27 #include "wx/control.h"
30 #include "wx/imaglist.h"
32 #include "wx/os2/private.h"
34 // ----------------------------------------------------------------------------
36 // ----------------------------------------------------------------------------
38 // check that the page index is valid
39 #define IS_VALID_PAGE(nPage) ( \
40 /* size_t is _always_ >= 0 */ \
41 /* ((nPage) >= 0) && */ \
42 ((nPage) < GetPageCount()) \
46 #define m_hWnd (HWND)GetHWND()
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 // ----------------------------------------------------------------------------
54 // ----------------------------------------------------------------------------
56 BEGIN_EVENT_TABLE(wxNotebook
, wxBookCtrlBase
)
57 EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY
, wxNotebook::OnSelChange
)
58 EVT_SIZE(wxNotebook::OnSize
)
59 EVT_SET_FOCUS(wxNotebook::OnSetFocus
)
60 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
63 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxBookCtrlBase
)
65 // ============================================================================
67 // ============================================================================
69 // ----------------------------------------------------------------------------
70 // wxNotebook construction
71 // ----------------------------------------------------------------------------
74 // Common part of all ctors
76 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( wxWindow
* pParent
,
120 const wxString
& rsName
)
122 if ( (lStyle
& wxBK_ALIGN_MASK
) == wxBK_DEFAULT
)
127 if (!CreateControl( pParent
138 // Notebook, so explicitly specify 0 as last parameter
140 if (!OS2CreateControl( wxT("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
| BKS_TABBEDDIALOG
;
163 if (lStyle
& wxBK_BOTTOM
)
164 dwTabStyle
|= BKS_MAJORTABBOTTOM
| BKS_BACKPAGESBL
;
165 else if (lStyle
& wxBK_RIGHT
)
166 dwTabStyle
|= BKS_MAJORTABRIGHT
| BKS_BACKPAGESBR
;
167 else if (lStyle
& wxBK_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
195 wxASSERT((int)m_pages
.Count() == (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT
, (MPARAM
)0, (MPARAM
)BKA_END
));
196 return m_pages
.Count();
197 } // end of wxNotebook::GetPageCount
199 int wxNotebook::GetRowCount() const
201 return (int)::WinSendMsg( GetHWND()
206 } // end of wxNotebook::GetRowCount
208 int wxNotebook::SetSelection( size_t nPage
)
210 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
212 if (nPage
!= (size_t)m_selection
)
214 wxBookCtrlEvent
vEvent( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
218 vEvent
.SetSelection(nPage
);
219 vEvent
.SetOldSelection(m_selection
);
220 vEvent
.SetEventObject(this);
221 if (!HandleWindowEvent(vEvent
) || vEvent
.IsAllowed())
225 // Program allows the page change
227 vEvent
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
228 HandleWindowEvent(vEvent
);
230 ::WinSendMsg( GetHWND()
232 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
239 } // end of wxNotebook::SetSelection
241 int wxNotebook::ChangeSelection( size_t nPage
)
243 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
245 if (nPage
!= (size_t)m_selection
)
247 ::WinSendMsg( GetHWND()
249 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
257 bool wxNotebook::SetPageText( size_t nPage
,
258 const wxString
& rsStrText
)
260 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
261 return (bool)::WinSendMsg( m_hWnd
263 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
264 ,MPFROMP((const char*)rsStrText
.c_str())
266 } // end of wxNotebook::SetPageText
268 wxString
wxNotebook::GetPageText ( size_t nPage
) const
275 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") );
277 memset(&vBookText
, '\0', sizeof(BOOKTEXT
));
278 vBookText
.textLen
= 0; // This will get the length
279 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
281 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
284 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
286 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
)
288 wxLogError(wxT("Invalid Page Id for page text querry."));
290 return wxEmptyString
;
292 vBookText
.textLen
= ulRc
+ 1; // To get the null terminator
293 vBookText
.pString
= (char*)zBuf
;
296 // Now get the actual text
298 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
300 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
303 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
305 return wxEmptyString
;
310 vBookText
.pString
[ulRc
] = '\0';
311 sStr
= (wxChar
*)vBookText
.pString
;
313 } // end of wxNotebook::GetPageText
315 int wxNotebook::GetPageImage ( size_t nPage
) const
317 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
320 // For OS/2 just return the page
323 } // end of wxNotebook::GetPageImage
325 bool wxNotebook::SetPageImage (
330 wxBitmap vBitmap
= (wxBitmap
)m_imageList
->GetBitmap(nImage
);
332 return (bool)::WinSendMsg( GetHWND()
334 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
335 ,(MPARAM
)wxCopyBmp(vBitmap
.GetHBITMAP(), true)
337 } // end of wxNotebook::SetPageImage
339 void wxNotebook::SetImageList (
340 wxImageList
* pImageList
344 // Does not really do anything yet, but at least we need to
345 // update the base class.
347 wxNotebookBase::SetImageList(pImageList
);
348 } // end of wxNotebook::SetImageList
350 // ----------------------------------------------------------------------------
351 // wxNotebook size settings
352 // ----------------------------------------------------------------------------
353 void wxNotebook::SetPageSize (
358 } // end of wxNotebook::SetPageSize
360 void wxNotebook::SetPadding (
361 const wxSize
& WXUNUSED(rPadding
)
365 // No padding in OS/2
367 } // end of wxNotebook::SetPadding
369 void wxNotebook::SetTabSize (
373 ::WinSendMsg( GetHWND()
375 ,MPFROM2SHORT( (USHORT
)rSize
.x
378 ,(MPARAM
)BKA_MAJORTAB
380 } // end of wxNotebook::SetTabSize
382 // ----------------------------------------------------------------------------
383 // wxNotebook operations
384 // ----------------------------------------------------------------------------
387 // Remove one page from the notebook, without deleting
389 wxNotebookPage
* wxNotebook::DoRemovePage ( size_t nPage
)
391 wxNotebookPage
* pPageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
396 ::WinSendMsg( GetHWND()
398 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
401 if (m_pages
.IsEmpty())
404 // No selection any more, the notebook becamse empty
406 m_selection
= wxNOT_FOUND
;
408 else // notebook still not empty
411 // Change the selected page if it was deleted or became invalid
415 if (m_selection
== (int)GetPageCount())
418 // Last page deleted, make the new last page the new selection
420 nSelNew
= m_selection
- 1;
422 else if (nPage
<= (size_t)m_selection
)
425 // We must show another page, even if it has the same index
427 nSelNew
= m_selection
;
429 else // nothing changes for the currently selected page
431 nSelNew
= wxNOT_FOUND
;
434 // We still must refresh the current page: this needs to be done
435 // for some unknown reason if the tab control shows the up-down
436 // control (i.e. when there are too many pages) -- otherwise after
437 // deleting a page nothing at all is shown
439 m_pages
[m_selection
]->Refresh();
442 if (nSelNew
!= wxNOT_FOUND
)
445 // m_selection must be always valid so reset it before calling
448 m_selection
= wxNOT_FOUND
;
449 SetSelection(nSelNew
);
453 } // end of wxNotebook::DoRemovePage
458 bool wxNotebook::DeleteAllPages()
460 int nPageCount
= GetPageCount();
463 for (nPage
= 0; nPage
< nPageCount
; nPage
++)
464 delete m_pages
[nPage
];
466 ::WinSendMsg( GetHWND()
471 m_selection
= wxNOT_FOUND
;
474 } // end of wxNotebook::DeleteAllPages
477 // Add a page to the notebook
479 bool wxNotebook::AddPage (
480 wxNotebookPage
* pPage
481 , const wxString
& rStrText
486 return InsertPage( GetPageCount()
492 } // end of wxNotebook::AddPage
495 // Same as AddPage() but does it at given position
497 bool wxNotebook::InsertPage ( size_t nPage
,
498 wxNotebookPage
* pPage
,
499 const wxString
& rsStrText
,
505 wxASSERT( pPage
!= NULL
);
506 wxCHECK( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false );
509 // Under OS/2 we can only insert FIRST, LAST, NEXT or PREV. Requires
510 // two different calls to the API. Page 1 uses the BKA_FIRST. Subsequent
511 // pages use the previous page ID coupled with a BKA_NEXT call. Unlike
512 // Windows, OS/2 uses an internal Page ID to ID the pages.
514 // OS/2 also has a nice auto-size feature that automatically sizes the
515 // the attached window so we don't have to worry about the size of the
516 // window on the page.
520 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
523 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_FIRST
)
530 vError
= ::WinGetLastError(vHabmain
);
531 sError
= wxPMErrorToStr(vError
);
534 m_alPageId
.Insert((long)ulApiPage
, nPage
);
538 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
540 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
- 1])
541 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_NEXT
)
548 vError
= ::WinGetLastError(vHabmain
);
549 sError
= wxPMErrorToStr(vError
);
552 m_alPageId
.Insert((long)ulApiPage
, nPage
);
556 // Associate a window handle with the page
560 if (!::WinSendMsg( GetHWND()
561 ,BKM_SETPAGEWINDOWHWND
562 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
563 ,MPFROMHWND(pPage
->GetHWND())
568 // If the inserted page is before the selected one, we must update the
569 // index of the selected page
571 if (nPage
<= (size_t)m_selection
)
574 // One extra page added
582 // Save the pointer to the page
584 m_pages
.Insert( pPage
590 // Now set TAB dimenstions
593 wxWindowDC
vDC(this);
597 vDC
.GetTextExtent(rsStrText
, &nTextX
, &nTextY
);
599 nTextX
= (wxCoord
)(nTextX
* 1.3);
600 if (nTextX
> m_nTabSize
)
603 ::WinSendMsg( GetHWND()
605 ,MPFROM2SHORT((USHORT
)m_nTabSize
, (USHORT
)nTextY
)
606 ,(MPARAM
)BKA_MAJORTAB
610 // Now set any TAB text
612 if (!rsStrText
.empty())
614 if (!SetPageText( nPage
621 // Now set any TAB bitmap image
625 if (!SetPageImage( nPage
634 // Don't show pages by default (we'll need to adjust their size first)
636 HWND hWnd
= GetWinHwnd(pPage
);
638 WinSetWindowULong( hWnd
640 ,WinQueryWindowULong( hWnd
646 // This updates internal flag too - otherwise it will get out of sync
651 DoSetSelectionAfterInsertion(nPage
, bSelect
);
653 InvalidateBestSize();
656 } // end of wxNotebook::InsertPage
658 // ----------------------------------------------------------------------------
659 // wxNotebook callbacks
660 // ----------------------------------------------------------------------------
661 void wxNotebook::OnSize(
666 } // end of wxNotebook::OnSize
668 void wxNotebook::OnSelChange (
669 wxBookCtrlEvent
& rEvent
673 // Is it our tab control?
675 if (rEvent
.GetEventObject() == this)
677 int nPageCount
= GetPageCount();
679 ULONG ulOS2Sel
= (ULONG
)rEvent
.GetOldSelection();
682 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
684 if (ulOS2Sel
== (ULONG
)m_alPageId
[nSel
])
694 m_pages
[nSel
]->Show(false);
696 ulOS2Sel
= (ULONG
)rEvent
.GetSelection();
700 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
702 if (ulOS2Sel
== (ULONG
)m_alPageId
[nSel
])
712 wxNotebookPage
* pPage
= m_pages
[nSel
];
719 // We want to give others a chance to process this message as well
722 } // end of wxNotebook::OnSelChange
724 void wxNotebook::OnSetFocus (
729 // This function is only called when the focus is explicitly set (i.e. from
730 // the program) to the notebook - in this case we don't need the
731 // complicated OnNavigationKey() logic because the programmer knows better
734 // set focus to the currently selected page if any
736 if (m_selection
!= wxNOT_FOUND
)
737 m_pages
[m_selection
]->SetFocus();
739 } // end of wxNotebook::OnSetFocus
741 void wxNotebook::OnNavigationKey (
742 wxNavigationKeyEvent
& rEvent
745 if (rEvent
.IsWindowChange())
750 AdvanceSelection(rEvent
.GetDirection());
755 // We get this event in 2 cases
757 // a) one of our pages might have generated it because the user TABbed
758 // out from it in which case we should propagate the event upwards and
759 // our parent will take care of setting the focus to prev/next sibling
763 // b) the parent panel wants to give the focus to us so that we
764 // forward it to our selected page. We can't deal with this in
765 // OnSetFocus() because we don't know which direction the focus came
766 // from in this case and so can't choose between setting the focus to
767 // first or last panel child
769 wxWindow
* pParent
= GetParent();
771 if (rEvent
.GetEventObject() == pParent
)
774 // No, it doesn't come from child, case (b): forward to a page
776 if (m_selection
!= wxNOT_FOUND
)
779 // So that the page knows that the event comes from it's parent
780 // and is being propagated downwards
782 rEvent
.SetEventObject(this);
784 wxWindow
* pPage
= m_pages
[m_selection
];
786 if (!pPage
->HandleWindowEvent(rEvent
))
790 //else: page manages focus inside it itself
795 // We have no pages - still have to give focus to _something_
803 // It comes from our child, case (a), pass to the parent
807 rEvent
.SetCurrentFocus(this);
808 pParent
->HandleWindowEvent(rEvent
);
812 } // end of wxNotebook::OnNavigationKey
814 // ----------------------------------------------------------------------------
815 // wxNotebook base class virtuals
816 // ----------------------------------------------------------------------------
819 // Override these 2 functions to do nothing: everything is done in OnSize
821 void wxNotebook::SetConstraintSizes( bool WXUNUSED(bRecurse
) )
824 // Don't set the sizes of the pages - their correct size is not yet known
826 wxControl::SetConstraintSizes(false);
827 } // end of wxNotebook::SetConstraintSizes
829 bool wxNotebook::DoPhase ( int WXUNUSED(nPhase
) )
832 } // end of wxNotebook::DoPhase
834 // ----------------------------------------------------------------------------
835 // wxNotebook Windows message handlers
836 // ----------------------------------------------------------------------------
837 bool wxNotebook::OS2OnScroll ( int nOrientation
,
843 // Don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
848 return wxNotebookBase::OS2OnScroll( nOrientation
853 } // end of wxNotebook::OS2OnScroll
855 #endif // wxUSE_NOTEBOOK