1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/os2/notebook.cpp
3 // Purpose: implementation of wxNotebook
4 // Author: David Webster
7 // Copyright: (c) David Webster
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
16 #include "wx/notebook.h"
21 #include "wx/dcclient.h"
22 #include "wx/string.h"
23 #include "wx/settings.h"
26 #include "wx/control.h"
29 #include "wx/imaglist.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 BEGIN_EVENT_TABLE(wxNotebook
, wxBookCtrlBase
)
56 EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY
, wxNotebook::OnSelChange
)
57 EVT_SIZE(wxNotebook::OnSize
)
58 EVT_SET_FOCUS(wxNotebook::OnSetFocus
)
59 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
62 // ============================================================================
64 // ============================================================================
66 // ----------------------------------------------------------------------------
67 // wxNotebook construction
68 // ----------------------------------------------------------------------------
71 // Common part of all ctors
73 void wxNotebook::Init()
76 } // end of wxNotebook::Init
79 // Default for dynamic class
81 wxNotebook::wxNotebook()
84 } // end of wxNotebook::wxNotebook
87 // The same arguments as for wxControl
89 wxNotebook::wxNotebook(
95 , const wxString
& rsName
106 } // end of wxNotebook::wxNotebook
111 bool wxNotebook::Create( wxWindow
* pParent
,
116 const wxString
& rsName
)
118 if ( (lStyle
& wxBK_ALIGN_MASK
) == wxBK_DEFAULT
)
123 if (!CreateControl( pParent
134 // Notebook, so explicitly specify 0 as last parameter
136 if (!OS2CreateControl( wxT("NOTEBOOK")
140 ,lStyle
| wxTAB_TRAVERSAL
144 SetBackgroundColour(wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)));
146 } // end of wxNotebook::Create
148 WXDWORD
wxNotebook::OS2GetStyle (
150 , WXDWORD
* pdwExstyle
153 WXDWORD dwTabStyle
= wxControl::OS2GetStyle( lStyle
157 dwTabStyle
|= WS_TABSTOP
| BKS_SOLIDBIND
| BKS_ROUNDEDTABS
| BKS_TABTEXTCENTER
| BKS_TABBEDDIALOG
;
159 if (lStyle
& wxBK_BOTTOM
)
160 dwTabStyle
|= BKS_MAJORTABBOTTOM
| BKS_BACKPAGESBL
;
161 else if (lStyle
& wxBK_RIGHT
)
162 dwTabStyle
|= BKS_MAJORTABRIGHT
| BKS_BACKPAGESBR
;
163 else if (lStyle
& wxBK_LEFT
)
164 dwTabStyle
|= BKS_MAJORTABLEFT
| BKS_BACKPAGESTL
;
165 else // default to top
166 dwTabStyle
|= BKS_MAJORTABTOP
| BKS_BACKPAGESTR
;
174 // Note that we never want to have the default WS_EX_CLIENTEDGE style
175 // as it looks too ugly for the notebooks
180 } // end of wxNotebook::OS2GetStyle
182 // ----------------------------------------------------------------------------
183 // wxNotebook accessors
184 // ----------------------------------------------------------------------------
186 size_t wxNotebook::GetPageCount() const
191 wxASSERT((int)m_pages
.Count() == (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT
, (MPARAM
)0, (MPARAM
)BKA_END
));
192 return m_pages
.Count();
193 } // end of wxNotebook::GetPageCount
195 int wxNotebook::GetRowCount() const
197 return (int)::WinSendMsg( GetHWND()
202 } // end of wxNotebook::GetRowCount
204 int wxNotebook::SetSelection( size_t nPage
)
206 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
208 if (nPage
!= (size_t)m_selection
)
210 wxBookCtrlEvent
vEvent( wxEVT_NOTEBOOK_PAGE_CHANGING
214 vEvent
.SetSelection(nPage
);
215 vEvent
.SetOldSelection(m_selection
);
216 vEvent
.SetEventObject(this);
217 if (!HandleWindowEvent(vEvent
) || vEvent
.IsAllowed())
221 // Program allows the page change
223 vEvent
.SetEventType(wxEVT_NOTEBOOK_PAGE_CHANGED
);
224 HandleWindowEvent(vEvent
);
226 ::WinSendMsg( GetHWND()
228 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
235 } // end of wxNotebook::SetSelection
237 int wxNotebook::ChangeSelection( size_t nPage
)
239 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
241 if (nPage
!= (size_t)m_selection
)
243 ::WinSendMsg( GetHWND()
245 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
253 bool wxNotebook::SetPageText( size_t nPage
,
254 const wxString
& rsStrText
)
256 wxCHECK_MSG( IS_VALID_PAGE(nPage
), false, wxT("notebook page out of range") );
257 return (bool)::WinSendMsg( m_hWnd
259 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
260 ,MPFROMP((const char*)rsStrText
.c_str())
262 } // end of wxNotebook::SetPageText
264 wxString
wxNotebook::GetPageText ( size_t nPage
) const
271 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxEmptyString
, wxT("notebook page out of range") );
273 memset(&vBookText
, '\0', sizeof(BOOKTEXT
));
274 vBookText
.textLen
= 0; // This will get the length
275 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
277 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
280 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
282 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
)
284 wxLogError(wxT("Invalid Page Id for page text querry."));
286 return wxEmptyString
;
288 vBookText
.textLen
= ulRc
+ 1; // To get the null terminator
289 vBookText
.pString
= (char*)zBuf
;
292 // Now get the actual text
294 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
296 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
299 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
301 return wxEmptyString
;
306 vBookText
.pString
[ulRc
] = '\0';
307 sStr
= (wxChar
*)vBookText
.pString
;
309 } // end of wxNotebook::GetPageText
311 int wxNotebook::GetPageImage ( size_t nPage
) const
313 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxNOT_FOUND
, wxT("notebook page out of range") );
316 // For OS/2 just return the page
319 } // end of wxNotebook::GetPageImage
321 bool wxNotebook::SetPageImage (
326 wxBitmap vBitmap
= (wxBitmap
)GetImageList()->GetBitmap(nImage
);
328 return (bool)::WinSendMsg( GetHWND()
330 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
331 ,(MPARAM
)wxCopyBmp(vBitmap
.GetHBITMAP(), true)
333 } // end of wxNotebook::SetPageImage
335 void wxNotebook::SetImageList (
336 wxImageList
* pImageList
340 // Does not really do anything yet, but at least we need to
341 // update the base class.
343 wxNotebookBase::SetImageList(pImageList
);
344 } // end of wxNotebook::SetImageList
346 // ----------------------------------------------------------------------------
347 // wxNotebook size settings
348 // ----------------------------------------------------------------------------
349 void wxNotebook::SetPageSize (
354 } // end of wxNotebook::SetPageSize
356 void wxNotebook::SetPadding (
357 const wxSize
& WXUNUSED(rPadding
)
361 // No padding in OS/2
363 } // end of wxNotebook::SetPadding
365 void wxNotebook::SetTabSize (
369 ::WinSendMsg( GetHWND()
371 ,MPFROM2SHORT( (USHORT
)rSize
.x
374 ,(MPARAM
)BKA_MAJORTAB
376 } // end of wxNotebook::SetTabSize
378 // ----------------------------------------------------------------------------
379 // wxNotebook operations
380 // ----------------------------------------------------------------------------
383 // Remove one page from the notebook, without deleting
385 wxNotebookPage
* wxNotebook::DoRemovePage ( size_t nPage
)
387 wxNotebookPage
* pPageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
392 ::WinSendMsg( GetHWND()
394 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
397 if (m_pages
.IsEmpty())
400 // No selection any more, the notebook becamse empty
402 m_selection
= wxNOT_FOUND
;
404 else // notebook still not empty
407 // Change the selected page if it was deleted or became invalid
411 if (m_selection
== (int)GetPageCount())
414 // Last page deleted, make the new last page the new selection
416 nSelNew
= m_selection
- 1;
418 else if (nPage
<= (size_t)m_selection
)
421 // We must show another page, even if it has the same index
423 nSelNew
= m_selection
;
425 else // nothing changes for the currently selected page
427 nSelNew
= wxNOT_FOUND
;
430 // We still must refresh the current page: this needs to be done
431 // for some unknown reason if the tab control shows the up-down
432 // control (i.e. when there are too many pages) -- otherwise after
433 // deleting a page nothing at all is shown
435 m_pages
[m_selection
]->Refresh();
438 if (nSelNew
!= wxNOT_FOUND
)
441 // m_selection must be always valid so reset it before calling
444 m_selection
= wxNOT_FOUND
;
445 SetSelection(nSelNew
);
449 } // end of wxNotebook::DoRemovePage
454 bool wxNotebook::DeleteAllPages()
456 int nPageCount
= GetPageCount();
459 for (nPage
= 0; nPage
< nPageCount
; nPage
++)
460 delete m_pages
[nPage
];
462 ::WinSendMsg( GetHWND()
467 m_selection
= wxNOT_FOUND
;
470 } // end of wxNotebook::DeleteAllPages
473 // Add a page to the notebook
475 bool wxNotebook::AddPage (
476 wxNotebookPage
* pPage
477 , const wxString
& rStrText
482 return InsertPage( GetPageCount()
488 } // end of wxNotebook::AddPage
491 // Same as AddPage() but does it at given position
493 bool wxNotebook::InsertPage ( size_t nPage
,
494 wxNotebookPage
* pPage
,
495 const wxString
& rsStrText
,
501 wxASSERT( pPage
!= NULL
);
502 wxCHECK( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), false );
505 // Under OS/2 we can only insert FIRST, LAST, NEXT or PREV. Requires
506 // two different calls to the API. Page 1 uses the BKA_FIRST. Subsequent
507 // pages use the previous page ID coupled with a BKA_NEXT call. Unlike
508 // Windows, OS/2 uses an internal Page ID to ID the pages.
510 // OS/2 also has a nice auto-size feature that automatically sizes the
511 // the attached window so we don't have to worry about the size of the
512 // window on the page.
516 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
519 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_FIRST
)
526 vError
= ::WinGetLastError(vHabmain
);
527 sError
= wxPMErrorToStr(vError
);
530 m_alPageId
.Insert((long)ulApiPage
, nPage
);
534 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
536 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
- 1])
537 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_NEXT
)
544 vError
= ::WinGetLastError(vHabmain
);
545 sError
= wxPMErrorToStr(vError
);
548 m_alPageId
.Insert((long)ulApiPage
, nPage
);
552 // Associate a window handle with the page
556 if (!::WinSendMsg( GetHWND()
557 ,BKM_SETPAGEWINDOWHWND
558 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
559 ,MPFROMHWND(pPage
->GetHWND())
564 // If the inserted page is before the selected one, we must update the
565 // index of the selected page
567 if (nPage
<= (size_t)m_selection
)
570 // One extra page added
578 // Save the pointer to the page
580 m_pages
.Insert( pPage
586 // Now set TAB dimenstions
589 wxWindowDC
vDC(this);
593 vDC
.GetTextExtent(rsStrText
, &nTextX
, &nTextY
);
595 nTextX
= (wxCoord
)(nTextX
* 1.3);
596 if (nTextX
> m_nTabSize
)
599 ::WinSendMsg( GetHWND()
601 ,MPFROM2SHORT((USHORT
)m_nTabSize
, (USHORT
)nTextY
)
602 ,(MPARAM
)BKA_MAJORTAB
606 // Now set any TAB text
608 if (!rsStrText
.empty())
610 if (!SetPageText( nPage
617 // Now set any TAB bitmap image
621 if (!SetPageImage( nPage
630 // Don't show pages by default (we'll need to adjust their size first)
632 HWND hWnd
= GetWinHwnd(pPage
);
634 WinSetWindowULong( hWnd
636 ,WinQueryWindowULong( hWnd
642 // This updates internal flag too - otherwise it will get out of sync
647 DoSetSelectionAfterInsertion(nPage
, bSelect
);
649 InvalidateBestSize();
652 } // end of wxNotebook::InsertPage
654 // ----------------------------------------------------------------------------
655 // wxNotebook callbacks
656 // ----------------------------------------------------------------------------
657 void wxNotebook::OnSize(
662 } // end of wxNotebook::OnSize
664 void wxNotebook::OnSelChange (
665 wxBookCtrlEvent
& rEvent
669 // Is it our tab control?
671 if (rEvent
.GetEventObject() == this)
673 int nPageCount
= GetPageCount();
675 ULONG ulOS2Sel
= (ULONG
)rEvent
.GetOldSelection();
678 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
680 if (ulOS2Sel
== (ULONG
)m_alPageId
[nSel
])
690 m_pages
[nSel
]->Show(false);
692 ulOS2Sel
= (ULONG
)rEvent
.GetSelection();
696 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
698 if (ulOS2Sel
== (ULONG
)m_alPageId
[nSel
])
708 wxNotebookPage
* pPage
= m_pages
[nSel
];
715 // We want to give others a chance to process this message as well
718 } // end of wxNotebook::OnSelChange
720 void wxNotebook::OnSetFocus (
725 // This function is only called when the focus is explicitly set (i.e. from
726 // the program) to the notebook - in this case we don't need the
727 // complicated OnNavigationKey() logic because the programmer knows better
730 // set focus to the currently selected page if any
732 if (m_selection
!= wxNOT_FOUND
)
733 m_pages
[m_selection
]->SetFocus();
735 } // end of wxNotebook::OnSetFocus
737 void wxNotebook::OnNavigationKey (
738 wxNavigationKeyEvent
& rEvent
741 if (rEvent
.IsWindowChange())
746 AdvanceSelection(rEvent
.GetDirection());
751 // We get this event in 2 cases
753 // a) one of our pages might have generated it because the user TABbed
754 // out from it in which case we should propagate the event upwards and
755 // our parent will take care of setting the focus to prev/next sibling
759 // b) the parent panel wants to give the focus to us so that we
760 // forward it to our selected page. We can't deal with this in
761 // OnSetFocus() because we don't know which direction the focus came
762 // from in this case and so can't choose between setting the focus to
763 // first or last panel child
765 wxWindow
* pParent
= GetParent();
767 if (rEvent
.GetEventObject() == pParent
)
770 // No, it doesn't come from child, case (b): forward to a page
772 if (m_selection
!= wxNOT_FOUND
)
775 // So that the page knows that the event comes from it's parent
776 // and is being propagated downwards
778 rEvent
.SetEventObject(this);
780 wxWindow
* pPage
= m_pages
[m_selection
];
782 if (!pPage
->HandleWindowEvent(rEvent
))
786 //else: page manages focus inside it itself
791 // We have no pages - still have to give focus to _something_
799 // It comes from our child, case (a), pass to the parent
803 rEvent
.SetCurrentFocus(this);
804 pParent
->HandleWindowEvent(rEvent
);
808 } // end of wxNotebook::OnNavigationKey
810 // ----------------------------------------------------------------------------
811 // wxNotebook base class virtuals
812 // ----------------------------------------------------------------------------
815 // Override these 2 functions to do nothing: everything is done in OnSize
817 void wxNotebook::SetConstraintSizes( bool WXUNUSED(bRecurse
) )
820 // Don't set the sizes of the pages - their correct size is not yet known
822 wxControl::SetConstraintSizes(false);
823 } // end of wxNotebook::SetConstraintSizes
825 bool wxNotebook::DoPhase ( int WXUNUSED(nPhase
) )
828 } // end of wxNotebook::DoPhase
830 // ----------------------------------------------------------------------------
831 // wxNotebook Windows message handlers
832 // ----------------------------------------------------------------------------
833 bool wxNotebook::OS2OnScroll ( int nOrientation
,
839 // Don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
844 return wxNotebookBase::OS2OnScroll( nOrientation
849 } // end of wxNotebook::OS2OnScroll
851 #endif // wxUSE_NOTEBOOK