]> git.saurik.com Git - wxWidgets.git/blobdiff - src/os2/notebook.cpp
Test the commit announcement bot some more by fixing more gtk signal callback handler...
[wxWidgets.git] / src / os2 / notebook.cpp
index 9d105d5ae998c44f8426a5d7cb248082ac453616..ee9b6810ebfe2c74e1188fe15f5c18c184a6ffdf 100644 (file)
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////////
-// Name:        notebook.cpp
+// Name:        src/os2/notebook.cpp
 // Purpose:     implementation of wxNotebook
 // Author:      David Webster
 // Modified by:
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
-// wxWindows
+#if wxUSE_NOTEBOOK
+
+// wxWidgets
 #ifndef WX_PRECOMP
-  #include  <wx/string.h>
+  #include "wx/app.h"
+  #include "wx/dcclient.h"
+  #include "wx/string.h"
+  #include "wx/settings.h"
 #endif  // WX_PRECOMP
 
-#include  <wx/log.h>
-#include  <wx/imaglist.h>
-#include  <wx/event.h>
-#include  <wx/control.h>
-#include  <wx/notebook.h>
-
-#include  <wx/os2/private.h>
+#include  "wx/log.h"
+#include  "wx/imaglist.h"
+#include  "wx/event.h"
+#include  "wx/control.h"
+#include  "wx/notebook.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()
+#define m_hWnd    (HWND)GetHWND()
 
 // ----------------------------------------------------------------------------
 // constants
 // ----------------------------------------------------------------------------
 
-// This is a work-around for missing defines in gcc-2.95 headers
-#ifndef TCS_RIGHT
-    #define TCS_RIGHT       0x0002
-#endif
-
-#ifndef TCS_VERTICAL
-    #define TCS_VERTICAL    0x0080
-#endif
-
-#ifndef TCS_BOTTOM
-    #define TCS_BOTTOM      TCS_RIGHT
-#endif
-
 // ----------------------------------------------------------------------------
 // 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()
+END_EVENT_TABLE()
 
-  IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
-  IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxNotifyEvent)
-#endif
+IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
+IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxNotifyEvent)
 
 // ============================================================================
 // implementation
 // 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
-  if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
-      return FALSE;
-
-  // colors and font
-// TODO:  m_backgroundColour = wxColour(GetSysColor(COLOR_BTNFACE));
-  m_foregroundColour = *wxBLACK ;
-
-    // TODO:
-/*
-  // style
-  m_windowStyle = style | wxTAB_TRAVERSAL;
-
-  long tabStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | TCS_TABS;
-
-  if (m_windowStyle & wxCLIP_CHILDREN)
-    tabStyle |= WS_CLIPCHILDREN;
-  if ( m_windowStyle & wxTC_MULTILINE )
-    tabStyle |= TCS_MULTILINE;
-  if ( m_windowStyle & wxBORDER )
-    tabStyle &= WS_BORDER;
-  if (m_windowStyle & wxNB_FIXEDWIDTH)
-    tabStyle |= TCS_FIXEDWIDTH ;
-  if (m_windowStyle & wxNB_BOTTOM)
-    tabStyle |= TCS_RIGHT;
-  if (m_windowStyle & wxNB_LEFT)
-    tabStyle |= TCS_VERTICAL;
-  if (m_windowStyle & wxNB_RIGHT)
-    tabStyle |= TCS_VERTICAL|TCS_RIGHT;
-
-
-  if ( !MSWCreate(GetId(), GetParent(), WC_TABCONTROL,
-                  this, NULL, pos.x, pos.y, size.x, size.y,
-                  tabStyle, NULL, 0) )
-  {
-    return FALSE;
-  }
-
-  // Not all compilers recognise SetWindowFont
-  ::SendMessage(GetHwnd(), WM_SETFONT,
-                (WPARAM)::GetStockObject(DEFAULT_GUI_FONT), TRUE);
-
-
-  if ( parent != NULL )
-    parent->AddChild(this);
-*/
-  SubclassWin(m_hWnd);
-
-    return FALSE;
-}
-
-// dtor
-wxNotebook::~wxNotebook()
+    //
+    // 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 )
 {
-    wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") );
+    wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
 
-    ChangePage(m_nSelection, nPage);
+    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())
+        {
 
-    // TODO
-    return 0;
-}
+            //
+            // 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)
+bool wxNotebook::SetPageText( size_t nPage,
+                              const wxString& rsStrText )
 {
-    int nSel = GetSelection();
-    int nMax = GetPageCount() - 1;
-    if ( bForward )
-        SetSelection(nSel == nMax ? 0 : nSel + 1);
-    else
-        SetSelection(nSel == 0 ? nMax : nSel - 1);
-}
-
-bool wxNotebook::SetPageText(int nPage, const wxString& strText)
+    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
 {
-    wxCHECK_MSG( IS_VALID_PAGE(nPage), FALSE, wxT("notebook page out of range") );
+    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 FALSE;
-}
+    vBookText.pString[ulRc] = '\0';
+    sStr = (wxChar*)vBookText.pString;
+    return sStr;
+} // end of wxNotebook::GetPageText
 
