notebook.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,435 行 · 第 1/3 页

CPP
1,435
字号
    int flags = 0;
    if ( n == m_sel )
    {
        flags |= wxCONTROL_SELECTED;

        if ( IsFocused() )
            flags |= wxCONTROL_FOCUSED;
    }

    GetRenderer()->DrawTab
                   (
                     dc,
                     rect,
                     GetTabOrientation(),
                     m_titles[n],
                     bmp,
                     flags,
                     m_accels[n]
                   );
}

void wxNotebook::DoDraw(wxControlRenderer *renderer)
{
    //wxRect rectUpdate = GetUpdateClientRect(); -- unused

    wxDC& dc = renderer->GetDC();
    dc.SetFont(GetFont());
    dc.SetTextForeground(GetForegroundColour());

    // redraw the border - it's simpler to always do it instead of checking
    // whether this needs to be done
    GetRenderer()->DrawBorder(dc, wxBORDER_RAISED, GetPagePart());

    // avoid overwriting the spin button
    if ( HasSpinBtn() )
    {
        wxRect rectTabs = GetAllTabsRect();
        wxSize sizeSpinBtn = m_spinbtn->GetSize();

        if ( IsVertical() )
        {
            rectTabs.height -= sizeSpinBtn.y;

            // Allow for erasing the line under selected tab
            rectTabs.width += 2;
        }
        else
        {
            rectTabs.width -= sizeSpinBtn.x;

            // Allow for erasing the line under selected tab
            rectTabs.height += 2;
        }

        dc.SetClippingRegion(rectTabs);
    }

    wxRect rect = GetTabsPart();
    bool isVertical = IsVertical();

    wxRect rectSel;
    for ( size_t n = m_firstVisible; n < m_lastVisible; n++ )
    {
        GetTabSize(n, &rect.width, &rect.height);

        if ( n == m_sel )
        {
            // don't redraw it now as this tab has to be drawn over the other
            // ones as it takes more place and spills over to them
            rectSel = rect;
        }
        else // not selected tab
        {
            // unfortunately we can't do this because the selected tab hangs
            // over its neighbours and so we might need to refresh more tabs -
            // of course, we could still avoid rereshing some of them with more
            // complicated checks, but it doesn't seem too bad to refresh all
            // of them, I still don't see flicker, so leaving as is for now

            //if ( rectUpdate.Intersects(rect) )
            {
                DoDrawTab(dc, rect, n);
            }
            //else: doesn't need to be refreshed
        }

        // move the rect to the next tab
        if ( isVertical )
            rect.y += rect.height;
        else
            rect.x += rect.width;
    }

    // now redraw the selected tab
    if ( rectSel.width )
    {
        DoDrawTab(dc, rectSel, m_sel);
    }

    dc.DestroyClippingRegion();
}

// ----------------------------------------------------------------------------
// wxNotebook geometry
// ----------------------------------------------------------------------------

int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
{
    if ( flags )
        *flags = wxNB_HITTEST_NOWHERE;

    // first check that it is in this window at all
    if ( !GetClientRect().Inside(pt) )
    {
        return -1;
    }

    wxRect rectTabs = GetAllTabsRect();

    switch ( GetTabOrientation() )
    {
        default:
            wxFAIL_MSG(_T("unknown tab orientation"));
            // fall through

        case wxTOP:
            if ( pt.y > rectTabs.GetBottom() )
                return -1;
            break;

        case wxBOTTOM:
            if ( pt.y < rectTabs.y )
                return -1;
            break;

        case wxLEFT:
            if ( pt.x > rectTabs.GetRight() )
                return -1;
            break;

        case wxRIGHT:
            if ( pt.x < rectTabs.x )
                return -1;
            break;
    }

    for ( size_t n = m_firstVisible; n < m_lastVisible; n++ )
    {
        GetTabSize(n, &rectTabs.width, &rectTabs.height);

        if ( rectTabs.Inside(pt) )
        {
            if ( flags )
            {
                // TODO: be more precise
                *flags = wxNB_HITTEST_ONITEM;
            }

            return n;
        }

        // move the rectTabs to the next tab
        if ( IsVertical() )
            rectTabs.y += rectTabs.height;
        else
            rectTabs.x += rectTabs.width;
    }

    return -1;
}

