Example #1
0
void wxNotebook::OnSize(wxSizeEvent& event)
{
    if ( GetPageCount() == 0 )
    {
        // Prevents droppings on resize, but does cause some flicker
        // when there are no pages.
        Refresh();
        event.Skip();
        return;
    }
#ifndef __WXWINCE__
    else
    {
        // Without this, we can sometimes get droppings at the edges
        // of a notebook, for example a notebook in a splitter window.
        // This needs to be reconciled with the RefreshRect calls
        // at the end of this function, which weren't enough to prevent
        // the droppings.

        wxSize sz = GetClientSize();

        // Refresh right side
        wxRect rect(sz.x-4, 0, 4, sz.y);
        RefreshRect(rect);

        // Refresh bottom side
        rect = wxRect(0, sz.y-4, sz.x, 4);
        RefreshRect(rect);

        // Refresh left side
        rect = wxRect(0, 0, 4, sz.y);
        RefreshRect(rect);
    }
#endif // !__WXWINCE__

    // fit all the notebook pages to the tab control's display area

    RECT rc;
    rc.left = rc.top = 0;
    GetSize((int *)&rc.right, (int *)&rc.bottom);

    // save the total size, we'll use it below
    int widthNbook = rc.right - rc.left,
        heightNbook = rc.bottom - rc.top;

    // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
    // returns completely false values for multiline tab controls after the tabs
    // are added but before getting the first WM_SIZE (off by ~50 pixels, see
    //
    // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
    //
    // and the only work around I could find was this ugly hack... without it
    // simply toggling the "multiline" checkbox in the notebook sample resulted
    // in a noticeable page displacement
    if ( HasFlag(wxNB_MULTILINE) )
    {
        // avoid an infinite recursion: we get another notification too!
        static bool s_isInOnSize = false;

        if ( !s_isInOnSize )
        {
            s_isInOnSize = true;
            SendMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED,
                    MAKELPARAM(rc.right, rc.bottom));
            s_isInOnSize = false;
        }

        // The best size depends on the number of rows of tabs, which can
        // change when the notepad is resized.
        InvalidateBestSize();
    }

#if wxUSE_UXTHEME
    // background bitmap size has changed, update the brush using it too
    UpdateBgBrush();
#endif // wxUSE_UXTHEME

    TabCtrl_AdjustRect(GetHwnd(), false, &rc);

    int width = rc.right - rc.left,
        height = rc.bottom - rc.top;
    size_t nCount = m_pages.Count();
    for ( size_t nPage = 0; nPage < nCount; nPage++ ) {
        wxNotebookPage *pPage = m_pages[nPage];
        pPage->SetSize(rc.left, rc.top, width, height);
    }


    // unless we had already repainted everything, we now need to refresh
    if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
    {
        // invalidate areas not covered by pages
        RefreshRect(wxRect(0, 0, widthNbook, rc.top), false);
        RefreshRect(wxRect(0, rc.top, rc.left, height), false);
        RefreshRect(wxRect(0, rc.bottom, widthNbook, heightNbook - rc.bottom),
                    false);
        RefreshRect(wxRect(rc.right, rc.top, widthNbook - rc.right, height),
                    false);
    }

#if USE_NOTEBOOK_ANTIFLICKER
    // subclass the spin control used by the notebook to scroll pages to
    // prevent it from flickering on resize
    if ( !m_hasSubclassedUpdown )
    {
        // iterate over all child windows to find spin button
        for ( HWND child = ::GetWindow(GetHwnd(), GW_CHILD);
              child;
              child = ::GetWindow(child, GW_HWNDNEXT) )
        {
            wxWindow *childWindow = wxFindWinFromHandle((WXHWND)child);

            // see if it exists, if no wxWindow found then assume it's the spin
            // btn
            if ( !childWindow )
            {
                // subclass the spin button to override WM_ERASEBKGND
                if ( !gs_wndprocNotebookSpinBtn )
                    gs_wndprocNotebookSpinBtn = (WXFARPROC)wxGetWindowProc(child);

                wxSetWindowProc(child, wxNotebookSpinBtnWndProc);
                m_hasSubclassedUpdown = true;
                break;
            }
        }
    }

    // Probably because of the games we play above to avoid flicker sometimes
    // the text controls inside notebook pages are not shown correctly (they
    // don't have their borders) when the notebook is shown for the first time.
    // It's not really clear why does this happen and maybe the bug is in
    // wxTextCtrl itself and not here but updating the page when it's about to
    // be shown doesn't cost much and works around the problem so do it here
    // for now.
    if ( !m_doneUpdateHack && IsShownOnScreen() )
    {
        m_doneUpdateHack = true;
        wxWindow* const page = GetCurrentPage();
        if ( page )
            page->Update();
    }