-wxString wxNotebook::GetPageText(int nPage) const
+int wxNotebook::GetPageImage ( size_t nPage ) const
 {
-    wxCHECK_MSG( IS_VALID_PAGE(nPage), wxT(""), wxT("notebook page out of range") );
-
-    // TODO
-    return wxString("");
-}
-
-int wxNotebook::GetPageImage(int nPage) const
+    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
+)
 {
-    wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") );
-
-    // TODO
-    return 0;
-}
-
-bool wxNotebook::SetPageImage(int nPage, int nImage)
+    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
+)
 {
-    wxCHECK_MSG( IS_VALID_PAGE(nPage), FALSE, wxT("notebook page out of range") );
+    //
+    // Does not really do anything yet, but at least we need to
+    // update the base class.
+    //
+    wxNotebookBase::SetImageList(pImageList);
+} // end of wxNotebook::SetImageList
 
-    // TODO
-    return FALSE;
-}
-
-void wxNotebook::SetImageList(wxImageList* imageList)
+// ----------------------------------------------------------------------------
+// wxNotebook size settings
+// ----------------------------------------------------------------------------
+void wxNotebook::SetPageSize (
+  const wxSize&                     rSize
+)
 {
-    m_pImageList = imageList;
-    // TODO
-}
+    SetSize(rSize);
+} // end of wxNotebook::SetPageSize
 
-void wxNotebook::SetTabSize(const wxSize& sz)
+void wxNotebook::SetPadding (
+  const wxSize&                     WXUNUSED(rPadding)
+)
+{
+    //
+    // No padding in OS/2
+    //
+} // end of wxNotebook::SetPadding
+
+void wxNotebook::SetTabSize (
+  const wxSize&                     rSize
+)
 {
-    // TODO
-}
+    ::WinSendMsg( GetHWND()
+                 ,BKM_SETDIMENSIONS
+                 ,MPFROM2SHORT( (USHORT)rSize.x
+                               ,(USHORT)rSize.y
+                              )
+                 ,(MPARAM)BKA_MAJORTAB
+                );
+} // end of wxNotebook::SetTabSize
 
 // ----------------------------------------------------------------------------
 // wxNotebook operations
 // ----------------------------------------------------------------------------
 
-// remove one page from the notebook
-bool wxNotebook::DeletePage(int nPage)
+//
+// Remove one page from the notebook, without deleting
+//
+wxNotebookPage* wxNotebook::DoRemovePage ( size_t nPage )
 {
-    wxCHECK_MSG( IS_VALID_PAGE(nPage), FALSE, wxT("notebook page out of range") );
+    wxNotebookPage* pPageRemoved = wxNotebookBase::DoRemovePage(nPage);
 
-    // TODO: delete native widget page
+    if (!pPageRemoved)
+        return NULL;
 
-    delete m_aPages[nPage];
-    m_aPages.Remove(nPage);
+    ::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;
 
-    return TRUE;
-}
+        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();
+        }
 
-// remove one page from the notebook, without deleting the window
-bool wxNotebook::RemovePage(int nPage)
+        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
+//
+bool wxNotebook::DeleteAllPages()
 {
-    wxCHECK_MSG( IS_VALID_PAGE(nPage), FALSE, wxT("notebook page out of range") );
+    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;
 
-    m_aPages.Remove(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;
 
-    return TRUE;
-}
+    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;
 
-// remove all pages
-bool wxNotebook::DeleteAllPages()
-{
-    // TODO: delete native widget pages
+            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;
 
-    int nPageCount = GetPageCount();
-    int nPage;
-    for ( nPage = 0; nPage < nPageCount; nPage++ )
-        delete m_aPages[nPage];
+            vError = ::WinGetLastError(vHabmain);
+            sError = wxPMErrorToStr(vError);
+            return false;
+        }
+        m_alPageId.Insert((long)ulApiPage, nPage);
+    }
 
-    m_aPages.Clear();
+    //
+    // 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++;
+    }
 
-    return TRUE;
-}
+    if (pPage)
+    {
+        //
+        // Save the pointer to the page
+        //
+        m_pages.Insert( pPage
+                       ,nPage
+                      );
+    }
 
-// 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);
-}
-
-// 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
+    //
 
-    // TODO: insert native widget page
+    wxWindowDC vDC(this);
+    wxCoord    nTextX;
+    wxCoord    nTextY;
 
