scrlwing.cpp

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

CPP
1,388
字号
                                          GetScrollRect() );
        }
    }
}

void wxScrollHelper::EnableScrolling (bool x_scroll, bool y_scroll)
{
    m_xScrollingEnabled = x_scroll;
    m_yScrollingEnabled = y_scroll;
}

// Where the current view starts from
void wxScrollHelper::GetViewStart (int *x, int *y) const
{
    if ( x )
        *x = m_xScrollPosition;
    if ( y )
        *y = m_yScrollPosition;
}

#if WXWIN_COMPATIBILITY_2_2

void wxScrollHelper::ViewStart(int *x, int *y) const
{
    GetViewStart( x, y );
}

#endif // WXWIN_COMPATIBILITY_2_2

void wxScrollHelper::DoCalcScrolledPosition(int x, int y, int *xx, int *yy) const
{
    if ( xx )
        *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine;
    if ( yy )
        *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine;
}

void wxScrollHelper::DoCalcUnscrolledPosition(int x, int y, int *xx, int *yy) const
{
    if ( xx )
        *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine;
    if ( yy )
        *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine;
}

// ----------------------------------------------------------------------------
// event handlers
// ----------------------------------------------------------------------------

// Default OnSize resets scrollbars, if any
void wxScrollHelper::HandleOnSize(wxSizeEvent& WXUNUSED(event))
{
    if ( m_targetWindow->GetAutoLayout() )
    {
        wxSize size = m_targetWindow->GetBestVirtualSize();
        
        // This will call ::Layout() and ::AdjustScrollbars()
        m_win->SetVirtualSize( size );
    }
    else
    {
        AdjustScrollbars();
    }
}

// This calls OnDraw, having adjusted the origin according to the current
// scroll position
void wxScrollHelper::HandleOnPaint(wxPaintEvent& WXUNUSED(event))
{
    // don't use m_targetWindow here, this is always called for ourselves
    wxPaintDC dc(m_win);
    DoPrepareDC(dc);

    OnDraw(dc);
}

// kbd handling: notice that we use OnChar() and not OnKeyDown() for
// compatibility here - if we used OnKeyDown(), the programs which process
// arrows themselves in their OnChar() would never get the message and like
// this they always have the priority
void wxScrollHelper::HandleOnChar(wxKeyEvent& event)
{
    int stx, sty,       // view origin
        szx, szy,       // view size (total)
        clix, cliy;     // view size (on screen)

    GetViewStart(&stx, &sty);
    GetTargetSize(&clix, &cliy);
    m_targetWindow->GetVirtualSize(&szx, &szy);

    if( m_xScrollPixelsPerLine )
    {
        clix /= m_xScrollPixelsPerLine;
        szx /= m_xScrollPixelsPerLine;
    }
    else
    {
        clix = 0;
        szx = -1;
    }
    if( m_yScrollPixelsPerLine )
    {
        cliy /= m_yScrollPixelsPerLine;
        szy /= m_yScrollPixelsPerLine;
    }
    else
    {
        cliy = 0;
        szy = -1;
    }

    int xScrollOld = m_xScrollPosition,
        yScrollOld = m_yScrollPosition;

    int dsty;
    switch ( event.GetKeyCode() )
    {
        case WXK_PAGEUP:
        case WXK_PRIOR:
            dsty = sty - (5 * cliy / 6);
            Scroll(-1, (dsty == -1) ? 0 : dsty);
            break;

        case WXK_PAGEDOWN:
        case WXK_NEXT:
            Scroll(-1, sty + (5 * cliy / 6));
            break;

        case WXK_HOME:
            Scroll(0, event.ControlDown() ? 0 : -1);
            break;

        case WXK_END:
            Scroll(szx - clix, event.ControlDown() ? szy - cliy : -1);
            break;

        case WXK_UP:
            Scroll(-1, sty - 1);
            break;

        case WXK_DOWN:
            Scroll(-1, sty + 1);
            break;

        case WXK_LEFT:
            Scroll(stx - 1, -1);
            break;

        case WXK_RIGHT:
            Scroll(stx + 1, -1);
            break;

        default:
            // not for us
            event.Skip();
    }

    if ( m_xScrollPosition != xScrollOld )
    {
        wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_xScrollPosition,
                               wxHORIZONTAL);
        event.SetEventObject(m_win);
        m_win->GetEventHandler()->ProcessEvent(event);
    }

    if ( m_yScrollPosition != yScrollOld )
    {
        wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_yScrollPosition,
                               wxVERTICAL);
        event.SetEventObject(m_win);
        m_win->GetEventHandler()->ProcessEvent(event);
    }
}

