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 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
)
57 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
)
59 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
)
60 EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY
, wxNotebook::OnSelChange
)
61 EVT_SIZE(wxNotebook::OnSize
)
62 EVT_SET_FOCUS(wxNotebook::OnSetFocus
)
63 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
66 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
)
67 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxNotifyEvent
)
69 // ============================================================================
71 // ============================================================================
73 // ----------------------------------------------------------------------------
74 // wxNotebook construction
75 // ----------------------------------------------------------------------------
78 // Common part of all ctors
80 void wxNotebook::Init()
85 } // end of wxNotebook::Init
88 // Default for dynamic class
90 wxNotebook::wxNotebook()
93 } // end of wxNotebook::wxNotebook
96 // The same arguments as for wxControl
98 wxNotebook::wxNotebook(
101 , const wxPoint
& rPos
102 , const wxSize
& rSize
104 , const wxString
& rsName
115 } // end of wxNotebook::wxNotebook
120 bool wxNotebook::Create( wxWindow
* pParent
,
125 const wxString
& rsName
)
127 if ( (lStyle
& wxBK_ALIGN_MASK
) == wxBK_DEFAULT
)
132 if (!CreateControl( pParent
143 // Notebook, so explicitly specify 0 as last parameter
145 if (!OS2CreateControl( wxT("NOTEBOOK")
149 ,lStyle
| wxTAB_TRAVERSAL
153 SetBackgroundColour(wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)));
155 } // end of wxNotebook::Create
157 WXDWORD
wxNotebook::OS2GetStyle (
159 , WXDWORD
* pdwExstyle
162 WXDWORD dwTabStyle
= wxControl::OS2GetStyle( lStyle
166 dwTabStyle
|= WS_TABSTOP
| BKS_SOLIDBIND
| BKS_ROUNDEDTABS
| BKS_TABTEXTCENTER
| BKS_TABBEDDIALOG
;
168 if (lStyle
& wxBK_BOTTOM
)
169 dwTabStyle
|= BKS_MAJORTABBOTTOM
| BKS_BACKPAGESBL
;
170 else if (lStyle
& wxBK_RIGHT
)
171 dwTabStyle
|= BKS_MAJORTABRIGHT
| BKS_BACKPAGESBR
;
172 else if (lStyle
& wxBK_LEFT
)
173 dwTabStyle
|= BKS_MAJORTABLEFT
| BKS_BACKPAGESTL
;
174 else // default to top
175 dwTabStyle
|= BKS_MAJORTABTOP
| BKS_BACKPAGESTR
;
183 // Note that we never want to have the default WS_EX_CLIENTEDGE style
184 // as it looks too ugly for the notebooks
189 } // end of wxNotebook::OS2GetStyle
191 // ----------------------------------------------------------------------------
192 // wxNotebook accessors
193 // ----------------------------------------------------------------------------
195 size_t wxNotebook::GetPageCount() const
200 wxASSERT((int)m_pages
.Count() == (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT
, (MPARAM
)0, (MPARAM
)BKA_END
));
201 return m_pages
.Count();
202 } // end of wxNotebook::GetPageCount
204 int wxNotebook::GetRowCount() const
206 return (int)::WinSendMsg( GetHWND()
211 } // end of wxNotebook::GetRowCount
213 int wxNotebook::SetSelection( size_t nPage
)
215 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
217 if (nPage
!= (size_t)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 ::WinSendMsg( GetHWND()
237 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
242 m_nSelection
= nPage
;
244 } // end of wxNotebook::SetSelection
246 bool wxNotebook::SetPageText( size_t nPage
,
247 const wxString
& rsStrText
)
249 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
250 return (bool)::WinSendMsg( m_hWnd
252 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
253 ,MPFROMP((PSZ
)rsStrText
.c_str())
255 } // end of wxNotebook::SetPageText
257 wxString
wxNotebook::GetPageText ( size_t nPage
) const
264 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") );
266 memset(&vBookText
, '\0', sizeof(BOOKTEXT
));
267 vBookText
.textLen
= 0; // This will get the length
268 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
270 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
273 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
275 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
)
277 wxLogError(wxT("Invalid Page Id for page text querry."));
279 return wxEmptyString
;
281 vBookText
.textLen
= ulRc
+ 1; // To get the null terminator
282 vBookText
.pString
= (char*)zBuf
;
285 // Now get the actual text
287 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
289 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
292 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
294 return wxEmptyString
;
299 vBookText
.pString
[ulRc
] = '\0';
300 sStr
= (wxChar
*)vBookText
.pString
;
302 } // end of wxNotebook::GetPageText
304 int wxNotebook::GetPageImage ( size_t nPage
) const
306 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
309 // For OS/2 just return the page
312 } // end of wxNotebook::GetPageImage
314 bool wxNotebook::SetPageImage (
319 wxBitmap vBitmap
= (wxBitmap
)m_imageList
->GetBitmap(nImage
);
321 return (bool)::WinSendMsg( GetHWND()
323 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
324 ,(MPARAM
)wxFlipBmp(vBitmap
.GetHBITMAP())
326 } // end of wxNotebook::SetPageImage
328 void wxNotebook::SetImageList (
329 wxImageList
* pImageList
333 // Does not really do anything yet, but at least we need to
334 // update the base class.
336 wxNotebookBase::SetImageList(pImageList
);
337 } // end of wxNotebook::SetImageList
339 // ----------------------------------------------------------------------------
340 // wxNotebook size settings
341 // ----------------------------------------------------------------------------
342 void wxNotebook::SetPageSize (
347 } // end of wxNotebook::SetPageSize
349 void wxNotebook::SetPadding (
350 const wxSize
& WXUNUSED(rPadding
)
354 // No padding in OS/2
356 } // end of wxNotebook::SetPadding
358 void wxNotebook::SetTabSize (
362 ::WinSendMsg( GetHWND()
364 ,MPFROM2SHORT( (USHORT
)rSize
.x
367 ,(MPARAM
)BKA_MAJORTAB
369 } // end of wxNotebook::SetTabSize
371 // ----------------------------------------------------------------------------
372 // wxNotebook operations
373 // ----------------------------------------------------------------------------
376 // Remove one page from the notebook, without deleting
378 wxNotebookPage
* wxNotebook::DoRemovePage ( size_t nPage
)
380 wxNotebookPage
* pPageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
385 ::WinSendMsg( GetHWND()
387 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
390 if (m_pages
.IsEmpty())
393 // No selection any more, the notebook becamse empty
397 else // notebook still not empty
400 // Change the selected page if it was deleted or became invalid
404 if (m_nSelection
== (int)GetPageCount())
407 // Last page deleted, make the new last page the new selection
409 nSelNew
= m_nSelection
- 1;
411 else if (nPage
<= (size_t)m_nSelection
)
414 // We must show another page, even if it has the same index
416 nSelNew
= m_nSelection
;
418 else // nothing changes for the currently selected page
423 // We still must refresh the current page: this needs to be done
424 // for some unknown reason if the tab control shows the up-down
425 // control (i.e. when there are too many pages) -- otherwise after
426 // deleting a page nothing at all is shown
428 m_pages
[m_nSelection
]->Refresh();
434 // m_nSelection must be always valid so reset it before calling
438 SetSelection(nSelNew
);
442 } // end of wxNotebook::DoRemovePage
447 bool wxNotebook::DeleteAllPages()
449 int nPageCount
= GetPageCount();
452 for (nPage
= 0; nPage
< nPageCount
; nPage
++)
453 delete m_pages
[nPage
];
455 ::WinSendMsg( GetHWND()
463 } // end of wxNotebook::DeleteAllPages
466 // Add a page to the notebook
468 bool wxNotebook::AddPage (
469 wxNotebookPage
* pPage
470 , const wxString
& rStrText
475 return InsertPage( GetPageCount()
481 } // end of wxNotebook::AddPage
484 // Same as AddPage() but does it at given position
486 bool wxNotebook::InsertPage ( size_t nPage
,
487 wxNotebookPage
* pPage
,
488 const wxString
& rsStrText
,
494 wxASSERT( pPage
!= NULL
);
495 wxCHECK( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false );
498 // Under OS/2 we can only insert FIRST, LAST, NEXT or PREV. Requires
499 // two different calls to the API. Page 1 uses the BKA_FIRST. Subsequent
500 // pages use the previous page ID coupled with a BKA_NEXT call. Unlike
501 // Windows, OS/2 uses an internal Page ID to ID the pages.
503 // OS/2 also has a nice auto-size feature that automatically sizes the
504 // the attached window so we don't have to worry about the size of the
505 // window on the page.
509 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
512 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_FIRST
)
519 vError
= ::WinGetLastError(vHabmain
);
520 sError
= wxPMErrorToStr(vError
);
523 m_alPageId
.Insert((long)ulApiPage
, nPage
);
527 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
529 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
- 1])
530 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_NEXT
)
537 vError
= ::WinGetLastError(vHabmain
);
538 sError
= wxPMErrorToStr(vError
);
541 m_alPageId
.Insert((long)ulApiPage
, nPage
);
545 // Associate a window handle with the page
549 if (!::WinSendMsg( GetHWND()
550 ,BKM_SETPAGEWINDOWHWND
551 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
552 ,MPFROMHWND(pPage
->GetHWND())
557 // If the inserted page is before the selected one, we must update the
558 // index of the selected page
560 if (nPage
<= (size_t)m_nSelection
)
563 // One extra page added
571 // Save the pointer to the page
573 m_pages
.Insert( pPage
579 // Now set TAB dimenstions
582 wxWindowDC
vDC(this);
586 vDC
.GetTextExtent(rsStrText
, &nTextX
, &nTextY
);
588 nTextX
= (wxCoord
)(nTextX
* 1.3);
589 if (nTextX
> m_nTabSize
)
592 ::WinSendMsg( GetHWND()
594 ,MPFROM2SHORT((USHORT
)m_nTabSize
, (USHORT
)nTextY
)
595 ,(MPARAM
)BKA_MAJORTAB
599 // Now set any TAB text
601 if (!rsStrText
.empty())
603 if (!SetPageText( nPage
610 // Now set any TAB bitmap image
614 if (!SetPageImage( nPage
623 // Don't show pages by default (we'll need to adjust their size first)
625 HWND hWnd
= GetWinHwnd(pPage
);
627 WinSetWindowULong( hWnd
629 ,WinQueryWindowULong( hWnd
635 // This updates internal flag too - otherwise it will get out of sync
641 // Some page should be selected: either this one or the first one if there is
642 // still no selection
648 else if ( m_nSelection
== -1 )
652 SetSelection(nSelNew
);
654 InvalidateBestSize();
657 } // end of wxNotebook::InsertPage
659 // ----------------------------------------------------------------------------
660 // wxNotebook callbacks
661 // ----------------------------------------------------------------------------
662 void wxNotebook::OnSize(
667 } // end of wxNotebook::OnSize
669 void wxNotebook::OnSelChange (
670 wxNotebookEvent
& rEvent
674 // Is it our tab control?
676 if (rEvent
.GetEventObject() == this)
678 int nPageCount
= GetPageCount();
680 ULONG ulOS2Sel
= (ULONG
)rEvent
.GetOldSelection();
683 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
685 if (ulOS2Sel
== (ULONG
)m_alPageId
[nSel
])
695 m_pages
[nSel
]->Show(false);
697 ulOS2Sel
= (ULONG
)rEvent
.GetSelection();
701 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
703 if (ulOS2Sel
== (ULONG
)m_alPageId
[nSel
])
713 wxNotebookPage
* pPage
= m_pages
[nSel
];
720 // We want to give others a chance to process this message as well
723 } // end of wxNotebook::OnSelChange
725 void wxNotebook::OnSetFocus (
730 // This function is only called when the focus is explicitly set (i.e. from
731 // the program) to the notebook - in this case we don't need the
732 // complicated OnNavigationKey() logic because the programmer knows better
735 // set focus to the currently selected page if any
737 if (m_nSelection
!= -1)
738 m_pages
[m_nSelection
]->SetFocus();
740 } // end of wxNotebook::OnSetFocus
742 void wxNotebook::OnNavigationKey (
743 wxNavigationKeyEvent
& rEvent
746 if (rEvent
.IsWindowChange())
751 AdvanceSelection(rEvent
.GetDirection());
756 // We get this event in 2 cases
758 // a) one of our pages might have generated it because the user TABbed
759 // out from it in which case we should propagate the event upwards and
760 // our parent will take care of setting the focus to prev/next sibling
764 // b) the parent panel wants to give the focus to us so that we
765 // forward it to our selected page. We can't deal with this in
766 // OnSetFocus() because we don't know which direction the focus came
767 // from in this case and so can't choose between setting the focus to
768 // first or last panel child
770 wxWindow
* pParent
= GetParent();
772 if (rEvent
.GetEventObject() == pParent
)
775 // No, it doesn't come from child, case (b): forward to a page
777 if (m_nSelection
!= -1)
780 // So that the page knows that the event comes from it's parent
781 // and is being propagated downwards
783 rEvent
.SetEventObject(this);
785 wxWindow
* pPage
= m_pages
[m_nSelection
];
787 if (!pPage
->GetEventHandler()->ProcessEvent(rEvent
))
791 //else: page manages focus inside it itself
796 // We have no pages - still have to give focus to _something_
804 // It comes from our child, case (a), pass to the parent
808 rEvent
.SetCurrentFocus(this);
809 pParent
->GetEventHandler()->ProcessEvent(rEvent
);
813 } // end of wxNotebook::OnNavigationKey
815 // ----------------------------------------------------------------------------
816 // wxNotebook base class virtuals
817 // ----------------------------------------------------------------------------
820 // Override these 2 functions to do nothing: everything is done in OnSize
822 void wxNotebook::SetConstraintSizes( bool WXUNUSED(bRecurse
) )
825 // Don't set the sizes of the pages - their correct size is not yet known
827 wxControl::SetConstraintSizes(false);
828 } // end of wxNotebook::SetConstraintSizes
830 bool wxNotebook::DoPhase ( int WXUNUSED(nPhase
) )
833 } // end of wxNotebook::DoPhase
835 // ----------------------------------------------------------------------------
836 // wxNotebook Windows message handlers
837 // ----------------------------------------------------------------------------
838 bool wxNotebook::OS2OnScroll ( int nOrientation
,
844 // Don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
849 return wxNotebookBase::OS2OnScroll( nOrientation
854 } // end of wxNotebook::OS2OnScroll
856 #endif // wxUSE_NOTEBOOK