]> git.saurik.com Git - wxWidgets.git/blobdiff - src/os2/notebook.cpp
Implement left indentation and tab stops support in wxTextCtrl, patch #1518114 -...
[wxWidgets.git] / src / os2 / notebook.cpp
index f7ee49cd5d09c1aec3707f8d9685a54308bb94ba..e0051d4fd4b0b4eccbeac8626e36a78b8fe77c4b 100644 (file)
@@ -1,53 +1,70 @@
 ///////////////////////////////////////////////////////////////////////////////
-// Name:        notebook.cpp
+// Name:        src/os2/notebook.cpp
 // Purpose:     implementation of wxNotebook
-// Author:      AUTHOR
-// Modified by: 
-// Created:     ??/??/98
+// Author:      David Webster
+// Modified by:
+// Created:     10/12/99
 // RCS-ID:      $Id$
-// Copyright:   (c) AUTHOR
+// Copyright:   (c) David Webster
 // Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
-// ============================================================================
-// declarations
-// ============================================================================
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
 
-// ----------------------------------------------------------------------------
-// headers
-// ----------------------------------------------------------------------------
-#ifdef __GNUG__
-#pragma implementation "notebook.h"
-#endif
+#if wxUSE_NOTEBOOK
+
+#include  "wx/notebook.h"
 
-#include  <wx/string.h>
-#include  <wx/log.h>
-#include  <wx/imaglist.h>
-#include  <wx/notebook.h>
+// wxWidgets
+#ifndef WX_PRECOMP
+    #include "wx/app.h"
+    #include "wx/dcclient.h"
+    #include "wx/string.h"
+    #include "wx/settings.h"
+    #include "wx/log.h"
+    #include "wx/event.h"
+    #include  "wx/control.h"
+#endif  // WX_PRECOMP
+
+#include  "wx/imaglist.h"
+
+#include  "wx/os2/private.h"
 
 // ----------------------------------------------------------------------------
 // macros
 // ----------------------------------------------------------------------------
 
 // check that the page index is valid
-#define IS_VALID_PAGE(nPage) (((nPage) >= 0) && ((nPage) < GetPageCount()))
+#define IS_VALID_PAGE(nPage) (                                \
+                               /* size_t is _always_ >= 0 */  \
+                               /* ((nPage) >= 0) && */        \
+                               ((nPage) < GetPageCount())     \
+                             )
+
+// hide the ugly cast
+#define m_hWnd    (HWND)GetHWND()
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 // event table
 // ----------------------------------------------------------------------------
 
-#if !USE_SHARED_LIBRARIES
-BEGIN_EVENT_TABLE(wxNotebook, wxControl)
-    EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING)
 
+BEGIN_EVENT_TABLE(wxNotebook, wxControl)
+    EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, wxNotebook::OnSelChange)
     EVT_SIZE(wxNotebook::OnSize)
     EVT_SET_FOCUS(wxNotebook::OnSetFocus)
     EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
 END_EVENT_TABLE()
 
 IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
-IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxCommandEvent)
-#endif
+IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxNotifyEvent)
 
 // ============================================================================
 // implementation
@@ -57,326 +74,799 @@ IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxCommandEvent)
 // wxNotebook construction
 // ----------------------------------------------------------------------------
 
-// common part of all ctors
+//
+// Common part of all ctors
+//
 void wxNotebook::Init()
 {
-    m_pImageList = NULL;
+    m_imageList  = NULL;
     m_nSelection = -1;
-}
+    m_nTabSize   = 0;
+} // end of wxNotebook::Init
 
-// default for dynamic class
+//
+// Default for dynamic class
+//
 wxNotebook::wxNotebook()
 {
     Init();
-}
-
-// the same arguments as for wxControl
-wxNotebook::wxNotebook(wxWindow *parent,
-                       wxWindowID id,
-                       const wxPoint& pos,
-                       const wxSize& size,
-                       long style,
-                       const wxString& name)
+} // end of wxNotebook::wxNotebook
+
+//
+// The same arguments as for wxControl
+//
+wxNotebook::wxNotebook(
+  wxWindow*                         pParent
+, wxWindowID                        vId
+, const wxPoint&                    rPos
+, const wxSize&                     rSize
+, long                              lStyle
+, const wxString&                   rsName
+)
 {
     Init();
-
-    Create(parent, id, pos, size, style, name);
-}
-
+    Create( pParent
+           ,vId
+           ,rPos
+           ,rSize
+           ,lStyle
+           ,rsName
+          );
+} // end of wxNotebook::wxNotebook
+
+//
 // Create() function
