notebook.cpp

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

CPP
1,435
字号
    rect.Inflate(-(rectBorder.x + rectBorder.width + 2),
                 -(rectBorder.y + rectBorder.height + 2));

    return rect;
}

wxSize wxNotebook::GetSizeForPage(const wxSize& size) const
{
    wxSize sizeNb = size;
    wxRect rect = GetAllTabsRect();
    if ( IsVertical() )
        sizeNb.x += rect.width;
    else
        sizeNb.y += rect.height;

    return sizeNb;
}

void wxNotebook::SetPageSize(const wxSize& size)
{
    SetClientSize(GetSizeForPage(size));
}

wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
{
    return AdjustSize(GetSizeForPage(sizePage));
}

// ----------------------------------------------------------------------------
// wxNotebook spin button
// ----------------------------------------------------------------------------

bool wxNotebook::HasSpinBtn() const
{
    return m_spinbtn && m_spinbtn->IsShown();
}

void wxNotebook::CalcLastVisibleTab()
{
    bool isVertical = IsVertical();

    wxCoord width = GetClientSize().x;

    wxRect rect = GetTabsPart();

    size_t count = GetPageCount();

    wxCoord widthLast = 0;
    size_t n;
    for ( n = m_firstVisible; n < count; n++ )
    {
        GetTabSize(n, &rect.width, &rect.height);
        if ( rect.GetRight() > width )
        {
            break;
        }

        // remember it to use below
        widthLast = rect.GetRight();

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

    if ( n == m_firstVisible )
    {
        // even the first tab isn't fully visible - but still pretend it is as
        // we have to show something
        m_lastFullyVisible = m_firstVisible;
    }
    else // more than one tab visible
    {
        m_lastFullyVisible = n - 1;

        // but is it really fully visible? it shouldn't overlap with the spin
        // button if it is present (again, even if the first button does
        // overlap with it, we pretend that it doesn't as there is not much
        // else we can do)
        if ( (m_lastFullyVisible > m_firstVisible) && HasSpinBtn() )
        {
            // adjust width to be the width before the spin button
            wxSize sizeSpinBtn = m_spinbtn->GetSize();
            if ( IsVertical() )
                width -= sizeSpinBtn.y;
            else
                width -= sizeSpinBtn.x;

            if ( widthLast > width )
            {
                // the last button overlaps with spin button, so take he
                // previous one
                m_lastFullyVisible--;
            }
        }
    }

    if ( n == count )
    {
        // everything is visible
        m_lastVisible = n;
    }
    else
    {
        // this tab is still (partially) visible, so m_lastVisible is the
        // next tab (remember, this is "exclusive" last)
        m_lastVisible = n + 1;

    }
}

void wxNotebook::UpdateSpinBtn()
{
    // first decide if we need a spin button
    bool allTabsShown;

    size_t count = (size_t)GetPageCount();
    if ( count == 0 )
    {
        // this case is special, get rid of it immediately: everything is
        // visible and we don't need any spin buttons
        allTabsShown = true;

        // have to reset them manually as we don't call CalcLastVisibleTab()
        m_firstVisible =
        m_lastVisible =
        m_lastFullyVisible = 0;
    }
    else
    {
        CalcLastVisibleTab();

        // if all tabs after the first visible one are shown, it doesn't yet
        // mean that all tabs are shown - so we go backwards until we arrive to
        // the beginning (then all tabs are indeed shown) or find a tab such
        // that not all tabs after it are shown
        while ( (m_lastFullyVisible == count - 1) && (m_firstVisible > 0) )
        {
            // this is equivalent to ScrollTo(m_firstVisible - 1) but more
            // efficient
            m_offset -= GetTabWidth(m_firstVisible--);

            // reclaculate after m_firstVisible change
            CalcLastVisibleTab();
        }

        allTabsShown = m_lastFullyVisible == count - 1;
    }

    if ( !allTabsShown )
    {
        if ( !m_spinbtn )
        {
            // create it once only
            m_spinbtn = new wxNotebookSpinBtn(this);

            // set the correct value to keep it in sync
            m_spinbtn->SetValue(m_sel);
        }

        // position it correctly
        PositionSpinBtn();

        // and show it
        m_spinbtn->Show();

        // also set/update the range
        m_spinbtn->SetRange(0, count - 1);

        // update m_lastFullyVisible once again as it might have changed
        // because the spin button appeared
        //
        // FIXME: might do it more efficiently
        CalcLastVisibleTab();
    }
    else // all tabs are visible, we don't need spin button
    {
        if ( m_spinbtn && m_spinbtn -> IsShown() )
        {
            m_spinbtn->Hide();
        }
    }
}

void wxNotebook::PositionSpinBtn()
{
    if ( !m_spinbtn )
        return;

    wxCoord wBtn, hBtn;
    m_spinbtn->GetSize(&wBtn, &hBtn);

    wxRect rectTabs = GetAllTabsRect();

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

        case wxTOP:
            x = rectTabs.GetRight() - wBtn;
            y = rectTabs.GetBottom() - hBtn;
            break;

        case wxBOTTOM:
            x = rectTabs.GetRight() - wBtn;
            y = rectTabs.GetTop();
            break;

        case wxLEFT:
            x = rectTabs.GetRight() - wBtn;
            y = rectTabs.GetBottom() - hBtn;
            break;

        case wxRIGHT:
            x = rectTabs.GetLeft();
            y = rectTabs.GetBottom() - hBtn;
            break;
    }

    m_spinbtn->Move(x, y);
}