bool wxNotebook::IsVertical() const
{
    wxDirection dir = GetTabOrientation();

    return dir == wxLEFT || dir == wxRIGHT;
}

wxDirection wxNotebook::GetTabOrientation() const
{
    long style = GetWindowStyle();
    if ( style & wxNB_BOTTOM )
        return wxBOTTOM;
    else if ( style & wxNB_RIGHT )
        return wxRIGHT;
    else if ( style & wxNB_LEFT )
        return wxLEFT;

    // wxNB_TOP == 0 so we don't have to test for it
    return wxTOP;
}

wxRect wxNotebook::GetTabRect(int page) const
{
    wxRect rect;
    wxCHECK_MSG( IS_VALID_PAGE(page), rect, _T("invalid notebook page") );

    // calc the size of this tab and of the preceding ones
    wxCoord widthThis, widthBefore;
    if ( FixedSizeTabs() )
    {
        widthThis = m_widthMax;
        widthBefore = page*m_widthMax;
    }
    else
    {
        widthBefore = 0;
        for ( int n = 0; n < page; n++ )
        {
            widthBefore += m_widths[n];
        }

        widthThis = m_widths[page];
    }

    rect = GetTabsPart();
    if ( IsVertical() )
    {
        rect.y += widthBefore - m_offset;
        rect.height = widthThis;
    }
    else // horz
    {
        rect.x += widthBefore - m_offset;
        rect.width = widthThis;
    }

    return rect;
}

wxRect wxNotebook::GetAllTabsRect() const
{
    wxRect rect;

    if ( GetPageCount() )
    {
        const wxSize indent = GetRenderer()->GetTabIndent();
        wxSize size = GetClientSize();

        if ( IsVertical() )
        {
            rect.width = m_heightTab + indent.x;
            rect.x = GetTabOrientation() == wxLEFT ? 0 : size.x - rect.width;
            rect.y = 0;
            rect.height = size.y;
        }
        else // horz
        {
            rect.x = 0;
            rect.width = size.x;
            rect.height = m_heightTab + indent.y;
            rect.y = GetTabOrientation() == wxTOP ? 0 : size.y - rect.height;
        }
    }
    //else: no pages

    return rect;
}

wxRect wxNotebook::GetTabsPart() const
{
    wxRect rect = GetAllTabsRect();

    wxDirection dir = GetTabOrientation();

    const wxSize indent = GetRenderer()->GetTabIndent();
    if ( IsVertical() )
    {
        rect.y += indent.x;
        if ( dir == wxLEFT )
        {
            rect.x += indent.y;
            rect.width -= indent.y;
        }
        else // wxRIGHT
        {
            rect.width -= indent.y;
        }
    }
    else // horz
    {
        rect.x += indent.x;
        if ( dir == wxTOP )
        {
            rect.y += indent.y;
            rect.height -= indent.y;
        }
        else // wxBOTTOM
        {
            rect.height -= indent.y;
        }
    }

    return rect;
}

void wxNotebook::GetTabSize(int page, wxCoord *w, wxCoord *h) const
{
    wxCHECK_RET( w && h, _T("NULL pointer in GetTabSize") );

    if ( IsVertical() )
    {
        // width and height have inverted meaning
        wxCoord *tmp = w;
        w = h;
        h = tmp;
    }

    // height is always fixed
    *h = m_heightTab;

    // width may also be fixed and be the same for all tabs
    *w = GetTabWidth(page);
}