-bool wxNotebook::Create(wxWindow *parent,
-                        wxWindowID id,
-                        const wxPoint& pos,
-                        const wxSize& size,
-                        long style,
-                        const wxString& name)
+//
+bool wxNotebook::Create( wxWindow*       pParent,
+                         wxWindowID      vId,
+                         const wxPoint&  rPos,
+                         const wxSize&   rSize,
+                         long            lStyle,
+                         const wxString& rsName )
 {
-    // base init
-    SetName(name);
-    SetParent(parent);
-
-    m_windowId = id == -1 ? NewControlId() : id;
-
-    // style
-    m_windowStyle = style;
-
-    if ( parent != NULL )
-        parent->AddChild(this);
-
-    // TODO
-
-    return FALSE;
-}
-
-// dtor
-wxNotebook::~wxNotebook()
+    if ( (lStyle & wxBK_ALIGN_MASK) == wxBK_DEFAULT )
+        lStyle |= wxBK_TOP;
+    //
+    // Base init
+    //
+    if (!CreateControl( pParent
+                       ,vId
+                       ,rPos
+                       ,rSize
+                       ,lStyle
+                       ,wxDefaultValidator
+                       ,rsName
+                      ))
+        return false;
+
+    //
+    // Notebook, so explicitly specify 0 as last parameter
+    //
+    if (!OS2CreateControl( wxT("NOTEBOOK")
+                          ,wxEmptyString
+                          ,rPos
+                          ,rSize
+                          ,lStyle | wxTAB_TRAVERSAL
+                         ))
+        return false;
+
+    SetBackgroundColour(wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)));
+    return true;
+} // end of wxNotebook::Create
+
+WXDWORD wxNotebook::OS2GetStyle (
+  long                              lStyle
+, WXDWORD*                          pdwExstyle
+) const
 {
-}
+    WXDWORD                         dwTabStyle = wxControl::OS2GetStyle( lStyle
+                                                                        ,pdwExstyle
+                                                                       );
+
+    dwTabStyle |= WS_TABSTOP | BKS_SOLIDBIND | BKS_ROUNDEDTABS | BKS_TABTEXTCENTER | BKS_TABBEDDIALOG;
+
+    if (lStyle & wxBK_BOTTOM)
+        dwTabStyle |= BKS_MAJORTABBOTTOM | BKS_BACKPAGESBL;
+    else if (lStyle & wxBK_RIGHT)
+        dwTabStyle |= BKS_MAJORTABRIGHT | BKS_BACKPAGESBR;
+    else if (lStyle & wxBK_LEFT)
+        dwTabStyle |= BKS_MAJORTABLEFT | BKS_BACKPAGESTL;
+    else // default to top
+        dwTabStyle |= BKS_MAJORTABTOP | BKS_BACKPAGESTR;
+
+    //
+    // Ex style
+    //
+    if (pdwExstyle )
+    {
+        //
+        // Note that we never want to have the default WS_EX_CLIENTEDGE style
+        // as it looks too ugly for the notebooks
+        //
+        *pdwExstyle = 0;
+    }
+    return dwTabStyle;
+} // end of wxNotebook::OS2GetStyle
 
 // ----------------------------------------------------------------------------
 // wxNotebook accessors
 // ----------------------------------------------------------------------------