// ----------------------------------------------------------------------------
// wxNotebook scrolling
// ----------------------------------------------------------------------------

void wxNotebook::ScrollTo(int page)
{
    wxCHECK_RET( IS_VALID_PAGE(page), _T("invalid notebook page") );

    // set the first visible tab and offset (easy)
    m_firstVisible = (size_t)page;
    m_offset = 0;
    for ( size_t n = 0; n < m_firstVisible; n++ )
    {
        m_offset += GetTabWidth(n);
    }

    // find the last visible tab too
    CalcLastVisibleTab();

    RefreshAllTabs();
}

void wxNotebook::ScrollLastTo(int page)
{
    wxCHECK_RET( IS_VALID_PAGE(page), _T("invalid notebook page") );

    // go backwards until we find the first tab which can be made visible
    // without hiding the given one
    wxSize size = GetClientSize();
    wxCoord widthAll = IsVertical() ? size.y : size.x,
            widthTabs = GetTabWidth(page);

    // the total width is less than the width of the window if we have the spin
    // button
    if ( HasSpinBtn() )
    {
        wxSize sizeSpinBtn = m_spinbtn->GetSize();
        if ( IsVertical() )
            widthAll -= sizeSpinBtn.y;
        else
            widthAll -= sizeSpinBtn.x;
    }

    m_firstVisible = page;
    while ( (m_firstVisible > 0) && (widthTabs <= widthAll) )
    {
        widthTabs += GetTabWidth(--m_firstVisible);
    }

    if ( widthTabs > widthAll )
    {
        // take one step back (that it is forward) if we can
        if ( m_firstVisible < (size_t)GetPageCount() - 1 )
            m_firstVisible++;
    }

    // go to it
    ScrollTo(m_firstVisible);

    // consitency check: the page we were asked to show should be shown
    wxASSERT_MSG( (size_t)page < m_lastVisible, _T("bug in ScrollLastTo") );
}

// ----------------------------------------------------------------------------
// wxNotebook sizing/moving
// ----------------------------------------------------------------------------

wxSize wxNotebook::DoGetBestClientSize() const
{
    // calculate the max page size
    wxSize size;

    size_t count = GetPageCount();
    if ( count )
    {
        for ( size_t n = 0; n < count; n++ )
        {
            wxSize sizePage = m_pages[n]->GetSize();

            if ( size.x < sizePage.x )
                size.x = sizePage.x;
            if ( size.y < sizePage.y )
                size.y = sizePage.y;
        }
    }
    else // no pages
    {
        // use some arbitrary default size
        size.x =
        size.y = 100;
    }

    return GetSizeForPage(size);
}

void wxNotebook::DoMoveWindow(int x, int y, int width, int height)
{
    wxControl::DoMoveWindow(x, y, width, height);

    // move the spin ctrl too (NOP if it doesn't exist)
    PositionSpinBtn();
}

