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"
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) ( \
39 /* size_t is _always_ >= 0 */ \
40 /* ((nPage) >= 0) && */ \
41 ((nPage) < GetPageCount()) \
45 #define m_hWnd (HWND)GetHWND()
47 // ----------------------------------------------------------------------------
49 // ----------------------------------------------------------------------------
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
)
56 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
)
58 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
)
59 EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY
, wxNotebook::OnSelChange
)
60 EVT_SIZE(wxNotebook::OnSize
)
61 EVT_SET_FOCUS(wxNotebook::OnSetFocus
)
62 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
65 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
)
66 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxNotifyEvent
)
68 // ============================================================================
70 // ============================================================================
72 // ----------------------------------------------------------------------------
73 // wxNotebook construction
74 // ----------------------------------------------------------------------------
77 // Common part of all ctors
79 void wxNotebook::Init()
84 } // end of wxNotebook::Init
87 // Default for dynamic class
89 wxNotebook::wxNotebook()
92 } // end of wxNotebook::wxNotebook
95 // The same arguments as for wxControl
97 wxNotebook::wxNotebook(
100 , const wxPoint
& rPos
101 , const wxSize
& rSize
103 , const wxString
& rsName
114 } // end of wxNotebook::wxNotebook
119 bool wxNotebook::Create( wxWindow
* pParent
,
124 const wxString
& rsName
)
129 if (!CreateControl( pParent
140 // Notebook, so explicitly specify 0 as last parameter
142 if (!OS2CreateControl( wxT("NOTEBOOK")
146 ,lStyle
| wxTAB_TRAVERSAL
150 SetBackgroundColour(wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)));
152 } // end of wxNotebook::Create
154 WXDWORD
wxNotebook::OS2GetStyle (
156 , WXDWORD
* pdwExstyle
159 WXDWORD dwTabStyle
= wxControl::OS2GetStyle( lStyle
163 dwTabStyle
|= WS_TABSTOP
| BKS_SOLIDBIND
| BKS_ROUNDEDTABS
| BKS_TABTEXTCENTER
| BKS_TABBEDDIALOG
;
165 if (lStyle
& wxBK_BOTTOM
)
166 dwTabStyle
|= BKS_MAJORTABBOTTOM
| BKS_BACKPAGESBL
;
167 else if (lStyle
& wxBK_RIGHT
)
168 dwTabStyle
|= BKS_MAJORTABRIGHT
| BKS_BACKPAGESBR
;
169 else if (lStyle
& wxBK_LEFT
)
170 dwTabStyle
|= BKS_MAJORTABLEFT
| BKS_BACKPAGESTL
;
171 else // default to top
172 dwTabStyle
|= BKS_MAJORTABTOP
| BKS_BACKPAGESTR
;
180 // Note that we never want to have the default WS_EX_CLIENTEDGE style
181 // as it looks too ugly for the notebooks
186 } // end of wxNotebook::OS2GetStyle
188 // ----------------------------------------------------------------------------
189 // wxNotebook accessors
190 // ----------------------------------------------------------------------------
192 size_t wxNotebook::GetPageCount() const
197 wxASSERT((int)m_pages
.Count() == (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT
, (MPARAM
)0, (MPARAM
)BKA_END
));
198 return m_pages
.Count();
199 } // end of wxNotebook::GetPageCount
201 int wxNotebook::GetRowCount() const
203 return (int)::WinSendMsg( GetHWND()
208 } // end of wxNotebook::GetRowCount
210 int wxNotebook::SetSelection( size_t nPage
)
212 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
214 if (nPage
!= (size_t)m_nSelection
)
216 wxNotebookEvent
vEvent( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
220 vEvent
.SetSelection(nPage
);
221 vEvent
.SetOldSelection(m_nSelection
);
222 vEvent
.SetEventObject(this);
223 if (!GetEventHandler()->ProcessEvent(vEvent
) || vEvent
.IsAllowed())
227 // Program allows the page change
229 vEvent
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
230 GetEventHandler()->ProcessEvent(vEvent
);
232 ::WinSendMsg( GetHWND()
234 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
239 m_nSelection
= nPage
;
241 } // end of wxNotebook::SetSelection
243 bool wxNotebook::SetPageText( size_t nPage
,
244 const wxString
& rsStrText
)
246 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
247 return (bool)::WinSendMsg( m_hWnd
249 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
250 ,MPFROMP((PSZ
)rsStrText
.c_str())
252 } // end of wxNotebook::SetPageText
254 wxString
wxNotebook::GetPageText ( size_t nPage
) const
261 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") );
263 memset(&vBookText
, '\0', sizeof(BOOKTEXT
));
264 vBookText
.textLen
= 0; // This will get the length
265 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
267 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
270 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
272 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
)
274 wxLogError(wxT("Invalid Page Id for page text querry."));
276 return wxEmptyString
;
278 vBookText
.textLen
= ulRc
+ 1; // To get the null terminator
279 vBookText
.pString
= (char*)zBuf
;
282 // Now get the actual text
284 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
286 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
289 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
291 return wxEmptyString
;
296 vBookText
.pString
[ulRc
] = '\0';
297 sStr
= (wxChar
*)vBookText
.pString
;
299 } // end of wxNotebook::GetPageText
301 int wxNotebook::GetPageImage ( size_t nPage
) const
303 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
306 // For OS/2 just return the page
309 } // end of wxNotebook::GetPageImage
311 bool wxNotebook::SetPageImage (
316 wxBitmap vBitmap
= (wxBitmap
)m_imageList
->GetBitmap(nImage
);
318 return (bool)::WinSendMsg( GetHWND()
320 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
321 ,(MPARAM
)vBitmap
.GetHBITMAP()
323 } // end of wxNotebook::SetPageImage
325 void wxNotebook::SetImageList (
326 wxImageList
* pImageList
330 // Does not really do anything yet, but at least we need to
331 // update the base class.
333 wxNotebookBase::SetImageList(pImageList
);
334 } // end of wxNotebook::SetImageList
336 // ----------------------------------------------------------------------------
337 // wxNotebook size settings
338 // ----------------------------------------------------------------------------
339 void wxNotebook::SetPageSize (
344 } // end of wxNotebook::SetPageSize
346 void wxNotebook::SetPadding (
347 const wxSize
& WXUNUSED(rPadding
)
351 // No padding in OS/2
353 } // end of wxNotebook::SetPadding
355 void wxNotebook::SetTabSize (
359 ::WinSendMsg( GetHWND()
361 ,MPFROM2SHORT( (USHORT
)rSize
.x
364 ,(MPARAM
)BKA_MAJORTAB
366 } // end of wxNotebook::SetTabSize
368 // ----------------------------------------------------------------------------
369 // wxNotebook operations
370 // ----------------------------------------------------------------------------
373 // Remove one page from the notebook, without deleting
375 wxNotebookPage
* wxNotebook::DoRemovePage ( size_t nPage
)
377 wxNotebookPage
* pPageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
382 ::WinSendMsg( GetHWND()
384 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
387 if (m_pages
.IsEmpty())
390 // No selection any more, the notebook becamse empty
394 else // notebook still not empty
397 // Change the selected page if it was deleted or became invalid
401 if (m_nSelection
== (int)GetPageCount())
404 // Last page deleted, make the new last page the new selection
406 nSelNew
= m_nSelection
- 1;
408 else if (nPage
<= (size_t)m_nSelection
)
411 // We must show another page, even if it has the same index
413 nSelNew
= m_nSelection
;
415 else // nothing changes for the currently selected page
420 // We still must refresh the current page: this needs to be done
421 // for some unknown reason if the tab control shows the up-down
422 // control (i.e. when there are too many pages) -- otherwise after
423 // deleting a page nothing at all is shown
425 m_pages
[m_nSelection
]->Refresh();
431 // m_nSelection must be always valid so reset it before calling
435 SetSelection(nSelNew
);
439 } // end of wxNotebook::DoRemovePage
444 bool wxNotebook::DeleteAllPages()
446 int nPageCount
= GetPageCount();
449 for (nPage
= 0; nPage
< nPageCount
; nPage
++)
450 delete m_pages
[nPage
];
452 ::WinSendMsg( GetHWND()
460 } // end of wxNotebook::DeleteAllPages
463 // Add a page to the notebook
465 bool wxNotebook::AddPage (
466 wxNotebookPage
* pPage
467 , const wxString
& rStrText
472 return InsertPage( GetPageCount()
478 } // end of wxNotebook::AddPage
481 // Same as AddPage() but does it at given position
483 bool wxNotebook::InsertPage ( size_t nPage
,
484 wxNotebookPage
* pPage
,
485 const wxString
& rsStrText
,
491 wxASSERT( pPage
!= NULL
);
492 wxCHECK( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false );
495 // Under OS/2 we can only insert FIRST, LAST, NEXT or PREV. Requires
496 // two different calls to the API. Page 1 uses the BKA_FIRST. Subsequent
497 // pages use the previous page ID coupled with a BKA_NEXT call. Unlike
498 // Windows, OS/2 uses an internal Page ID to ID the pages.
500 // OS/2 also has a nice auto-size feature that automatically sizes the
501 // the attached window so we don't have to worry about the size of the
502 // window on the page.
506 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
509 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_FIRST
)
516 vError
= ::WinGetLastError(vHabmain
);
517 sError
= wxPMErrorToStr(vError
);
520 m_alPageId
.Insert((long)ulApiPage
, nPage
);
524 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
526 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
- 1])
527 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_NEXT
)
534 vError
= ::WinGetLastError(vHabmain
);
535 sError
= wxPMErrorToStr(vError
);
538 m_alPageId
.Insert((long)ulApiPage
, nPage
);
542 // Associate a window handle with the page
546 if (!::WinSendMsg( GetHWND()
547 ,BKM_SETPAGEWINDOWHWND
548 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
549 ,MPFROMHWND(pPage
->GetHWND())
554 // If the inserted page is before the selected one, we must update the
555 // index of the selected page
557 if (nPage
<= (size_t)m_nSelection
)
560 // One extra page added
568 // Save the pointer to the page
570 m_pages
.Insert( pPage
576 // Now set TAB dimenstions
579 wxWindowDC
vDC(this);
583 vDC
.GetTextExtent(rsStrText
, &nTextX
, &nTextY
);
585 nTextX
= (wxCoord
)(nTextX
* 1.3);
586 if (nTextX
> m_nTabSize
)
589 ::WinSendMsg( GetHWND()
591 ,MPFROM2SHORT((USHORT
)m_nTabSize
, (USHORT
)nTextY
)
592 ,(MPARAM
)BKA_MAJORTAB
596 // Now set any TAB text
598 if (!rsStrText
.empty())
600 if (!SetPageText( nPage
607 // Now set any TAB bitmap image
611 if (!SetPageImage( nPage
620 // Don't show pages by default (we'll need to adjust their size first)
622 HWND hWnd
= GetWinHwnd(pPage
);
624 WinSetWindowULong( hWnd
626 ,WinQueryWindowULong( hWnd
632 // This updates internal flag too - otherwise it will get out of sync
638 // Some page should be selected: either this one or the first one if there is
639 // still no selection
645 else if ( m_nSelection
== -1 )
649 SetSelection(nSelNew
);
651 InvalidateBestSize();
654 } // end of wxNotebook::InsertPage
656 // ----------------------------------------------------------------------------
657 // wxNotebook callbacks
658 // ----------------------------------------------------------------------------
659 void wxNotebook::OnSize(
664 } // end of wxNotebook::OnSize
666 void wxNotebook::OnSelChange (
667 wxNotebookEvent
& rEvent
671 // Is it our tab control?
673 if (rEvent
.GetEventObject() == this)
675 int nPageCount
= GetPageCount();
677 ULONG ulOS2Sel
= (ULONG
)rEvent
.GetOldSelection();
680 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
682 if (ulOS2Sel
== (ULONG
)m_alPageId
[nSel
])
692 m_pages
[nSel
]->Show(false);
694 ulOS2Sel
= (ULONG
)rEvent
.GetSelection();
698 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
700 if (ulOS2Sel
== (ULONG
)m_alPageId
[nSel
])
710 wxNotebookPage
* pPage
= m_pages
[nSel
];
717 // We want to give others a chance to process this message as well
720 } // end of wxNotebook::OnSelChange
722 void wxNotebook::OnSetFocus (
727 // This function is only called when the focus is explicitly set (i.e. from
728 // the program) to the notebook - in this case we don't need the
729 // complicated OnNavigationKey() logic because the programmer knows better
732 // set focus to the currently selected page if any
734 if (m_nSelection
!= -1)
735 m_pages
[m_nSelection
]->SetFocus();
737 } // end of wxNotebook::OnSetFocus
739 void wxNotebook::OnNavigationKey (
740 wxNavigationKeyEvent
& rEvent
743 if (rEvent
.IsWindowChange())
748 AdvanceSelection(rEvent
.GetDirection());
753 // We get this event in 2 cases
755 // a) one of our pages might have generated it because the user TABbed
756 // out from it in which case we should propagate the event upwards and
757 // our parent will take care of setting the focus to prev/next sibling
761 // b) the parent panel wants to give the focus to us so that we
762 // forward it to our selected page. We can't deal with this in
763 // OnSetFocus() because we don't know which direction the focus came
764 // from in this case and so can't choose between setting the focus to
765 // first or last panel child
767 wxWindow
* pParent
= GetParent();
769 if (rEvent
.GetEventObject() == pParent
)
772 // No, it doesn't come from child, case (b): forward to a page
774 if (m_nSelection
!= -1)
777 // So that the page knows that the event comes from it's parent
778 // and is being propagated downwards
780 rEvent
.SetEventObject(this);
782 wxWindow
* pPage
= m_pages
[m_nSelection
];
784 if (!pPage
->GetEventHandler()->ProcessEvent(rEvent
))
788 //else: page manages focus inside it itself
793 // We have no pages - still have to give focus to _something_
801 // It comes from our child, case (a), pass to the parent
805 rEvent
.SetCurrentFocus(this);
806 pParent
->GetEventHandler()->ProcessEvent(rEvent
);
810 } // end of wxNotebook::OnNavigationKey
812 // ----------------------------------------------------------------------------
813 // wxNotebook base class virtuals
814 // ----------------------------------------------------------------------------
817 // Override these 2 functions to do nothing: everything is done in OnSize
819 void wxNotebook::SetConstraintSizes( bool WXUNUSED(bRecurse
) )
822 // Don't set the sizes of the pages - their correct size is not yet known
824 wxControl::SetConstraintSizes(false);
825 } // end of wxNotebook::SetConstraintSizes
827 bool wxNotebook::DoPhase ( int WXUNUSED(nPhase
) )
830 } // end of wxNotebook::DoPhase
832 // ----------------------------------------------------------------------------
833 // wxNotebook Windows message handlers
834 // ----------------------------------------------------------------------------
835 bool wxNotebook::OS2OnScroll ( int nOrientation
,
841 // Don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
846 return wxNotebookBase::OS2OnScroll( nOrientation
851 } // end of wxNotebook::OS2OnScroll
853 #endif // wxUSE_NOTEBOOK