-int wxNotebook::GetPageCount() const
+
+size_t wxNotebook::GetPageCount() const
 {
-    return m_aPages.Count();
-}
+    //
+    // Consistency check
+    //
+    wxASSERT((int)m_pages.Count() == (int)::WinSendMsg(GetHWND(), BKM_QUERYPAGECOUNT, (MPARAM)0, (MPARAM)BKA_END));
+    return m_pages.Count();
+} // end of wxNotebook::GetPageCount
 
 int wxNotebook::GetRowCount() const
 {
-    // TODO
-    return 0;
-}
-
-int wxNotebook::SetSelection(int nPage)
+    return (int)::WinSendMsg( GetHWND()
+                             ,BKM_QUERYPAGECOUNT
+                             ,(MPARAM)0
+                             ,(MPARAM)BKA_MAJOR
+                            );
+} // end of wxNotebook::GetRowCount
+
+int wxNotebook::SetSelection( size_t nPage )
 {
-    wxASSERT( IS_VALID_PAGE(nPage) );
-
-    ChangePage(m_nSelection, nPage);
-
-    // TODO
-    return 0;
-}
+    wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
+
+    if (nPage != (size_t)m_nSelection)
+    {
+        wxNotebookEvent             vEvent( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
+                                           ,m_windowId
+                                          );
+
+        vEvent.SetSelection(nPage);
+        vEvent.SetOldSelection(m_nSelection);
+        vEvent.SetEventObject(this);
+        if (!GetEventHandler()->ProcessEvent(vEvent) || vEvent.IsAllowed())
+        {
+
+            //
+            // Program allows the page change
+            //
+            vEvent.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
+            GetEventHandler()->ProcessEvent(vEvent);
+
+            ::WinSendMsg( GetHWND()
+                         ,BKM_TURNTOPAGE
+                         ,MPFROMLONG((ULONG)m_alPageId[nPage])
+                         ,(MPARAM)0
+                        );
+        }
+    }
+    m_nSelection = nPage;
+    return nPage;
+} // end of wxNotebook::SetSelection
 
-void wxNotebook::AdvanceSelection(bool bForward)
+int wxNotebook::ChangeSelection( size_t nPage )
 {
-    int nSel = GetSelection();
-    int nMax = GetPageCount() - 1;
-    if ( bForward )
-        SetSelection(nSel == nMax ? 0 : nSel + 1);
-    else
-        SetSelection(nSel == 0 ? nMax : nSel - 1);
+    wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
+
+    if (nPage != (size_t)m_nSelection)
+    {
+        ::WinSendMsg( GetHWND()
+                ,BKM_TURNTOPAGE
+                ,MPFROMLONG((ULONG)m_alPageId[nPage])
+                        ,(MPARAM)0
+                    );
+    }
+    m_nSelection = nPage;
+    return nPage;
 }
 
-bool wxNotebook::SetPageText(int nPage, const wxString& strText)
+bool wxNotebook::SetPageText( size_t nPage,
+                              const wxString& rsStrText )
 {
-    wxASSERT( IS_VALID_PAGE(nPage) );
-
-    // TODO
-    return FALSE;
-}
-
-wxString wxNotebook::GetPageText(int nPage) const
+    wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
+    return (bool)::WinSendMsg( m_hWnd
+                              ,BKM_SETTABTEXT
+                              ,MPFROMLONG((ULONG)m_alPageId[nPage])
+                              ,MPFROMP((PSZ)rsStrText.c_str())
+                             );
+} // end of wxNotebook::SetPageText
+
+wxString wxNotebook::GetPageText ( size_t nPage ) const
 {
-    wxASSERT( IS_VALID_PAGE(nPage) );
+    BOOKTEXT                        vBookText;
+    wxChar                          zBuf[256];
+    wxString                        sStr;
+    ULONG                           ulRc;
+
+    wxCHECK_MSG( IS_VALID_PAGE(nPage), wxEmptyString, wxT("notebook page out of range") );
+
+    memset(&vBookText, '\0', sizeof(BOOKTEXT));
+    vBookText.textLen = 0; // This will get the length
+    ulRc = LONGFROMMR(::WinSendMsg( m_hWnd
+                                   ,BKM_QUERYTABTEXT
+                                   ,MPFROMLONG((ULONG)m_alPageId[nPage])
+                                   ,MPFROMP(&vBookText)
+                                  ));
+    if (ulRc == (ULONG)BOOKERR_INVALID_PARAMETERS || ulRc == 0L)
+    {
+        if (ulRc == (ULONG)BOOKERR_INVALID_PARAMETERS)
+        {
+            wxLogError(wxT("Invalid Page Id for page text querry."));
+        }
+        return wxEmptyString;
+    }
+    vBookText.textLen = ulRc + 1; // To get the null terminator
+    vBookText.pString = (char*)zBuf;
+
+    //
+    // Now get the actual text
+    //
+    ulRc = LONGFROMMR(::WinSendMsg( m_hWnd
+                                   ,BKM_QUERYTABTEXT
+                                   ,MPFROMLONG((ULONG)m_alPageId[nPage])
+                                   ,MPFROMP(&vBookText)
+                                  ));
+    if (ulRc == (ULONG)BOOKERR_INVALID_PARAMETERS || ulRc == 0L)
+    {
+        return wxEmptyString;
+    }
+    if (ulRc > 255L)
+        ulRc = 255L;
 
-    // TODO
-    return wxString("");
-}
+    vBookText.pString[ulRc] = '\0';
+    sStr = (wxChar*)vBookText.pString;
+    return sStr;
+} // end of wxNotebook::GetPageText
 