// ----------------------------------------------------------------------------
// autoscroll stuff: these functions deal with sending fake scroll events when
// a captured mouse is being held outside the window
// ----------------------------------------------------------------------------

bool wxScrollHelper::SendAutoScrollEvents(wxScrollWinEvent& event) const
{
    // only send the event if the window is scrollable in this direction
    wxWindow *win = (wxWindow *)event.GetEventObject();
    return win->HasScrollbar(event.GetOrientation());
}

void wxScrollHelper::StopAutoScrolling()
{
#if wxUSE_TIMER
    if ( m_timerAutoScroll )
    {
        delete m_timerAutoScroll;
        m_timerAutoScroll = (wxTimer *)NULL;
    }
#endif
}

void wxScrollHelper::HandleOnMouseEnter(wxMouseEvent& event)
{
    StopAutoScrolling();

    event.Skip();
}

void wxScrollHelper::HandleOnMouseLeave(wxMouseEvent& event)
{
    // don't prevent the usual processing of the event from taking place
    event.Skip();

    // when a captured mouse leave a scrolled window we start generate
    // scrolling events to allow, for example, extending selection beyond the
    // visible area in some controls
    if ( wxWindow::GetCapture() == m_targetWindow )
    {
        // where is the mouse leaving?
        int pos, orient;
        wxPoint pt = event.GetPosition();
        if ( pt.x < 0 )
        {
            orient = wxHORIZONTAL;
            pos = 0;
        }
        else if ( pt.y < 0 )
        {
            orient = wxVERTICAL;
            pos = 0;
        }
        else // we're lower or to the right of the window
        {
            wxSize size = m_targetWindow->GetClientSize();
            if ( pt.x > size.x )
            {
                orient = wxHORIZONTAL;
                pos = m_xScrollLines;
            }
            else if ( pt.y > size.y )
            {
                orient = wxVERTICAL;
                pos = m_yScrollLines;
            }
            else // this should be impossible
            {
                // but seems to happen sometimes under wxMSW - maybe it's a bug
                // there but for now just ignore it

                //wxFAIL_MSG( _T("can't understand where has mouse gone") );

                return;
            }
        }

        // only start the auto scroll timer if the window can be scrolled in
        // this direction
        if ( !m_targetWindow->HasScrollbar(orient) )
            return;

#if wxUSE_TIMER
        delete m_timerAutoScroll;
        m_timerAutoScroll = new wxAutoScrollTimer
                                (
                                    m_targetWindow, this,
                                    pos == 0 ? wxEVT_SCROLLWIN_LINEUP
                                             : wxEVT_SCROLLWIN_LINEDOWN,
                                    pos,
                                    orient
                                );
        m_timerAutoScroll->Start(50); // FIXME: make configurable
#else
        wxUnusedVar(pos);
#endif
    }
}

#if wxUSE_MOUSEWHEEL

void wxScrollHelper::HandleOnMouseWheel(wxMouseEvent& event)
{
    m_wheelRotation += event.GetWheelRotation();
    int lines = m_wheelRotation / event.GetWheelDelta();
    m_wheelRotation -= lines * event.GetWheelDelta();

    if (lines != 0)
    {

        wxScrollWinEvent newEvent;

        newEvent.SetPosition(0);
        newEvent.SetOrientation(wxVERTICAL);
        newEvent.SetEventObject(m_win);

        if (event.IsPageScroll())
        {
            if (lines > 0)
                newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEUP);
            else
                newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN);

            m_win->GetEventHandler()->ProcessEvent(newEvent);
        }
        else
        {
            lines *= event.GetLinesPerAction();
            if (lines > 0)
                newEvent.SetEventType(wxEVT_SCROLLWIN_LINEUP);
            else
                newEvent.SetEventType(wxEVT_SCROLLWIN_LINEDOWN);

            int times = abs(lines);
            for (; times > 0; times--)
                m_win->GetEventHandler()->ProcessEvent(newEvent);
        }
    }
}