void wxNotebook::DoSetSize(int x, int y,
                           int width, int height,
                           int sizeFlags)
{
    wxSize old_client_size = GetClientSize();

    wxControl::DoSetSize(x, y, width, height, sizeFlags);

    wxSize new_client_size = GetClientSize();

    if (old_client_size != new_client_size)
        Relayout();
}

// ----------------------------------------------------------------------------
// wxNotebook input processing
// ----------------------------------------------------------------------------

bool wxNotebook::PerformAction(const wxControlAction& action,
                               long numArg,
                               const wxString& strArg)
{
    if ( action == wxACTION_NOTEBOOK_NEXT )
        SetSelection(GetNextPage(true));
    else if ( action == wxACTION_NOTEBOOK_PREV )
        SetSelection(GetNextPage(false));
    else if ( action == wxACTION_NOTEBOOK_GOTO )
        SetSelection((int)numArg);
    else
        return wxControl::PerformAction(action, numArg, strArg);

    return true;
}

// ----------------------------------------------------------------------------
// wxStdNotebookInputHandler
// ----------------------------------------------------------------------------

wxStdNotebookInputHandler::wxStdNotebookInputHandler(wxInputHandler *inphand)
                         : wxStdInputHandler(inphand)
{
}

bool wxStdNotebookInputHandler::HandleKey(wxInputConsumer *consumer,
                                          const wxKeyEvent& event,
                                          bool pressed)
{
    // ignore the key releases
    if ( pressed )
    {
        wxNotebook *notebook = wxStaticCast(consumer->GetInputWindow(), wxNotebook);

        int page = 0;
        wxControlAction action;
        switch ( event.GetKeyCode() )
        {
            case WXK_UP:
                if ( notebook->IsVertical() )
                    action = wxACTION_NOTEBOOK_PREV;
                break;

            case WXK_LEFT:
                if ( !notebook->IsVertical() )
                    action = wxACTION_NOTEBOOK_PREV;
                break;

            case WXK_DOWN:
                if ( notebook->IsVertical() )
                    action = wxACTION_NOTEBOOK_NEXT;
                break;

            case WXK_RIGHT:
                if ( !notebook->IsVertical() )
                    action = wxACTION_NOTEBOOK_NEXT;
                break;

            case WXK_HOME:
                action = wxACTION_NOTEBOOK_GOTO;
                // page = 0; -- already has this value
                break;

            case WXK_END:
                action = wxACTION_NOTEBOOK_GOTO;
                page = notebook->GetPageCount() - 1;
                break;
        }

        if ( !action.IsEmpty() )
        {
            return consumer->PerformAction(action, page);
        }
    }

    return wxStdInputHandler::HandleKey(consumer, event, pressed);
}

bool wxStdNotebookInputHandler::HandleMouse(wxInputConsumer *consumer,
                                            const wxMouseEvent& event)
{
    if ( event.ButtonDown(1) )
    {
        wxNotebook *notebook = wxStaticCast(consumer->GetInputWindow(), wxNotebook);
        int page = notebook->HitTest(event.GetPosition());
        if ( page != -1 )
        {
            consumer->PerformAction(wxACTION_NOTEBOOK_GOTO, page);

            return false;
        }
    }

    return wxStdInputHandler::HandleMouse(consumer, event);
}

bool wxStdNotebookInputHandler::HandleMouseMove(wxInputConsumer *consumer,
                                                const wxMouseEvent& event)
{
    return wxStdInputHandler::HandleMouseMove(consumer, event);
}

bool
wxStdNotebookInputHandler::HandleFocus(wxInputConsumer *consumer,
                                       const wxFocusEvent& WXUNUSED(event))
{
    HandleFocusChange(consumer);

    return false;
}

bool wxStdNotebookInputHandler::HandleActivation(wxInputConsumer *consumer,
                                                 bool WXUNUSED(activated))
{
    // we react to the focus change in the same way as to the [de]activation
    HandleFocusChange(consumer);

    return false;
}

void wxStdNotebookInputHandler::HandleFocusChange(wxInputConsumer *consumer)
{
    wxNotebook *notebook = wxStaticCast(consumer->GetInputWindow(), wxNotebook);
    notebook->RefreshCurrent();
}

#endif // wxUSE_NOTEBOOK

⌨️ 快捷键说明

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