-int wxNotebook::GetPageImage(int nPage) const
+int wxNotebook::GetPageImage ( size_t nPage ) const
 {
-    wxASSERT( IS_VALID_PAGE(nPage) );
-
-    // TODO
-    return 0;
-}
-
-bool wxNotebook::SetPageImage(int nPage, int nImage)
+    wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
+
+    //
+    // For OS/2 just return the page
+    //
+    return nPage;
+} // end of wxNotebook::GetPageImage
+
+bool wxNotebook::SetPageImage (
+  size_t                            nPage
+, int                               nImage
+)
 {
-    wxASSERT( IS_VALID_PAGE(nPage) );
-
-    // TODO
-    return FALSE;
-}
-
-void wxNotebook::SetImageList(wxImageList* imageList)
-{ 
-    m_pImageList = imageList;
-    // TODO
-}
+    wxBitmap                        vBitmap = (wxBitmap)m_imageList->GetBitmap(nImage);
+
+    return (bool)::WinSendMsg( GetHWND()
+                              ,BKM_SETTABBITMAP
+                              ,MPFROMLONG((ULONG)m_alPageId[nPage])
+                              ,(MPARAM)wxFlipBmp(vBitmap.GetHBITMAP())
+                             );
+} // end of wxNotebook::SetPageImage
+
+void wxNotebook::SetImageList (
+  wxImageList*                      pImageList
+)
+{
+    //
+    // Does not really do anything yet, but at least we need to
+    // update the base class.
+    //
+    wxNotebookBase::SetImageList(pImageList);
+} // end of wxNotebook::SetImageList
 
 // ----------------------------------------------------------------------------
-// wxNotebook operations
+// wxNotebook size settings
 // ----------------------------------------------------------------------------
-
-// remove one page from the notebook
-bool wxNotebook::DeletePage(int nPage)
+void wxNotebook::SetPageSize (
+  const wxSize&                     rSize
+)
 {
-    wxCHECK( IS_VALID_PAGE(nPage), FALSE );
+    SetSize(rSize);
+} // end of wxNotebook::SetPageSize
 
-    // TODO: delete native widget page
-
-    delete m_aPages[nPage];
-    m_aPages.Remove(nPage);
+void wxNotebook::SetPadding (
+  const wxSize&                     WXUNUSED(rPadding)
+)
+{
+    //
+    // No padding in OS/2
+    //
+} // end of wxNotebook::SetPadding
+
+void wxNotebook::SetTabSize (
+  const wxSize&                     rSize
+)
+{
+    ::WinSendMsg( GetHWND()
+                 ,BKM_SETDIMENSIONS
+                 ,MPFROM2SHORT( (USHORT)rSize.x
+                               ,(USHORT)rSize.y
+                              )
+                 ,(MPARAM)BKA_MAJORTAB
+                );
+} // end of wxNotebook::SetTabSize
 
-    return TRUE;
-}
+// ----------------------------------------------------------------------------
+// wxNotebook operations
+// ----------------------------------------------------------------------------
 