-    // save the pointer to the page
-    m_aPages.Insert(pPage, nPage);
+    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;
+    }
+
+    //
+    // Now set any TAB bitmap image
+    //
+    if (nImageId != -1)
+    {
+        if (!SetPageImage( nPage
+                          ,nImageId
+                         ))
+            return false;
+    }
+
+    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;
+
+    if (nSelNew != -1)
+        SetSelection(nSelNew);
+
+    InvalidateBestSize();
 
-    return TRUE;
-}
+    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;
 
-    // TODO: all this may or may not be necessary for your platform
+        for (nSel = 0; nSel < nPageCount; nSel++)
+        {
+            if (ulOS2Sel == (ULONG)m_alPageId[nSel])
+            {
+                bFound = true;
+                break;
+            }
+        }
 
-    // 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();
-    }
+        if (!bFound)
+            return;
 
-    // Processing continues to next OnSize
-    event.Skip();
-}
+        m_pages[nSel]->Show(false);
 
-void wxNotebook::OnSelChange(wxNotebookEvent& event)
-{
-    // is it our tab control?
-    if ( event.GetEventObject() == this )
-    {
-        int sel = event.GetOldSelection();
-        if ( sel != -1 )
-            m_aPages[sel]->Show(FALSE);
+        ulOS2Sel = (ULONG)rEvent.GetSelection();
+
+        bFound = false;
 
-        sel = event.GetSelection();
-        if ( sel != -1 )
+        for (nSel = 0; nSel < nPageCount; nSel++)
         {
-            wxNotebookPage *pPage = m_aPages[sel];
-            pPage->Show(TRUE);
-            pPage->SetFocus();
+            if (ulOS2Sel == (ULONG)m_alPageId[nSel])
+            {
+                bFound = true;
+                break;
+            }
         }
 
-        m_nSelection = sel;
-  }
-    // we want to give others a chance to process this message as well
-    event.Skip();
-}
+        if (!bFound)
+            return;
 
-void wxNotebook::OnSetFocus(wxFocusEvent& event)
-{
-    // set focus to the currently selected page if any
-    if ( m_nSelection != -1 )
-        m_aPages[m_nSelection]->SetFocus();
+        wxNotebookPage*         pPage = m_pages[nSel];
+
+        pPage->Show(true);
+        m_nSelection = nSel;
+    }
 
-    event.Skip();
-}
+    //
+    // We want to give others a chance to process this message as well
+    //
+    rEvent.Skip();
+} // end of wxNotebook::OnSelChange
 
-void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
+void wxNotebook::OnSetFocus (
+  wxFocusEvent&                     rEvent
+)
 {
-    if ( event.IsWindowChange() ) {
-        // change pages
-        AdvanceSelection(event.GetDirection());
+    //
+    // 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 (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
 
-bool wxNotebook::OS2OnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
+bool wxNotebook::DoPhase ( int WXUNUSED(nPhase) )
 {
-  wxNotebookEvent event(wxEVT_NULL, m_windowId);
-//TODO:
-/*
-  NMHDR* hdr = (NMHDR *)lParam;
-  switch ( hdr->code ) {
-    case TCN_SELCHANGE:
-      event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
-      break;
-
-    case TCN_SELCHANGING:
-      event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
-      break;
-
-    default:
-      return wxControl::MSWOnNotify(idCtrl, lParam, result);
-  }
-*/
-// TODO:    event.SetSelection(TabCtrl_GetCurSel(m_hwnd));
-    event.SetOldSelection(m_nSelection);
-    event.SetEventObject(this);
-    event.SetInt(idCtrl);
-
-    bool processed = GetEventHandler()->ProcessEvent(event);
-// TODO:   *result = !event.IsAllowed();
-    return processed;
-}
+    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)
+bool wxNotebook::OS2OnScroll ( int    nOrientation,
+                               WXWORD wSBCode,
+                               WXWORD wPos,
+                               WXHWND wControl )
 {
-    // MT-FIXME should use a real semaphore
-    static bool s_bInsideChangePage = FALSE;
-
-    // when we call ProcessEvent(), our own OnSelChange() is called which calls
-    // this function - break the infinite loop
-    if ( s_bInsideChangePage )
-        return;
-
-    // it's not an error (the message may be generated by the tab control itself)
-    // and it may happen - just do nothing
-    if ( nSel == nOldSel )
-        return;
-
-    s_bInsideChangePage = TRUE;
-
-    wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_windowId);
-    event.SetSelection(nSel);
-    event.SetOldSelection(nOldSel);
-    event.SetEventObject(this);
-    if ( ProcessEvent(event) && !event.IsAllowed() )
-    {
-        // program doesn't allow the page change
-        s_bInsideChangePage = FALSE;
-        return;
-    }
-
-    event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
-    ProcessEvent(event);
-
-    s_bInsideChangePage = FALSE;
-}
-
+    //
+    // 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