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( 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
& 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
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(
212 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, 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(
245 , const wxString
& rsStrText
248 wxCHECK_MSG( IS_VALID_PAGE(nPage
), FALSE
, wxT("notebook page out of range") );
249 return (bool)::WinSendMsg( m_hWnd
251 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
252 ,MPFROMP((PSZ
)rsStrText
.c_str())
254 } // end of wxNotebook::SetPageText
256 wxString
wxNotebook::GetPageText (
265 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxT(""), wxT("notebook page out of range") );
267 memset(&vBookText
, '\0', sizeof(BOOKTEXT
));
268 vBookText
.textLen
= 0; // This will get the length
269 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
271 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
274 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
276 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
)
278 wxLogError(wxT("Invalid Page Id for page text querry."));
280 return wxEmptyString
;
282 vBookText
.textLen
= ulRc
+ 1; // To get the null terminator
283 vBookText
.pString
= (char*)zBuf
;
286 // Now get the actual text
288 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
290 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
293 if (ulRc
== (ULONG
)BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
295 return wxEmptyString
;
300 vBookText
.pString
[ulRc
] = '\0';
301 sStr
= (wxChar
*)vBookText
.pString
;
303 } // end of wxNotebook::GetPageText
305 int wxNotebook::GetPageImage (
309 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
312 // For OS/2 just return the page
315 } // end of wxNotebook::GetPageImage
317 bool wxNotebook::SetPageImage (
322 wxBitmap vBitmap
= (wxBitmap
)m_imageList
->GetBitmap(nImage
);
324 return (bool)::WinSendMsg( GetHWND()
326 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
327 ,(MPARAM
)vBitmap
.GetHBITMAP()
329 } // end of wxNotebook::SetPageImage
331 void wxNotebook::SetImageList (
332 wxImageList
* pImageList
336 // Does not really do anything yet, but at least we need to
337 // update the base class.
339 wxNotebookBase::SetImageList(pImageList
);
340 } // end of wxNotebook::SetImageList
342 // ----------------------------------------------------------------------------
343 // wxNotebook size settings
344 // ----------------------------------------------------------------------------
345 void wxNotebook::SetPageSize (
350 } // end of wxNotebook::SetPageSize
352 void wxNotebook::SetPadding (
353 const wxSize
& WXUNUSED(rPadding
)
357 // No padding in OS/2
359 } // end of wxNotebook::SetPadding
361 void wxNotebook::SetTabSize (
365 ::WinSendMsg( GetHWND()
367 ,MPFROM2SHORT( (USHORT
)rSize
.x
370 ,(MPARAM
)BKA_MAJORTAB
372 } // end of wxNotebook::SetTabSize
374 // ----------------------------------------------------------------------------
375 // wxNotebook operations
376 // ----------------------------------------------------------------------------
379 // Remove one page from the notebook, without deleting
381 wxNotebookPage
* wxNotebook::DoRemovePage (
385 wxNotebookPage
* pPageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
390 ::WinSendMsg( GetHWND()
392 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
395 if (m_pages
.IsEmpty())
398 // No selection any more, the notebook becamse empty
402 else // notebook still not empty
405 // Change the selected page if it was deleted or became invalid
409 if (m_nSelection
== (int)GetPageCount())
412 // Last page deleted, make the new last page the new selection
414 nSelNew
= m_nSelection
- 1;
416 else if (nPage
<= (size_t)m_nSelection
)
419 // We must show another page, even if it has the same index
421 nSelNew
= m_nSelection
;
423 else // nothing changes for the currently selected page
428 // We still must refresh the current page: this needs to be done
429 // for some unknown reason if the tab control shows the up-down
430 // control (i.e. when there are too many pages) -- otherwise after
431 // deleting a page nothing at all is shown
433 m_pages
[m_nSelection
]->Refresh();
439 // m_nSelection must be always valid so reset it before calling
443 SetSelection(nSelNew
);
447 } // end of wxNotebook::DoRemovePage
452 bool wxNotebook::DeleteAllPages()
454 int nPageCount
= GetPageCount();
457 for (nPage
= 0; nPage
< nPageCount
; nPage
++)
458 delete m_pages
[nPage
];
460 ::WinSendMsg( GetHWND()
467 } // end of wxNotebook::DeleteAllPages
470 // Add a page to the notebook
472 bool wxNotebook::AddPage (
473 wxNotebookPage
* pPage
474 , const wxString
& rStrText
479 return InsertPage( GetPageCount()
485 } // end of wxNotebook::AddPage
488 // Same as AddPage() but does it at given position
490 bool wxNotebook::InsertPage (
492 , wxNotebookPage
* pPage
493 , const wxString
& rsStrText
500 wxASSERT( pPage
!= NULL
);
501 wxCHECK( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), FALSE
);
504 // Under OS/2 we can only insert FIRST, LAST, NEXT or PREV. Requires
505 // two different calls to the API. Page 1 uses the BKA_FIRST. Subsequent
506 // pages use the previous page ID coupled with a BKA_NEXT call. Unlike
507 // Windows, OS/2 uses an internal Page ID to ID the pages.
509 // OS/2 also has a nice auto-size feature that automatically sizes the
510 // the attached window so we don't have to worry about the size of the
511 // window on the page.
515 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
518 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_FIRST
)
525 vError
= ::WinGetLastError(vHabmain
);
526 sError
= wxPMErrorToStr(vError
);
529 m_alPageId
.Insert((long)ulApiPage
, nPage
);
533 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
535 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
- 1])
536 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_NEXT
)
543 vError
= ::WinGetLastError(vHabmain
);
544 sError
= wxPMErrorToStr(vError
);
547 m_alPageId
.Insert((long)ulApiPage
, nPage
);
551 // Associate a window handle with the page
555 if (!::WinSendMsg( GetHWND()
556 ,BKM_SETPAGEWINDOWHWND
557 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
558 ,MPFROMHWND(pPage
->GetHWND())
563 // If the inserted page is before the selected one, we must update the
564 // index of the selected page
566 if (nPage
<= (size_t)m_nSelection
)
569 // One extra page added
577 // Save the pointer to the page
579 m_pages
.Insert( pPage
585 // Now set TAB dimenstions
588 wxWindowDC
vDC(this);
592 vDC
.GetTextExtent(rsStrText
, &nTextX
, &nTextY
);
594 nTextX
= (wxCoord
)(nTextX
* 1.3);
595 if (nTextX
> m_nTabSize
)
598 ::WinSendMsg( GetHWND()
600 ,MPFROM2SHORT((USHORT
)m_nTabSize
, (USHORT
)nTextY
)
601 ,(MPARAM
)BKA_MAJORTAB
605 // Now set any TAB text
607 if (!rsStrText
.IsEmpty())
609 if (!SetPageText( nPage
616 // Now set any TAB bitmap image
620 if (!SetPageImage( nPage
629 // Don't show pages by default (we'll need to adjust their size first)
631 HWND hWnd
= GetWinHwnd(pPage
);
633 WinSetWindowULong( hWnd
635 ,WinQueryWindowULong( hWnd
641 // This updates internal flag too - otherwise it will get out of sync
647 // Some page should be selected: either this one or the first one if there is
648 // still no selection
654 else if ( m_nSelection
== -1 )
658 SetSelection(nSelNew
);
660 InvalidateBestSize();
663 } // end of wxNotebook::InsertPage
665 // ----------------------------------------------------------------------------
666 // wxNotebook callbacks
667 // ----------------------------------------------------------------------------
668 void wxNotebook::OnSize(
673 } // end of wxNotebook::OnSize
675 void wxNotebook::OnSelChange (
676 wxNotebookEvent
& rEvent
680 // Is it our tab control?
682 if (rEvent
.GetEventObject() == this)
684 int nPageCount
= GetPageCount();
686 ULONG ulOS2Sel
= (ULONG
)rEvent
.GetOldSelection();
689 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
691 if (ulOS2Sel
== (ULONG
)m_alPageId
[nSel
])
701 m_pages
[nSel
]->Show(FALSE
);
703 ulOS2Sel
= (ULONG
)rEvent
.GetSelection();
707 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
709 if (ulOS2Sel
== (ULONG
)m_alPageId
[nSel
])
719 wxNotebookPage
* pPage
= m_pages
[nSel
];
726 // We want to give others a chance to process this message as well
729 } // end of wxNotebook::OnSelChange
731 void wxNotebook::OnSetFocus (
736 // This function is only called when the focus is explicitly set (i.e. from
737 // the program) to the notebook - in this case we don't need the
738 // complicated OnNavigationKey() logic because the programmer knows better
741 // set focus to the currently selected page if any
743 if (m_nSelection
!= -1)
744 m_pages
[m_nSelection
]->SetFocus();
746 } // end of wxNotebook::OnSetFocus
748 void wxNotebook::OnNavigationKey (
749 wxNavigationKeyEvent
& rEvent
752 if (rEvent
.IsWindowChange())
757 AdvanceSelection(rEvent
.GetDirection());
762 // We get this event in 2 cases
764 // a) one of our pages might have generated it because the user TABbed
765 // out from it in which case we should propagate the event upwards and
766 // our parent will take care of setting the focus to prev/next sibling
770 // b) the parent panel wants to give the focus to us so that we
771 // forward it to our selected page. We can't deal with this in
772 // OnSetFocus() because we don't know which direction the focus came
773 // from in this case and so can't choose between setting the focus to
774 // first or last panel child
776 wxWindow
* pParent
= GetParent();
778 if (rEvent
.GetEventObject() == pParent
)
781 // No, it doesn't come from child, case (b): forward to a page
783 if (m_nSelection
!= -1)
786 // So that the page knows that the event comes from it's parent
787 // and is being propagated downwards
789 rEvent
.SetEventObject(this);
791 wxWindow
* pPage
= m_pages
[m_nSelection
];
793 if (!pPage
->GetEventHandler()->ProcessEvent(rEvent
))
797 //else: page manages focus inside it itself
802 // We have no pages - still have to give focus to _something_
810 // It comes from our child, case (a), pass to the parent
814 rEvent
.SetCurrentFocus(this);
815 pParent
->GetEventHandler()->ProcessEvent(rEvent
);
819 } // end of wxNotebook::OnNavigationKey
821 // ----------------------------------------------------------------------------
822 // wxNotebook base class virtuals
823 // ----------------------------------------------------------------------------
826 // Override these 2 functions to do nothing: everything is done in OnSize
828 void wxNotebook::SetConstraintSizes(
829 bool WXUNUSED(bRecurse
)
833 // Don't set the sizes of the pages - their correct size is not yet known
835 wxControl::SetConstraintSizes(FALSE
);
836 } // end of wxNotebook::SetConstraintSizes
838 bool wxNotebook::DoPhase (
843 } // end of wxNotebook::DoPhase
845 // ----------------------------------------------------------------------------
846 // wxNotebook Windows message handlers
847 // ----------------------------------------------------------------------------
848 bool wxNotebook::OS2OnScroll (
856 // Don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
861 return wxNotebookBase::OS2OnScroll( nOrientation
866 } // end of wxNotebook::OS2OnScroll
868 #endif // wxUSE_NOTEBOOK