#endif // USE_NOTEBOOK_ANTIFLICKER

    event.Skip();
}
Example #2
0
// Create() function
bool wxNotebook::Create(wxWindow *parent,
                        wxWindowID id,
                        const wxPoint& pos,
                        const wxSize& size,
                        long style,
                        const wxString& name)
{
    if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT )
    {
#if defined(__POCKETPC__)
        style |= wxBK_BOTTOM | wxNB_FLAT;
#else
        style |= wxBK_TOP;
#endif
    }

#ifdef __WXWINCE__
    // Not sure why, but without this style, there is no border
    // around the notebook tabs.
    if (style & wxNB_FLAT)
        style |= wxBORDER_SUNKEN;
#endif

#if !wxUSE_UXTHEME
    // ComCtl32 notebook tabs simply don't work unless they're on top if we
    // have uxtheme, we can work around it later (after control creation), but
    // if we have been compiled without uxtheme support, we have to clear those
    // styles
    if ( HasTroubleWithNonTopTabs() )
    {
        style &= ~(wxBK_BOTTOM | wxBK_LEFT | wxBK_RIGHT);
    }
#endif //wxUSE_UXTHEME

#if defined(__WINE__) && wxUSE_UNICODE
    LPCTSTR className = L"SysTabControl32";
#else
    LPCTSTR className = WC_TABCONTROL;
#endif

#if USE_NOTEBOOK_ANTIFLICKER
    // SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it
    // causes horrible flicker when resizing notebook, so get rid of it by
    // using a class without these styles (but otherwise identical to it)
    if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
    {
        static ClassRegistrar s_clsNotebook;
        if ( !s_clsNotebook.IsInitialized() )
        {
            // get a copy of standard class and modify it
            WNDCLASS wc;

            if ( ::GetClassInfo(NULL, WC_TABCONTROL, &wc) )
            {
                gs_wndprocNotebook =
                    reinterpret_cast<WXFARPROC>(wc.lpfnWndProc);
                wc.lpszClassName = wxT("_wx_SysTabCtl32");
                wc.style &= ~(CS_HREDRAW | CS_VREDRAW);
                wc.hInstance = wxGetInstance();
                wc.lpfnWndProc = wxNotebookWndProc;
                s_clsNotebook.Register(wc);
            }
            else
            {
                wxLogLastError(wxT("GetClassInfoEx(SysTabCtl32)"));
            }
        }

        // use our custom class if available but fall back to the standard
        // notebook if we failed to register it
        if ( s_clsNotebook.IsRegistered() )
        {
            // it's ok to use c_str() here as the static s_clsNotebook object
            // has sufficiently long lifetime
            className = s_clsNotebook.GetName().c_str();
        }
    }
#endif // USE_NOTEBOOK_ANTIFLICKER

    if ( !CreateControl(parent, id, pos, size, style | wxTAB_TRAVERSAL,
                        wxDefaultValidator, name) )
        return false;

    if ( !MSWCreateControl(className, wxEmptyString, pos, size) )
        return false;

    // Inherit parent attributes and, unlike the default, also inherit the
    // parent background colour in order to blend in with its background if
    // it's set to a non-default value.
    InheritAttributes();
    if ( parent->InheritsBackgroundColour() && !UseBgCol() )
        SetBackgroundColour(parent->GetBackgroundColour());

