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/string.h"
21 #include "wx/settings.h"
25 #include "wx/imaglist.h"
27 #include "wx/control.h"
28 #include "wx/notebook.h"
30 #include "wx/os2/private.h"
32 // ----------------------------------------------------------------------------
34 // ----------------------------------------------------------------------------
36 // check that the page index is valid
37 #define IS_VALID_PAGE(nPage) (((nPage) >= 0) && ((nPage) < GetPageCount()))
40 #define m_hWnd (HWND)GetHWND()
42 // ----------------------------------------------------------------------------
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
)
51 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
)
53 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
)
54 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange
)
55 EVT_SIZE(wxNotebook::OnSize
)
56 EVT_SET_FOCUS(wxNotebook::OnSetFocus
)
57 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
60 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
)
61 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxNotifyEvent
)
63 // ============================================================================
65 // ============================================================================
67 // ----------------------------------------------------------------------------
68 // wxNotebook construction
69 // ----------------------------------------------------------------------------
72 // Common part of all ctors
74 void wxNotebook::Init()
79 } // end of wxNotebook::Init
82 // Default for dynamic class
84 wxNotebook::wxNotebook()
87 } // end of wxNotebook::wxNotebook
90 // The same arguments as for wxControl
92 wxNotebook::wxNotebook(
98 , const wxString
& rsName
109 } // end of wxNotebook::wxNotebook
114 bool wxNotebook::Create(
117 , const wxPoint
& rPos
118 , const wxSize
& rSize
120 , const wxString
& rsName
126 if (!CreateControl( pParent
137 // Notebook, so explicitly specify 0 as last parameter
139 if (!OS2CreateControl( "NOTEBOOK"
143 ,lStyle
| wxTAB_TRAVERSAL
147 SetBackgroundColour(wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)));
149 } // end of wxNotebook::Create
151 WXDWORD
wxNotebook::OS2GetStyle (
153 , WXDWORD
* pdwExstyle
156 WXDWORD dwTabStyle
= wxControl::OS2GetStyle( lStyle
160 dwTabStyle
|= WS_TABSTOP
| BKS_SOLIDBIND
| BKS_ROUNDEDTABS
| BKS_TABTEXTCENTER
;
162 if (lStyle
& wxNB_BOTTOM
)
163 dwTabStyle
|= BKS_MAJORTABBOTTOM
| BKS_BACKPAGESBL
;
164 else if (lStyle
& wxNB_RIGHT
)
165 dwTabStyle
|= BKS_MAJORTABRIGHT
| BKS_BACKPAGESBR
;
166 else if (lStyle
& wxNB_LEFT
)
167 dwTabStyle
|= BKS_MAJORTABLEFT
| BKS_BACKPAGESTL
;
168 else // default to top
169 dwTabStyle
|= BKS_MAJORTABTOP
| BKS_BACKPAGESTR
;
177 // Note that we never want to have the default WS_EX_CLIENTEDGE style
178 // as it looks too ugly for the notebooks
183 } // end of wxNotebook::OS2GetStyle
185 // ----------------------------------------------------------------------------
186 // wxNotebook accessors
187 // ----------------------------------------------------------------------------
189 int wxNotebook::GetPageCount() const
191 int nPageInternal
= m_pages
.Count();
192 int nPageAPI
= (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT
, (MPARAM
)0, (MPARAM
)BKA_END
);
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(
214 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
216 if (nPage
!= m_nSelection
)
218 wxNotebookEvent
vEvent( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
222 vEvent
.SetSelection(nPage
);
223 vEvent
.SetOldSelection(m_nSelection
);
224 vEvent
.SetEventObject(this);
225 if (!GetEventHandler()->ProcessEvent(vEvent
) || vEvent
.IsAllowed())
229 // Program allows the page change
231 vEvent
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
232 GetEventHandler()->ProcessEvent(vEvent
);
234 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
236 ::WinSendMsg( GetHWND()
238 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
243 m_nSelection
= nPage
;
245 } // end of wxNotebook::SetSelection
247 bool wxNotebook::SetPageText(
249 , const wxString
& rsStrText
252 wxCHECK_MSG( IS_VALID_PAGE(nPage
), FALSE
, wxT("notebook page out of range") );
255 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
257 return (bool)::WinSendMsg( m_hWnd
259 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
260 ,MPFROMP((PSZ
)rsStrText
.c_str())
262 } // end of wxNotebook::SetPageText
264 wxString
wxNotebook::GetPageText (
273 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxT(""), wxT("notebook page out of range") );
276 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
278 memset(&vBookText
, '\0', sizeof(BOOKTEXT
));
279 vBookText
.textLen
= 0; // This will get the length
280 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
282 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
285 if (ulRc
== BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
287 if (ulRc
== BOOKERR_INVALID_PARAMETERS
)
289 wxLogError(wxT("Invalid Page Id for page text querry."));
291 return wxEmptyString
;
293 vBookText
.textLen
= ulRc
+ 1; // To get the null terminator
294 vBookText
.pString
= zBuf
;
297 // Now get the actual text
299 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
301 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
304 if (ulRc
== BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
306 return wxEmptyString
;
311 vBookText
.pString
[ulRc
] = '\0';
312 sStr
= vBookText
.pString
;
314 } // end of wxNotebook::GetPageText
316 int wxNotebook::GetPageImage (
320 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, wxT("notebook page out of range") );
323 // For OS/2 just return the page
326 } // end of wxNotebook::GetPageImage
328 bool wxNotebook::SetPageImage (
333 wxBitmap
* pBitmap
= (wxBitmap
*)m_imageList
->GetBitmap(nImage
);
336 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
338 return (bool)::WinSendMsg( GetHWND()
340 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
341 ,(MPARAM
)pBitmap
->GetHBITMAP()
343 } // end of wxNotebook::SetPageImage
345 void wxNotebook::SetImageList (
346 wxImageList
* WXUNUSED(pImageList
)
350 // Does nothing under OS/2
352 } // end of wxNotebook::SetImageList
354 // ----------------------------------------------------------------------------
355 // wxNotebook size settings
356 // ----------------------------------------------------------------------------
357 void wxNotebook::SetPageSize (
364 // Transform the page size into the notebook size
366 vRect
.xLeft
= vRect
.yTop
= 0;
367 vRect
.xRight
= rSize
.x
;
368 vRect
.yBottom
= rSize
.y
;
374 SetSize( vRect
.xRight
- vRect
.xLeft
375 ,vRect
.yBottom
- vRect
.yTop
377 } // end of wxNotebook::SetPageSize
379 void wxNotebook::SetPadding (
380 const wxSize
& WXUNUSED(rPadding
)
384 // No padding in OS/2
386 } // end of wxNotebook::SetPadding
388 void wxNotebook::SetTabSize (
392 ::WinSendMsg( GetHWND()
394 ,MPFROM2SHORT( (USHORT
)rSize
.x
397 ,(MPARAM
)BKA_MAJORTAB
399 } // end of wxNotebook::SetTabSize
401 // ----------------------------------------------------------------------------
402 // wxNotebook operations
403 // ----------------------------------------------------------------------------
406 // Remove one page from the notebook, without deleting
408 wxNotebookPage
* wxNotebook::DoRemovePage (
412 wxNotebookPage
* pPageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
418 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
420 ::WinSendMsg( GetHWND()
422 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
425 if (m_pages
.IsEmpty())
428 // No selection any more, the notebook becamse empty
432 else // notebook still not empty
435 // Change the selected page if it was deleted or became invalid
439 if (m_nSelection
== GetPageCount())
442 // Last page deleted, make the new last page the new selection
444 nSelNew
= m_nSelection
- 1;
446 else if (nPage
<= m_nSelection
)
449 // We must show another page, even if it has the same index
451 nSelNew
= m_nSelection
;
453 else // nothing changes for the currently selected page
458 // We still must refresh the current page: this needs to be done
459 // for some unknown reason if the tab control shows the up-down
460 // control (i.e. when there are too many pages) -- otherwise after
461 // deleting a page nothing at all is shown
463 m_pages
[m_nSelection
]->Refresh();
469 // m_nSelection must be always valid so reset it before calling
473 SetSelection(nSelNew
);
477 } // end of wxNotebook::DoRemovePage
482 bool wxNotebook::DeleteAllPages()
484 int nPageCount
= GetPageCount();
487 for (nPage
= 0; nPage
< nPageCount
; nPage
++)
488 delete m_pages
[nPage
];
490 ::WinSendMsg( GetHWND()
497 } // end of wxNotebook::DeleteAllPages
500 // Add a page to the notebook
502 bool wxNotebook::AddPage (
503 wxNotebookPage
* pPage
504 , const wxString
& rStrText
509 return InsertPage( GetPageCount()
515 } // end of wxNotebook::AddPage
518 // Same as AddPage() but does it at given position
520 bool wxNotebook::InsertPage (
522 , wxNotebookPage
* pPage
523 , const wxString
& rsStrText
530 wxASSERT( pPage
!= NULL
);
531 wxCHECK( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), FALSE
);
534 // Under OS/2 we can only insert FIRST, LAST, NEXT or PREV. Requires
535 // two different calls to the API. Page 1 uses the BKA_FIRST. Subsequent
536 // pages use the previous page ID coupled with a BKA_NEXT call. Unlike
537 // Windows, OS/2 uses an internal Page ID to ID the pages.
539 // OS/2 also has a nice auto-size feature that automatically sizes the
540 // the attached window so we don't have to worry about the size of the
541 // window on the page.
545 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
548 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_FIRST
)
555 vError
= ::WinGetLastError(vHabmain
);
556 sError
= wxPMErrorToStr(vError
);
559 m_alPageId
.Insert((long)ulApiPage
, nPage
);
563 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
565 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
- 1])
566 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_NEXT
)
573 vError
= ::WinGetLastError(vHabmain
);
574 sError
= wxPMErrorToStr(vError
);
577 m_alPageId
.Insert((long)ulApiPage
, nPage
);
581 // Associate a window handle with the page
585 if (!::WinSendMsg( GetHWND()
586 ,BKM_SETPAGEWINDOWHWND
587 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
588 ,MPFROMHWND(pPage
->GetHWND())
593 // If the inserted page is before the selected one, we must update the
594 // index of the selected page
596 if (nPage
<= m_nSelection
)
599 // One extra page added
607 // Save the pointer to the page
609 m_pages
.Insert( pPage
615 // Now set TAB dimenstions
618 wxWindowDC
vDC(this);
622 vDC
.GetTextExtent(rsStrText
, &nTextX
, &nTextY
);
625 if (nTextX
> m_nTabSize
)
628 ::WinSendMsg( GetHWND()
630 ,MPFROM2SHORT((USHORT
)m_nTabSize
, (USHORT
)nTextY
)
631 ,(MPARAM
)BKA_MAJORTAB
635 // Now set any TAB text
637 if (!rsStrText
.IsEmpty())
639 if (!SetPageText( nPage
646 // Now set any TAB bitmap image
650 if (!SetPageImage( nPage
659 // Don't show pages by default (we'll need to adjust their size first)
661 HWND hWnd
= GetWinHwnd(pPage
);
663 WinSetWindowULong( hWnd
665 ,WinQueryWindowULong( hWnd
671 // This updates internal flag too - otherwise it will get out of sync
677 // Some page should be selected: either this one or the first one if there is
678 // still no selection
684 else if ( m_nSelection
== -1 )
688 SetSelection(nSelNew
);
690 } // end of wxNotebook::InsertPage
692 // ----------------------------------------------------------------------------
693 // wxNotebook callbacks
694 // ----------------------------------------------------------------------------
695 void wxNotebook::OnSize(
700 int nCount
= (int)m_pages
.Count();
702 for (nPage
= 0; nPage
< nCount
; nPage
++)
704 if (m_nSelection
== nPage
)
705 m_pages
[nPage
]->Refresh();
707 ::WinSetWindowPos(m_pages
[nPage
]->GetHWND()
714 } // end of wxNotebook::OnSize
716 void wxNotebook::OnSelChange (
717 wxNotebookEvent
& rEvent
721 // Is it our tab control?
723 if (rEvent
.GetEventObject() == this)
725 int nPageCount
= GetPageCount();
727 ULONG ulOS2Sel
= (ULONG
)rEvent
.GetOldSelection();
730 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
732 if (ulOS2Sel
== m_alPageId
[nSel
])
742 m_pages
[nSel
]->Show(FALSE
);
744 ulOS2Sel
= (ULONG
)rEvent
.GetSelection();
748 for (nSel
= 0; nSel
< nPageCount
; nSel
++)
750 if (ulOS2Sel
== m_alPageId
[nSel
])
760 wxNotebookPage
* pPage
= m_pages
[nSel
];
767 // We want to give others a chance to process this message as well
770 } // end of wxNotebook::OnSelChange
772 void wxNotebook::OnSetFocus (
777 // This function is only called when the focus is explicitly set (i.e. from
778 // the program) to the notebook - in this case we don't need the
779 // complicated OnNavigationKey() logic because the programmer knows better
782 // set focus to the currently selected page if any
784 if (m_nSelection
!= -1)
785 m_pages
[m_nSelection
]->SetFocus();
787 } // end of wxNotebook::OnSetFocus
789 void wxNotebook::OnNavigationKey (
790 wxNavigationKeyEvent
& rEvent
793 if (rEvent
.IsWindowChange())
798 AdvanceSelection(rEvent
.GetDirection());
803 // We get this event in 2 cases
805 // a) one of our pages might have generated it because the user TABbed
806 // out from it in which case we should propagate the event upwards and
807 // our parent will take care of setting the focus to prev/next sibling
811 // b) the parent panel wants to give the focus to us so that we
812 // forward it to our selected page. We can't deal with this in
813 // OnSetFocus() because we don't know which direction the focus came
814 // from in this case and so can't choose between setting the focus to
815 // first or last panel child
817 wxWindow
* pParent
= GetParent();
819 if (rEvent
.GetEventObject() == pParent
)
822 // No, it doesn't come from child, case (b): forward to a page
824 if (m_nSelection
!= -1)
827 // So that the page knows that the event comes from it's parent
828 // and is being propagated downwards
830 rEvent
.SetEventObject(this);
832 wxWindow
* pPage
= m_pages
[m_nSelection
];
834 if (!pPage
->GetEventHandler()->ProcessEvent(rEvent
))
838 //else: page manages focus inside it itself
843 // We have no pages - still have to give focus to _something_
851 // It comes from our child, case (a), pass to the parent
855 rEvent
.SetCurrentFocus(this);
856 pParent
->GetEventHandler()->ProcessEvent(rEvent
);
860 } // end of wxNotebook::OnNavigationKey
862 // ----------------------------------------------------------------------------
863 // wxNotebook base class virtuals
864 // ----------------------------------------------------------------------------
867 // Override these 2 functions to do nothing: everything is done in OnSize
869 void wxNotebook::SetConstraintSizes(
870 bool WXUNUSED(bRecurse
)
874 // Don't set the sizes of the pages - their correct size is not yet known
876 wxControl::SetConstraintSizes(FALSE
);
877 } // end of wxNotebook::SetConstraintSizes
879 bool wxNotebook::DoPhase (
884 } // end of wxNotebook::DoPhase
886 // ----------------------------------------------------------------------------
887 // wxNotebook Windows message handlers
888 // ----------------------------------------------------------------------------
889 bool wxNotebook::OS2OnScroll (
897 // Don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
902 return wxNotebookBase::OS2OnScroll( nOrientation
907 } // end of wxNotebook::OS2OnScroll
909 #endif // wxUSE_NOTEBOOK