-// remove one page from the notebook, without deleting the window
-bool wxNotebook::RemovePage(int nPage)
+//
+// Remove one page from the notebook, without deleting
+//
+wxNotebookPage* wxNotebook::DoRemovePage ( size_t nPage )
 {
-    wxCHECK( IS_VALID_PAGE(nPage), FALSE );
-
-    m_aPages.Remove(nPage);
+    wxNotebookPage* pPageRemoved = wxNotebookBase::DoRemovePage(nPage);
+
+    if (!pPageRemoved)
+        return NULL;
+
+    ::WinSendMsg( GetHWND()
+                 ,BKM_DELETEPAGE
+                 ,MPFROMLONG((ULONG)m_alPageId[nPage])
+                 ,(MPARAM)BKA_TAB
+                );
+    if (m_pages.IsEmpty())
+    {
+        //
+        // No selection any more, the notebook becamse empty
+        //
+        m_nSelection = -1;
+    }
+    else // notebook still not empty
+    {
+        //
+        // Change the selected page if it was deleted or became invalid
+        //
+        int                         nSelNew;
+
+        if (m_nSelection == (int)GetPageCount())
+        {
+            //
+            // Last page deleted, make the new last page the new selection
+            //
+            nSelNew = m_nSelection - 1;
+        }
+        else if (nPage <= (size_t)m_nSelection)
+        {
+            //
+            // We must show another page, even if it has the same index
+            //
+            nSelNew = m_nSelection;
+        }
+        else // nothing changes for the currently selected page
+        {
+            nSelNew = -1;
+
+            //
+            // We still must refresh the current page: this needs to be done
+            // for some unknown reason if the tab control shows the up-down
+            // control (i.e. when there are too many pages) -- otherwise after
+            // deleting a page nothing at all is shown
+            //
+            m_pages[m_nSelection]->Refresh();
+        }
 
-    return TRUE;
-}
+        if (nSelNew != -1)
+        {
+            //
+            // m_nSelection must be always valid so reset it before calling
+            // SetSelection()
+            //
+            m_nSelection = -1;
+            SetSelection(nSelNew);
+        }
+    }
+    return pPageRemoved;
+} // end of wxNotebook::DoRemovePage
 
-// remove all pages
+//
+// Remove all pages
+//
 bool wxNotebook::DeleteAllPages()
 {
-    // TODO: delete native widget pages
+    int                             nPageCount = GetPageCount();
+    int                             nPage;
+
+    for (nPage = 0; nPage < nPageCount; nPage++)
+        delete m_pages[nPage];
+    m_pages.Clear();
+    ::WinSendMsg( GetHWND()
+                 ,BKM_DELETEPAGE
+                 ,(MPARAM)0
+                 ,(MPARAM)BKA_ALL
+                );
+    m_nSelection = -1;
 
-    int nPageCount = GetPageCount();
-    int nPage;
-    for ( nPage = 0; nPage < nPageCount; nPage++ )
-        delete m_aPages[nPage];
+    return true;
+} // end of wxNotebook::DeleteAllPages
+
+//
+// Add a page to the notebook
+//
+bool wxNotebook::AddPage (
+  wxNotebookPage*                   pPage
+, const wxString&                   rStrText
+, bool                              bSelect
+, int                               nImageId
+)
+{
+    return InsertPage( GetPageCount()
+                      ,pPage
+                      ,rStrText
+                      ,bSelect
+                      ,nImageId
+                     );
+} // end of wxNotebook::AddPage
+
+//
+// Same as AddPage() but does it at given position
+//
+bool wxNotebook::InsertPage ( size_t          nPage,
+                              wxNotebookPage* pPage,
+                              const wxString& rsStrText,
+                              bool            bSelect,
+                              int             nImageId )
+{
+    ULONG                           ulApiPage;
 
-    m_aPages.Clear();
+    wxASSERT( pPage != NULL );
+    wxCHECK( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false );
+
+    //
+    // Under OS/2 we can only insert FIRST, LAST, NEXT or PREV.  Requires
+    // two different calls to the API.  Page 1 uses the BKA_FIRST.  Subsequent
+    // pages use the previous page ID coupled with a BKA_NEXT call.  Unlike
+    // Windows, OS/2 uses an internal Page ID to ID the pages.
+    //
+    // OS/2 also has a nice auto-size feature that automatically sizes the
+    // the attached window so we don't have to worry about the size of the
+    // window on the page.
+    //
+    if (nPage == 0)
+    {
+        ulApiPage = LONGFROMMR(::WinSendMsg( GetHWND()
+                                            ,BKM_INSERTPAGE
+                                            ,(MPARAM)0
+                                            ,MPFROM2SHORT(BKA_AUTOPAGESIZE | BKA_MAJOR, BKA_FIRST)
+                                           ));
+        if (ulApiPage == 0L)
+        {
+            ERRORID                 vError;
+            wxString                sError;
+
+            vError = ::WinGetLastError(vHabmain);
+            sError = wxPMErrorToStr(vError);
+            return false;
+        }
+        m_alPageId.Insert((long)ulApiPage, nPage);
+    }
+    else
+    {
+        ulApiPage = LONGFROMMR(::WinSendMsg( GetHWND()
+                                            ,BKM_INSERTPAGE
+                                            ,MPFROMLONG((ULONG)m_alPageId[nPage - 1])
+                                            ,MPFROM2SHORT(BKA_AUTOPAGESIZE | BKA_MAJOR, BKA_NEXT)
+                                           ));
+        if (ulApiPage == 0L)
+        {
+            ERRORID                     vError;
+            wxString                    sError;
+
+            vError = ::WinGetLastError(vHabmain);
+            sError = wxPMErrorToStr(vError);
+            return false;
+        }
+        m_alPageId.Insert((long)ulApiPage, nPage);
+    }
 
-    return TRUE;
-}
+    //
+    // Associate a window handle with the page
+    //
+    if (pPage)
+    {
+        if (!::WinSendMsg( GetHWND()
+                          ,BKM_SETPAGEWINDOWHWND
+                          ,MPFROMLONG((ULONG)m_alPageId[nPage])
+                          ,MPFROMHWND(pPage->GetHWND())
+                         ))
+            return false;
+    }
+    //
+    // If the inserted page is before the selected one, we must update the
+    // index of the selected page
+    //
+    if (nPage <= (size_t)m_nSelection)
+    {
+        //
+        // One extra page added
+        //
+        m_nSelection++;
+    }
 