#if wxUSE_UXTHEME
    if ( HasFlag(wxNB_NOPAGETHEME) ||
            wxSystemOptions::IsFalse(wxT("msw.notebook.themed-background")) )
    {
        SetBackgroundColour(GetThemeBackgroundColour());
    }
    else // use themed background by default
    {
        // create backing store
        UpdateBgBrush();
    }

    // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the
    // control is simply not rendered correctly), so we disable themes
    // if possible, otherwise we simply clear the styles.
    if ( HasTroubleWithNonTopTabs() &&
            (style & (wxBK_BOTTOM | wxBK_LEFT | wxBK_RIGHT)) )
    {
        // check if we use themes at all -- if we don't, we're still okay
        if ( wxUxThemeEngine::GetIfActive() )
        {
            wxUxThemeEngine::GetIfActive()->SetWindowTheme(GetHwnd(), L"", L"");

            // correct the background color for the new non-themed control
            SetBackgroundColour(GetThemeBackgroundColour());
        }
    }
#endif // wxUSE_UXTHEME

    // Undocumented hack to get flat notebook style
    // In fact, we should probably only do this in some
    // curcumstances, i.e. if we know we will have a border
    // at the bottom (the tab control doesn't draw it itself)
#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
    if (HasFlag(wxNB_FLAT))
    {
        SendMessage(GetHwnd(), CCM_SETVERSION, COMCTL32_VERSION, 0);
        if (!m_hasBgCol)
            SetBackgroundColour(*wxWHITE);
    }
