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"
19 #include "wx/string.h"
23 #include "wx/imaglist.h"
25 #include "wx/control.h"
26 #include "wx/notebook.h"
28 #include "wx/os2/private.h"
30 // ----------------------------------------------------------------------------
32 // ----------------------------------------------------------------------------
34 // check that the page index is valid
35 #define IS_VALID_PAGE(nPage) (((nPage) >= 0) && ((nPage) < GetPageCount()))
38 #define m_hWnd (HWND)GetHWND()
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
)
49 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
)
51 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
)
52 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange
)
53 EVT_SIZE(wxNotebook::OnSize
)
54 EVT_SET_FOCUS(wxNotebook::OnSetFocus
)
55 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
58 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
)
59 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxNotifyEvent
)
61 // ============================================================================
63 // ============================================================================
65 // ----------------------------------------------------------------------------
66 // wxNotebook construction
67 // ----------------------------------------------------------------------------
70 // Common part of all ctors
72 void wxNotebook::Init()
77 } // end of wxNotebook::Init
80 // Default for dynamic class
82 wxNotebook::wxNotebook()
85 } // end of wxNotebook::wxNotebook
88 // The same arguments as for wxControl
90 wxNotebook::wxNotebook(
96 , const wxString
& rsName
107 } // end of wxNotebook::wxNotebook
112 bool wxNotebook::Create(
115 , const wxPoint
& rPos
116 , const wxSize
& rSize
118 , const wxString
& rsName
124 if (!CreateControl( pParent
135 // Notebook, so explicitly specify 0 as last parameter
137 if (!OS2CreateControl( "NOTEBOOK"
141 ,lStyle
| wxTAB_TRAVERSAL
145 SetBackgroundColour(wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)));
147 } // end of wxNotebook::Create
149 WXDWORD
wxNotebook::OS2GetStyle (
151 , WXDWORD
* pdwExstyle
154 WXDWORD dwTabStyle
= wxControl::OS2GetStyle( lStyle
158 dwTabStyle
|= WS_TABSTOP
| BKS_SOLIDBIND
| BKS_ROUNDEDTABS
| BKS_TABTEXTCENTER
;
160 if (lStyle
& wxNB_BOTTOM
)
161 dwTabStyle
|= BKS_MAJORTABBOTTOM
| BKS_BACKPAGESBL
;
162 else if (lStyle
& wxNB_RIGHT
)
163 dwTabStyle
|= BKS_MAJORTABRIGHT
| BKS_BACKPAGESBR
;
164 else if (lStyle
& wxNB_LEFT
)
165 dwTabStyle
|= BKS_MAJORTABLEFT
| BKS_BACKPAGESTL
;
166 else // default to top
167 dwTabStyle
|= BKS_MAJORTABTOP
| BKS_BACKPAGESTR
;
175 // Note that we never want to have the default WS_EX_CLIENTEDGE style
176 // as it looks too ugly for the notebooks
181 } // end of wxNotebook::OS2GetStyle
183 // ----------------------------------------------------------------------------
184 // wxNotebook accessors
185 // ----------------------------------------------------------------------------
187 int wxNotebook::GetPageCount() const
189 int nPageInternal
= m_pages
.Count();
190 int nPageAPI
= (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT
, (MPARAM
)0, (MPARAM
)BKA_END
);
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") );
213 int nOldPage
= GetSelection();
215 ChangePage( m_nSelection
219 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
221 ::WinSendMsg( GetHWND()
223 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
226 m_nSelection
= nPage
;
228 } // end of wxNotebook::SetSelection
230 bool wxNotebook::SetPageText(
232 , const wxString
& rsStrText
235 wxCHECK_MSG( IS_VALID_PAGE(nPage
), FALSE
, wxT("notebook page out of range") );
238 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
240 return (bool)::WinSendMsg( m_hWnd
242 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
243 ,MPFROMP((PSZ
)rsStrText
.c_str())
245 } // end of wxNotebook::SetPageText
247 wxString
wxNotebook::GetPageText (
256 wxCHECK_MSG( IS_VALID_PAGE(nPage
), wxT(""), wxT("notebook page out of range") );
259 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
261 memset(&vBookText
, '\0', sizeof(BOOKTEXT
));
262 vBookText
.textLen
= 0; // This will get the length
263 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
265 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
268 if (ulRc
== BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
270 if (ulRc
== BOOKERR_INVALID_PARAMETERS
)
272 wxLogError(wxT("Invalid Page Id for page text querry."));
274 return wxEmptyString
;
276 vBookText
.textLen
= ulRc
+ 1; // To get the null terminator
277 vBookText
.pString
= zBuf
;
280 // Now get the actual text
282 ulRc
= LONGFROMMR(::WinSendMsg( m_hWnd
284 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
287 if (ulRc
== BOOKERR_INVALID_PARAMETERS
|| ulRc
== 0L)
289 return wxEmptyString
;
294 vBookText
.pString
[ulRc
] = '\0';
295 sStr
= vBookText
.pString
;
297 } // end of wxNotebook::GetPageText
299 int wxNotebook::GetPageImage (
303 wxCHECK_MSG( IS_VALID_PAGE(nPage
), -1, 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
* pBitmap
= (wxBitmap
*)m_imageList
->GetBitmap(nImage
);
319 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
321 return (bool)::WinSendMsg( GetHWND()
323 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
324 ,(MPARAM
)pBitmap
->GetHBITMAP()
326 } // end of wxNotebook::SetPageImage
328 void wxNotebook::SetImageList (
329 wxImageList
* WXUNUSED(pImageList
)
333 // Does nothing under OS/2
335 } // end of wxNotebook::SetImageList
337 // ----------------------------------------------------------------------------
338 // wxNotebook size settings
339 // ----------------------------------------------------------------------------
340 void wxNotebook::SetPageSize (
347 // Transform the page size into the notebook size
349 vRect
.xLeft
= vRect
.yTop
= 0;
350 vRect
.xRight
= rSize
.x
;
351 vRect
.yBottom
= rSize
.y
;
357 SetSize( vRect
.xRight
- vRect
.xLeft
358 ,vRect
.yBottom
- vRect
.yTop
360 } // end of wxNotebook::SetPageSize
362 void wxNotebook::SetPadding (
363 const wxSize
& WXUNUSED(rPadding
)
367 // No padding in OS/2
369 } // end of wxNotebook::SetPadding
371 void wxNotebook::SetTabSize (
375 ::WinSendMsg( GetHWND()
377 ,MPFROM2SHORT( (USHORT
)rSize
.x
380 ,(MPARAM
)BKA_MAJORTAB
382 } // end of wxNotebook::SetTabSize
384 // ----------------------------------------------------------------------------
385 // wxNotebook operations
386 // ----------------------------------------------------------------------------
389 // Remove one page from the notebook, without deleting
391 wxNotebookPage
* wxNotebook::DoRemovePage (
395 wxNotebookPage
* pPageRemoved
= wxNotebookBase::DoRemovePage(nPage
);
401 ULONG ulPageId
= (ULONG
)m_alPageId
[nPage
];
403 ::WinSendMsg( GetHWND()
405 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
408 if (m_pages
.IsEmpty())
411 // No selection any more, the notebook becamse empty
415 else // notebook still not empty
418 // Change the selected page if it was deleted or became invalid
422 if (m_nSelection
== GetPageCount())
425 // Last page deleted, make the new last page the new selection
427 nSelNew
= m_nSelection
- 1;
429 else if (nPage
<= m_nSelection
)
432 // We must show another page, even if it has the same index
434 nSelNew
= m_nSelection
;
436 else // nothing changes for the currently selected page
441 // We still must refresh the current page: this needs to be done
442 // for some unknown reason if the tab control shows the up-down
443 // control (i.e. when there are too many pages) -- otherwise after
444 // deleting a page nothing at all is shown
446 m_pages
[m_nSelection
]->Refresh();
452 // m_nSelection must be always valid so reset it before calling
456 SetSelection(nSelNew
);
460 } // end of wxNotebook::DoRemovePage
465 bool wxNotebook::DeleteAllPages()
467 int nPageCount
= GetPageCount();
470 for (nPage
= 0; nPage
< nPageCount
; nPage
++)
471 delete m_pages
[nPage
];
473 ::WinSendMsg( GetHWND()
480 } // end of wxNotebook::DeleteAllPages
483 // Add a page to the notebook
485 bool wxNotebook::AddPage (
486 wxNotebookPage
* pPage
487 , const wxString
& rStrText
492 return InsertPage( GetPageCount()
498 } // end of wxNotebook::AddPage
501 // Same as AddPage() but does it at given position
503 bool wxNotebook::InsertPage (
505 , wxNotebookPage
* pPage
506 , const wxString
& rsStrText
513 wxASSERT( pPage
!= NULL
);
514 wxCHECK( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), FALSE
);
517 // Under OS/2 we can only insert FIRST, LAST, NEXT or PREV. Requires
518 // two different calls to the API. Page 1 uses the BKA_FIRST. Subsequent
519 // pages use the previous page ID coupled with a BKA_NEXT call. Unlike
520 // Windows, OS/2 uses an internal Page ID to ID the pages.
522 // OS/2 also has a nice auto-size feature that automatically sizes the
523 // the attached window so we don't have to worry about the size of the
524 // window on the page.
528 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
531 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_FIRST
)
538 vError
= ::WinGetLastError(vHabmain
);
539 sError
= wxPMErrorToStr(vError
);
542 m_alPageId
.Insert((long)ulApiPage
, nPage
);
546 ulApiPage
= LONGFROMMR(::WinSendMsg( GetHWND()
548 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
- 1])
549 ,MPFROM2SHORT(BKA_AUTOPAGESIZE
| BKA_MAJOR
, BKA_NEXT
)
556 vError
= ::WinGetLastError(vHabmain
);
557 sError
= wxPMErrorToStr(vError
);
560 m_alPageId
.Insert((long)ulApiPage
, nPage
);
564 // Associate a window handle with the page
568 if (!::WinSendMsg( GetHWND()
569 ,BKM_SETPAGEWINDOWHWND
570 ,MPFROMLONG((ULONG
)m_alPageId
[nPage
])
571 ,MPFROMHWND(pPage
->GetHWND())
576 // If the inserted page is before the selected one, we must update the
577 // index of the selected page
579 if (nPage
<= m_nSelection
)
582 // One extra page added
590 // Save the pointer to the page
592 m_pages
.Insert( pPage
598 // Now set TAB dimenstions
601 wxWindowDC
vDC(this);
605 vDC
.GetTextExtent(rsStrText
, &nTextX
, &nTextY
);
608 if (nTextX
> m_nTabSize
)
611 ::WinSendMsg( GetHWND()
613 ,MPFROM2SHORT((USHORT
)m_nTabSize
, (USHORT
)nTextY
)
614 ,(MPARAM
)BKA_MAJORTAB
618 // Now set any TAB text
620 if (!rsStrText
.IsEmpty())
622 if (!SetPageText( nPage
629 // Now set any TAB bitmap image
633 if (!SetPageImage( nPage
642 // Don't show pages by default (we'll need to adjust their size first)
644 HWND hWnd
= GetWinHwnd(pPage
);
646 WinSetWindowULong( hWnd
648 ,WinQueryWindowULong( hWnd
654 // This updates internal flag too - otherwise it will get out of sync
660 // Some page should be selected: either this one or the first one if there is
661 // still no selection
667 else if ( m_nSelection
== -1 )
671 SetSelection(nSelNew
);
673 } // end of wxNotebook::InsertPage
675 // ----------------------------------------------------------------------------
676 // wxNotebook callbacks
677 // ----------------------------------------------------------------------------
678 void wxNotebook::OnSize(
682 if (m_nSelection
< m_pages
.Count() && m_nSelection
>= 0)
683 m_pages
[m_nSelection
]->Refresh();
685 } // end of wxNotebook::OnSize
687 void wxNotebook::OnSelChange (
688 wxNotebookEvent
& rEvent
692 // Is it our tab control?
694 if (rEvent
.GetEventObject() == this)
696 int nSel
= rEvent
.GetOldSelection();
700 m_pages
[nSel
]->Show(FALSE
);
701 m_pages
[nSel
]->SetActivePage(FALSE
);
703 nSel
= rEvent
.GetSelection();
706 wxNotebookPage
* pPage
= m_pages
[nSel
];
710 m_pages
[nSel
]->SetActivePage(TRUE
);
716 // We want to give others a chance to process this message as well
719 } // end of wxNotebook::OnSelChange
721 void wxNotebook::OnSetFocus (
726 // This function is only called when the focus is explicitly set (i.e. from
727 // the program) to the notebook - in this case we don't need the
728 // complicated OnNavigationKey() logic because the programmer knows better
731 // set focus to the currently selected page if any
733 if (m_nSelection
!= -1)
734 m_pages
[m_nSelection
]->SetFocus();
736 } // end of wxNotebook::OnSetFocus
738 void wxNotebook::OnNavigationKey (
739 wxNavigationKeyEvent
& rEvent
742 if (rEvent
.IsWindowChange())
747 AdvanceSelection(rEvent
.GetDirection());
752 // We get this event in 2 cases
754 // a) one of our pages might have generated it because the user TABbed
755 // out from it in which case we should propagate the event upwards and
756 // our parent will take care of setting the focus to prev/next sibling
760 // b) the parent panel wants to give the focus to us so that we
761 // forward it to our selected page. We can't deal with this in
762 // OnSetFocus() because we don't know which direction the focus came
763 // from in this case and so can't choose between setting the focus to
764 // first or last panel child
766 wxWindow
* pParent
= GetParent();
768 if (rEvent
.GetEventObject() == pParent
)
771 // No, it doesn't come from child, case (b): forward to a page
773 if (m_nSelection
!= -1)
776 // So that the page knows that the event comes from it's parent
777 // and is being propagated downwards
779 rEvent
.SetEventObject(this);
781 wxWindow
* pPage
= m_pages
[m_nSelection
];
783 if (!pPage
->GetEventHandler()->ProcessEvent(rEvent
))
787 //else: page manages focus inside it itself
792 // We have no pages - still have to give focus to _something_
800 // It comes from our child, case (a), pass to the parent
804 rEvent
.SetCurrentFocus(this);
805 pParent
->GetEventHandler()->ProcessEvent(rEvent
);
809 } // end of wxNotebook::OnNavigationKey
811 // ----------------------------------------------------------------------------
812 // wxNotebook base class virtuals
813 // ----------------------------------------------------------------------------
816 // Override these 2 functions to do nothing: everything is done in OnSize
818 void wxNotebook::SetConstraintSizes(
819 bool WXUNUSED(bRecurse
)
823 // Don't set the sizes of the pages - their correct size is not yet known
825 wxControl::SetConstraintSizes(FALSE
);
826 } // end of wxNotebook::SetConstraintSizes
828 bool wxNotebook::DoPhase (
833 } // end of wxNotebook::DoPhase
835 // ----------------------------------------------------------------------------
836 // wxNotebook Windows message handlers
837 // ----------------------------------------------------------------------------
838 bool wxNotebook::OS2OnScroll (
846 // Don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
851 return wxNotebookBase::OS2OnScroll( nOrientation
856 } // end of wxNotebook::OS2OnScroll
858 // ----------------------------------------------------------------------------
859 // wxNotebook helper functions
860 // ----------------------------------------------------------------------------
863 // Generate the page changing and changed events, hide the currently active
864 // panel and show the new one
866 void wxNotebook::ChangePage (
871 static bool sbInsideChangePage
= FALSE
;
874 // When we call ProcessEvent(), our own OnSelChange() is called which calls
875 // this function - break the infinite loop
877 if (sbInsideChangePage
)
881 // It's not an error (the message may be generated by the tab control itself)
882 // and it may happen - just do nothing
887 sbInsideChangePage
= TRUE
;
889 wxNotebookEvent
rEvent( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
893 rEvent
.SetSelection(nSel
);
894 rEvent
.SetOldSelection(nOldSel
);
895 rEvent
.SetEventObject(this);
896 if (GetEventHandler()->ProcessEvent(rEvent
) && !rEvent
.IsAllowed())
899 // Program doesn't allow the page change
901 sbInsideChangePage
= FALSE
;
904 rEvent
.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
);
905 GetEventHandler()->ProcessEvent(rEvent
);
906 sbInsideChangePage
= FALSE
;
907 } // end of wxNotebook::ChangePage
909 #endif // wxUSE_NOTEBOOK