-// add a page to the notebook
-bool wxNotebook::AddPage(wxNotebookPage *pPage,
-                         const wxString& strText,
-                         bool bSelect,
-                         int imageId)
-{
-    return InsertPage(GetPageCount(), pPage, strText, bSelect, imageId);
-}
+    if (pPage)
+    {
+        //
+        // Save the pointer to the page
+        //
+        m_pages.Insert( pPage
+                       ,nPage
+                      );
+    }
 
-// same as AddPage() but does it at given position
-bool wxNotebook::InsertPage(int nPage,
-                            wxNotebookPage *pPage,
-                            const wxString& strText,
-                            bool bSelect,
-                            int imageId)
-{
-    wxASSERT( pPage != NULL );
-    wxCHECK( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), FALSE );
+    //
+    // Now set TAB dimenstions
+    //
+
+    wxWindowDC vDC(this);
+    wxCoord    nTextX;
+    wxCoord    nTextY;
+
+    vDC.GetTextExtent(rsStrText, &nTextX, &nTextY);
+    nTextY *= 2;
+    nTextX  = (wxCoord)(nTextX * 1.3);
+    if (nTextX > m_nTabSize)
+    {
+        m_nTabSize = nTextX;
+        ::WinSendMsg( GetHWND()
+                     ,BKM_SETDIMENSIONS
+                     ,MPFROM2SHORT((USHORT)m_nTabSize, (USHORT)nTextY)
+                     ,(MPARAM)BKA_MAJORTAB
+                    );
+    }
+    //
+    // Now set any TAB text
+    //
+    if (!rsStrText.empty())
+    {
+        if (!SetPageText( nPage
+                         ,rsStrText
+                        ))
+            return false;
+    }
 
-    // TODO: insert native widget page
+    //
+    // Now set any TAB bitmap image
+    //
+    if (nImageId != -1)
+    {
+        if (!SetPageImage( nPage
+                          ,nImageId
+                         ))
+            return false;
+    }
 
-    // save the pointer to the page
-    m_aPages.Insert(pPage, nPage);
+    if (pPage)
+    {
+        //
+        // Don't show pages by default (we'll need to adjust their size first)
+        //
+        HWND hWnd = GetWinHwnd(pPage);
+
+        WinSetWindowULong( hWnd
+                          ,QWL_STYLE
+                          ,WinQueryWindowULong( hWnd
+                                               ,QWL_STYLE
+                                              ) & ~WS_VISIBLE
+                         );
+
+        //
+        // This updates internal flag too - otherwise it will get out of sync
+        //
+        pPage->Show(false);
+    }
 
-    // some page must be selected: either this one or the first one if there is 
+    //
+    // Some page should be selected: either this one or the first one if there is
     // still no selection
-    if ( bSelect )
-        m_nSelection = nPage;
+    //
+    int nSelNew = -1;
+
+    if (bSelect)
+        nSelNew = nPage;
     else if ( m_nSelection == -1 )
-        m_nSelection = 0;
+        nSelNew = 0;
 
-    return TRUE;
-}
+    if (nSelNew != -1)
+        SetSelection(nSelNew);
+
+    InvalidateBestSize();
+
+    return true;
+} // end of wxNotebook::InsertPage
 
 // ----------------------------------------------------------------------------
 // wxNotebook callbacks
 // ----------------------------------------------------------------------------