void wxNotebook::SetTabSize(const wxSize& sz)
{
    wxCHECK_RET( FixedSizeTabs(), _T("SetTabSize() ignored") );

    if ( IsVertical() )
    {
        m_heightTab = sz.x;
        m_widthMax = sz.y;
    }
    else // horz
    {
        m_widthMax = sz.x;
        m_heightTab = sz.y;
    }
}

wxSize wxNotebook::CalcTabSize(int page) const
{
    // NB: don't use m_widthMax, m_heightTab or m_widths here because this
    //     method is called to calculate them

    wxSize size;

    wxCHECK_MSG( IS_VALID_PAGE(page), size, _T("invalid notebook page") );

    GetTextExtent(m_titles[page], &size.x, &size.y);

    if ( HasImage(page) )
    {
        wxSize sizeImage;
        m_imageList->GetSize(m_images[page], sizeImage.x, sizeImage.y);

        size.x += sizeImage.x + 5; // FIXME: hard coded margin

        if ( sizeImage.y > size.y )
            size.y = sizeImage.y;
    }

    size.x += 2*m_sizePad.x;
    size.y += 2*m_sizePad.y;

    return size;
}

void wxNotebook::ResizeTab(int page)
{
    wxSize sizeTab = CalcTabSize(page);

    // we only need full relayout if the page size changes
    bool needsRelayout = false;

    if ( IsVertical() )
    {
        // swap coordinates
        wxCoord tmp = sizeTab.x;
        sizeTab.x = sizeTab.y;
        sizeTab.y = tmp;
    }

    if ( sizeTab.y > m_heightTab )
    {
        needsRelayout = true;

        m_heightTab = sizeTab.y;
    }

    m_widths[page] = sizeTab.x;

    if ( sizeTab.x > m_widthMax )
        m_widthMax = sizeTab.x;

    // the total of the tabs has changed too
    UpdateSpinBtn();

    if ( needsRelayout )
        Relayout();
    else
        RefreshAllTabs();
}

void wxNotebook::SetPadding(const wxSize& padding)
{
    if ( padding != m_sizePad )
    {
        m_sizePad = padding;

        Relayout();
    }
}

void wxNotebook::Relayout()
{
    if ( GetPageCount() )
    {
        RefreshAllTabs();

        UpdateSpinBtn();

        if ( m_sel != INVALID_PAGE )
        {
            // resize the currently shown page
            wxRect rectPage = GetPageRect();

            m_pages[m_sel]->SetSize(rectPage);

            // also scroll it into view if needed (note that m_lastVisible
            // was updated by the call to UpdateSpinBtn() above, this is why it
            // is needed here)
            if ( HasSpinBtn() )
            {
                if ( m_sel < m_firstVisible )
                {
                    // selection is to the left of visible part of tabs
                    ScrollTo(m_sel);
                }
                else if ( m_sel > m_lastFullyVisible )
                {
                    // selection is to the right of visible part of tabs
                    ScrollLastTo(m_sel);
                }
            }
        }
    }
    else // we have no pages
    {
        // just refresh everything
        Refresh();
    }
}

wxRect wxNotebook::GetPagePart() const
{
    wxRect rectPage = GetClientRect();

    if ( GetPageCount() )
    {
        wxRect rectTabs = GetAllTabsRect();
        wxDirection dir = GetTabOrientation();
        if ( IsVertical() )
        {
            rectPage.width -= rectTabs.width;
            if ( dir == wxLEFT )
                rectPage.x += rectTabs.width;
        }
        else // horz
        {
            rectPage.height -= rectTabs.height;
            if ( dir == wxTOP )
                rectPage.y += rectTabs.height;
        }
    }
    //else: no pages at all

    return rectPage;
}

wxRect wxNotebook::GetPageRect() const
{
    wxRect rect = GetPagePart();

    // leave space for the border
    wxRect rectBorder = GetRenderer()->GetBorderDimensions(wxBORDER_RAISED);

    // FIXME: hardcoded +2!

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?