#endif
    return true;
}
Example #3
0
// same as AddPage() but does it at given position
bool wxNotebook::InsertPage(size_t nPage,
                            wxNotebookPage *pPage,
                            const wxString& strText,
                            bool bSelect,
                            int imageId)
{
    wxCHECK_MSG( pPage != NULL, false, wxT("NULL page in wxNotebook::InsertPage") );
    wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false,
                 wxT("invalid index in wxNotebook::InsertPage") );

    wxASSERT_MSG( pPage->GetParent() == this,
                    wxT("notebook pages must have notebook as parent") );

    // add a new tab to the control
    // ----------------------------

    // init all fields to 0
    TC_ITEM tcItem;
    wxZeroMemory(tcItem);

    // set the image, if any
    if ( imageId != -1 )
    {
        tcItem.mask |= TCIF_IMAGE;
        tcItem.iImage  = imageId;
    }

    // and the text
    if ( !strText.empty() )
    {
        tcItem.mask |= TCIF_TEXT;
        tcItem.pszText = wxMSW_CONV_LPTSTR(strText);
    }

    // hide the page: unless it is selected, it shouldn't be shown (and if it
    // is selected it will be shown later)
    HWND hwnd = GetWinHwnd(pPage);
    SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);

    // this updates internal flag too -- otherwise it would get out of sync
    // with the real state
    pPage->Show(false);


    // fit the notebook page to the tab control's display area: this should be
    // done before adding it to the notebook or TabCtrl_InsertItem() will
    // change the notebooks size itself!
    AdjustPageSize(pPage);

    // finally do insert it
    if ( TabCtrl_InsertItem(GetHwnd(), nPage, &tcItem) == -1 )
    {
        wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());

        return false;
    }

    // need to update the bg brush when the first page is added
    // so the first panel gets the correct themed background
    if ( m_pages.empty() )
    {
#if wxUSE_UXTHEME
        UpdateBgBrush();
#endif // wxUSE_UXTHEME
    }

    // succeeded: save the pointer to the page
    m_pages.Insert(pPage, nPage);

    // we may need to adjust the size again if the notebook size changed:
    // normally this only happens for the first page we add (the tabs which
    // hadn't been there before are now shown) but for a multiline notebook it
    // can happen for any page at all as a new row could have been started
    if ( m_pages.GetCount() == 1 || HasFlag(wxNB_MULTILINE) )
    {
        AdjustPageSize(pPage);

        // Additionally, force the layout of the notebook itself by posting a
        // size event to it. If we don't do it, notebooks with pages on the
        // left or the right side may fail to account for the fact that they
        // are now big enough to fit all all of their pages on one row and
        // still reserve space for the second row of tabs, see #1792.
        const wxSize s = GetSize();
        ::PostMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED, MAKELPARAM(s.x, s.y));
    }

    // now deal with the selection
    // ---------------------------

    // if the inserted page is before the selected one, we must update the
    // index of the selected page
    if ( int(nPage) <= m_selection )
    {
        // one extra page added
        m_selection++;
    }

    DoSetSelectionAfterInsertion(nPage, bSelect);

    InvalidateBestSize();

    return true;
}
// same as AddPage() but does it at given position
bool wxNotebook::InsertPage(size_t nPage,
                            wxNotebookPage *pPage,
                            const wxString& strText,
                            bool bSelect,
                            int imageId)
{
    wxCHECK_MSG( pPage != NULL, false, wxT("NULL page in wxNotebook::InsertPage") );
    wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false,
                 wxT("invalid index in wxNotebook::InsertPage") );

    wxASSERT_MSG( pPage->GetParent() == this,
                    wxT("notebook pages must have notebook as parent") );

    // add a new tab to the control
    // ----------------------------

    // init all fields to 0
    TC_ITEM tcItem;
    wxZeroMemory(tcItem);

    // set the image, if any
    if ( imageId != -1 )
    {
        tcItem.mask |= TCIF_IMAGE;
        tcItem.iImage  = imageId;
    }

    // and the text
    if ( !strText.empty() )
    {
        tcItem.mask |= TCIF_TEXT;
        tcItem.pszText = (wxChar *)strText.wx_str(); // const_cast
    }

    // hide the page: unless it is selected, it shouldn't be shown (and if it
    // is selected it will be shown later)
    HWND hwnd = GetWinHwnd(pPage);
    SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);

    // this updates internal flag too -- otherwise it would get out of sync
    // with the real state
    pPage->Show(false);


    // fit the notebook page to the tab control's display area: this should be
    // done before adding it to the notebook or TabCtrl_InsertItem() will
    // change the notebooks size itself!
    AdjustPageSize(pPage);

    // finally do insert it
    if ( TabCtrl_InsertItem(GetHwnd(), nPage, &tcItem) == -1 )
    {
        wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());

        return false;
    }

    // need to update the bg brush when the first page is added
    // so the first panel gets the correct themed background
    if ( m_pages.empty() )
    {
#if wxUSE_UXTHEME
        UpdateBgBrush();
#endif // wxUSE_UXTHEME
    }

    // succeeded: save the pointer to the page
    m_pages.Insert(pPage, nPage);

    // also ensure that the notebook background is used for its pages by making
    // them transparent: this ensures that MSWGetBgBrush() queries the notebook
    // for the background brush to be used for erasing them
    if ( wxPanel *panel = wxDynamicCast(pPage, wxPanel) )
    {
        panel->MSWSetTransparentBackground();
    }

    // we may need to adjust the size again if the notebook size changed:
    // normally this only happens for the first page we add (the tabs which
    // hadn't been there before are now shown) but for a multiline notebook it
    // can happen for any page at all as a new row could have been started
    if ( m_pages.GetCount() == 1 || HasFlag(wxNB_MULTILINE) )
    {
        AdjustPageSize(pPage);
    }

    // now deal with the selection
    // ---------------------------

    // if the inserted page is before the selected one, we must update the
    // index of the selected page
    if ( int(nPage) <= m_nSelection )
    {
        // one extra page added
        m_nSelection++;
    }

    // some page should be selected: either this one or the first one if there
    // is still no selection
    int selNew = wxNOT_FOUND;
    if ( bSelect )
        selNew = nPage;
    else if ( m_nSelection == wxNOT_FOUND )
        selNew = 0;

    if ( selNew != wxNOT_FOUND )
        SetSelection(selNew);

    InvalidateBestSize();

    return true;
}