+void wxNotebook::OnSize(
+  wxSizeEvent&                      rEvent
+)
+{
+    rEvent.Skip();
+} // end of wxNotebook::OnSize
 
-// @@@ OnSize() is used for setting the font when it's called for the first
-//     time because doing it in ::Create() doesn't work (for unknown reasons)
-void wxNotebook::OnSize(wxSizeEvent& event)
+void wxNotebook::OnSelChange (
+  wxNotebookEvent&                  rEvent
+)
 {
-    static bool s_bFirstTime = TRUE;
-    if ( s_bFirstTime ) {
-        // TODO: any first-time-size processing.
-        s_bFirstTime = FALSE;
-    }
+    //
+    // Is it our tab control?
+    //
+    if (rEvent.GetEventObject() == this)
+    {
+        int   nPageCount = GetPageCount();
+        int   nSel;
+        ULONG ulOS2Sel = (ULONG)rEvent.GetOldSelection();
+        bool  bFound = false;
+
+        for (nSel = 0; nSel < nPageCount; nSel++)
+        {
+            if (ulOS2Sel == (ULONG)m_alPageId[nSel])
+            {
+                bFound = true;
+                break;
+            }
+        }
 
-    // TODO: all this may or may not be necessary for your platform
+        if (!bFound)
+            return;
 
-    // emulate page change (it's esp. important to do it first time because
-    // otherwise our page would stay invisible)
-    int nSel = m_nSelection;
-    m_nSelection = -1;
-    SetSelection(nSel);
-
-    // fit the notebook page to the tab control's display area
-    int w, h;
-    GetSize(&w, &h);
-
-    unsigned int nCount = m_aPages.Count();
-    for ( unsigned int nPage = 0; nPage < nCount; nPage++ ) {
-        wxNotebookPage *pPage = m_aPages[nPage];
-        pPage->SetSize(0, 0, w, h);
-        if ( pPage->GetAutoLayout() )
-            pPage->Layout();
-    }
+        m_pages[nSel]->Show(false);
 
-    // Processing continues to next OnSize
-    event.Skip();
-}
+        ulOS2Sel = (ULONG)rEvent.GetSelection();
 
-void wxNotebook::OnSelChange(wxNotebookEvent& event)
-{
-    // is it our tab control?
-    if ( event.GetEventObject() == this )
-        ChangePage(event.GetOldSelection(), event.GetSelection());
+        bFound = false;
 
-    // we want to give others a chance to process this message as well
-    event.Skip();
-}
+        for (nSel = 0; nSel < nPageCount; nSel++)
+        {
+            if (ulOS2Sel == (ULONG)m_alPageId[nSel])
+            {
+                bFound = true;
+                break;
+            }
+        }
 
-void wxNotebook::OnSetFocus(wxFocusEvent& event)
-{
-    // set focus to the currently selected page if any
-    if ( m_nSelection != -1 )
-        m_aPages[m_nSelection]->SetFocus();
+        if (!bFound)
+            return;
 
-    event.Skip();
-}
+        wxNotebookPage*         pPage = m_pages[nSel];
 
-void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
+        pPage->Show(true);
+        m_nSelection = nSel;
+    }
+
+    //
+    // We want to give others a chance to process this message as well
+    //
+    rEvent.Skip();
+} // end of wxNotebook::OnSelChange
+
+void wxNotebook::OnSetFocus (
+  wxFocusEvent&                     rEvent
+)
+{
+    //
+    // This function is only called when the focus is explicitly set (i.e. from
+    // the program) to the notebook - in this case we don't need the
+    // complicated OnNavigationKey() logic because the programmer knows better
+    // what [s]he wants
+    //
+    // set focus to the currently selected page if any
+    //
+    if (m_nSelection != -1)
+        m_pages[m_nSelection]->SetFocus();
+    rEvent.Skip();
+} // end of wxNotebook::OnSetFocus
+
+void wxNotebook::OnNavigationKey (
+  wxNavigationKeyEvent&             rEvent
+)
 {
-    if ( event.IsWindowChange() ) {
-        // change pages
-        AdvanceSelection(event.GetDirection());
+    if (rEvent.IsWindowChange())
+    {
+        //
+        // Change pages
+        //
+        AdvanceSelection(rEvent.GetDirection());
     }
-    else {
-        // pass to the parent
-        if ( GetParent() ) {
-            event.SetCurrentFocus(this);
-            GetParent()->ProcessEvent(event);
+    else
+    {
+        //
+        // We get this event in 2 cases
+        //
+        // a) one of our pages might have generated it because the user TABbed
+        // out from it in which case we should propagate the event upwards and
+        // our parent will take care of setting the focus to prev/next sibling
+        //
+        // or
+        //
+        // b) the parent panel wants to give the focus to us so that we
+        // forward it to our selected page. We can't deal with this in
+        // OnSetFocus() because we don't know which direction the focus came
+        // from in this case and so can't choose between setting the focus to
+        // first or last panel child
+        //
+        wxWindow*                   pParent = GetParent();
+
+        if (rEvent.GetEventObject() == pParent)
+        {
+            //
+            // No, it doesn't come from child, case (b): forward to a page
+            //
+            if (m_nSelection != -1)
+            {
+                //
+                // So that the page knows that the event comes from it's parent
+                // and is being propagated downwards
+                //
+                rEvent.SetEventObject(this);
+
+                wxWindow*           pPage = m_pages[m_nSelection];
+
+                if (!pPage->GetEventHandler()->ProcessEvent(rEvent))
+                {
+                    pPage->SetFocus();
+                }
+                //else: page manages focus inside it itself
+            }
+            else
+            {
+                //
+                // We have no pages - still have to give focus to _something_
+                //
+                SetFocus();
+            }
+        }
+        else
+        {
+            //
+            // It comes from our child, case (a), pass to the parent
+            //
+            if (pParent)
+            {
+                rEvent.SetCurrentFocus(this);
+                pParent->GetEventHandler()->ProcessEvent(rEvent);
+            }
         }
     }
-}
+} // end of wxNotebook::OnNavigationKey
 
 // ----------------------------------------------------------------------------
 // wxNotebook base class virtuals
 // ----------------------------------------------------------------------------
 
-// override these 2 functions to do nothing: everything is done in OnSize
-
-void wxNotebook::SetConstraintSizes(bool /* recurse */)
-{
-    // don't set the sizes of the pages - their correct size is not yet known
-    wxControl::SetConstraintSizes(FALSE);
-}
-
-bool wxNotebook::DoPhase(int /* nPhase */)
+//
+// Override these 2 functions to do nothing: everything is done in OnSize
+//
+void wxNotebook::SetConstraintSizes( bool WXUNUSED(bRecurse) )
 {
-    return TRUE;
-}
+    //
+    // Don't set the sizes of the pages - their correct size is not yet known
+    //
+    wxControl::SetConstraintSizes(false);
+} // end of wxNotebook::SetConstraintSizes
 
-void wxNotebook::Command(wxCommandEvent& event)
+bool wxNotebook::DoPhase ( int WXUNUSED(nPhase) )
 {
-    wxFAIL_MSG("wxNotebook::Command not implemented");
-}
+    return true;
+} // end of wxNotebook::DoPhase
 
 // ----------------------------------------------------------------------------
-// wxNotebook helper functions
+// wxNotebook Windows message handlers
 // ----------------------------------------------------------------------------
-
-// hide the currently active panel and show the new one
-void wxNotebook::ChangePage(int nOldSel, int nSel)
-{
-    wxASSERT( nOldSel != nSel ); // impossible
-
-    if ( nOldSel != -1 ) {
-        m_aPages[nOldSel]->Show(FALSE);
-    }
-
-    wxNotebookPage *pPage = m_aPages[nSel];
-    pPage->Show(TRUE);
-    pPage->SetFocus();
-
-    m_nSelection = nSel;
-}
-
-void wxNotebook::SetTabSize(const wxSize& sz)
+bool wxNotebook::OS2OnScroll ( int    nOrientation,
+                               WXWORD wSBCode,
+                               WXWORD wPos,
+                               WXHWND wControl )
 {
-    // TODO
-}
-
+    //
+    // Don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
+    // up-down control
+    //
+    if (wControl)
+        return false;
+    return wxNotebookBase::OS2OnScroll( nOrientation
+                                       ,wSBCode
+                                       ,wPos
+                                       ,wControl
+                                      );
+} // end of wxNotebook::OS2OnScroll
+
+#endif // wxUSE_NOTEBOOK