#endif // wxUSE_MOUSEWHEEL

// ----------------------------------------------------------------------------
// wxGenericScrolledWindow implementation
// ----------------------------------------------------------------------------

IMPLEMENT_DYNAMIC_CLASS(wxGenericScrolledWindow, wxPanel)

BEGIN_EVENT_TABLE(wxGenericScrolledWindow, wxPanel)
    EVT_PAINT(wxGenericScrolledWindow::OnPaint)
END_EVENT_TABLE()

bool wxGenericScrolledWindow::Create(wxWindow *parent,
                              wxWindowID id,
                              const wxPoint& pos,
                              const wxSize& size,
                              long style,
                              const wxString& name)
{
    m_targetWindow = this;
#ifdef __WXMAC__
    MacSetClipChildren( true ) ;
#endif

    bool ok = wxPanel::Create(parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);

    return ok;
}

wxGenericScrolledWindow::~wxGenericScrolledWindow()
{
}

bool wxGenericScrolledWindow::Layout()
{
    if (GetSizer() && m_targetWindow == this)
    {
        // If we're the scroll target, take into account the
        // virtual size and scrolled position of the window.

        int x, y, w, h;
        CalcScrolledPosition(0,0, &x,&y);
        GetVirtualSize(&w, &h);
        GetSizer()->SetDimension(x, y, w, h);
        return true;
    }

    // fall back to default for LayoutConstraints
    return wxPanel::Layout();
}

void wxGenericScrolledWindow::DoSetVirtualSize(int x, int y)
{
    wxPanel::DoSetVirtualSize( x, y );
    AdjustScrollbars();

    if (GetAutoLayout())
        Layout();
}

// wxWindow's GetBestVirtualSize returns the actual window size,
// whereas we want to return the virtual size
wxSize wxGenericScrolledWindow::GetBestVirtualSize() const
{
    wxSize  clientSize( GetClientSize() );
    if (GetSizer())
    {
        wxSize minSize( GetSizer()->CalcMin() );

        return wxSize( wxMax( clientSize.x, minSize.x ), wxMax( clientSize.y, minSize.y ) );
    }
    else
        return clientSize;
}

// return the size best suited for the current window
// (this isn't a virtual size, this is a sensible size for the window)
wxSize wxGenericScrolledWindow::DoGetBestSize() const
{
    wxSize best;

    if ( GetSizer() )
    {
        wxSize b = GetSizer()->GetMinSize();

        // Only use the content to set the window size in the direction
        // where there's no scrolling; otherwise we're going to get a huge
        // window in the direction in which scrolling is enabled
        int ppuX, ppuY;
        GetScrollPixelsPerUnit(& ppuX, & ppuY);

        wxSize minSize;
        if ( GetMinSize().IsFullySpecified() )
            minSize = GetMinSize();
        else
            minSize = GetSize();

        if (ppuX > 0)
            b.x = minSize.x;
        if (ppuY > 0)
            b.y = minSize.y;
        best = b;
    }
    else
        return wxWindow::DoGetBestSize();

    // Add any difference between size and client size
    wxSize diff = GetSize() - GetClientSize();
    best.x += wxMax(0, diff.x);
    best.y += wxMax(0, diff.y);

    return best;
}

void wxGenericScrolledWindow::OnPaint(wxPaintEvent& event)
{
    // the user code didn't really draw the window if we got here, so set this
    // flag to try to call OnDraw() later
    m_handler->ResetDrawnFlag();

    event.Skip();
}

#ifdef __WXMSW__
WXLRESULT
wxGenericScrolledWindow::MSWWindowProc(WXUINT nMsg,
                                       WXWPARAM wParam,
                                       WXLPARAM lParam)
{
    WXLRESULT rc = wxPanel::MSWWindowProc(nMsg, wParam, lParam);

#ifndef __WXWINCE__
    // we need to process arrows ourselves for scrolling
    if ( nMsg == WM_GETDLGCODE )
    {
        rc |= DLGC_WANTARROWS;
    }
#endif

    return rc;
}

#endif // __WXMSW__

#endif // !wxGTK

// vi:sts=4:sw=4:et

⌨️ 快捷键说明

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