window.cpp

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

CPP
2,123
字号
    }

    return style;
}

// Setup background and foreground colours correctly
void wxWindowMSW::SetupColours()
{
    if ( GetParent() )
        SetBackgroundColour(GetParent()->GetBackgroundColour());
}

bool wxWindowMSW::IsMouseInWindow() const
{
    // get the mouse position
    POINT pt;
#ifdef __WXWINCE__
    ::GetCursorPosWinCE(&pt);
#else
    ::GetCursorPos(&pt);
#endif

    // find the window which currently has the cursor and go up the window
    // chain until we find this window - or exhaust it
    HWND hwnd = ::WindowFromPoint(pt);
    while ( hwnd && (hwnd != GetHwnd()) )
        hwnd = ::GetParent(hwnd);

    return hwnd != NULL;
}

void wxWindowMSW::OnInternalIdle()
{
#ifndef HAVE_TRACKMOUSEEVENT
    // Check if we need to send a LEAVE event
    if ( m_mouseInWindow )
    {
        // note that we should generate the leave event whether the window has
        // or doesn't have mouse capture
        if ( !IsMouseInWindow() )
        {
            GenerateMouseLeave();
        }
    }
#endif // !HAVE_TRACKMOUSEEVENT

    if (wxUpdateUIEvent::CanUpdate(this))
        UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
}

// Set this window to be the child of 'parent'.
bool wxWindowMSW::Reparent(wxWindowBase *parent)
{
    if ( !wxWindowBase::Reparent(parent) )
        return false;

    HWND hWndChild = GetHwnd();
    HWND hWndParent = GetParent() ? GetWinHwnd(GetParent()) : (HWND)0;

    ::SetParent(hWndChild, hWndParent);

#ifndef __WXWINCE__
    if ( ::GetWindowLong(hWndChild, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
    {
        EnsureParentHasControlParentStyle(GetParent());
    }
#endif // !__WXWINCE__

    return true;
}

static inline void SendSetRedraw(HWND hwnd, bool on)
{
#ifndef __WXMICROWIN__
    ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0);
#endif
}

void wxWindowMSW::Freeze()
{
    if ( !m_frozenness++ )
    {
        if ( IsShown() )
            SendSetRedraw(GetHwnd(), false);
    }
}

void wxWindowMSW::Thaw()
{
    wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") );

    if ( !--m_frozenness )
    {
        if ( IsShown() )
        {
            SendSetRedraw(GetHwnd(), true);

            // we need to refresh everything or otherwise the invalidated area
            // is not going to be repainted
            Refresh();
        }
    }
}

void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
{
    HWND hWnd = GetHwnd();
    if ( hWnd )
    {
        RECT mswRect;
        const RECT *pRect;
        if ( rect )
        {
            mswRect.left = rect->x;
            mswRect.top = rect->y;
            mswRect.right = rect->x + rect->width;
            mswRect.bottom = rect->y + rect->height;

            pRect = &mswRect;
        }
        else
        {
            pRect = NULL;
        }

        // RedrawWindow not available on SmartPhone or eVC++ 3
#if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
        UINT flags = RDW_INVALIDATE | RDW_ALLCHILDREN;
        if ( eraseBack )
            flags |= RDW_ERASE;

        ::RedrawWindow(hWnd, pRect, NULL, flags);
#else
        ::InvalidateRect(hWnd, pRect, eraseBack);
#endif
    }
}

void wxWindowMSW::Update()
{
    if ( !::UpdateWindow(GetHwnd()) )
    {
        wxLogLastError(_T("UpdateWindow"));
    }

#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
    // just calling UpdateWindow() is not enough, what we did in our WM_PAINT
    // handler needs to be really drawn right now
    (void)::GdiFlush();
#endif // __WIN32__
}

// ---------------------------------------------------------------------------
// drag and drop
// ---------------------------------------------------------------------------


#if wxUSE_DRAG_AND_DROP
void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget)
{
    if ( m_dropTarget != 0 ) {
        m_dropTarget->Revoke(m_hWnd);
        delete m_dropTarget;
    }

    m_dropTarget = pDropTarget;
    if ( m_dropTarget != 0 )
        m_dropTarget->Register(m_hWnd);
}
#endif // wxUSE_DRAG_AND_DROP

// old style file-manager drag&drop support: we retain the old-style
// DragAcceptFiles in parallel with SetDropTarget.
void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept))
{
#ifndef __WXWINCE__
    HWND hWnd = GetHwnd();
    if ( hWnd )
        ::DragAcceptFiles(hWnd, (BOOL)accept);
#endif
}

// ----------------------------------------------------------------------------
// tooltips
// ----------------------------------------------------------------------------

#if wxUSE_TOOLTIPS

void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip)
{
    wxWindowBase::DoSetToolTip(tooltip);

    if ( m_tooltip )
        m_tooltip->SetWindow((wxWindow *)this);
}

#endif // wxUSE_TOOLTIPS

// ---------------------------------------------------------------------------
// moving and resizing
// ---------------------------------------------------------------------------

bool wxWindowMSW::IsSizeDeferred() const
{
#if USE_DEFERRED_SIZING
    if ( m_pendingPosition != wxDefaultPosition ||
         m_pendingSize     != wxDefaultSize )
        return true;
#endif // USE_DEFERRED_SIZING

    return false;
}

// Get total size
void wxWindowMSW::DoGetSize(int *x, int *y) const
{
    // if SetSize() had been called at wx level but not realized at Windows
    // level yet (i.e. EndDeferWindowPos() not called), we still should return
    // the new and not the old position to the other wx code
    if ( m_pendingSize != wxDefaultSize )
    {
        if ( x )
            *x = m_pendingSize.x;
        if ( y )
            *y = m_pendingSize.y;
    }
    else // use current size
    {
        RECT rect = wxGetWindowRect(GetHwnd());

        if ( x )
            *x = rect.right - rect.left;
        if ( y )
            *y = rect.bottom - rect.top;
    }
}

// Get size *available for subwindows* i.e. excluding menu bar etc.
void wxWindowMSW::DoGetClientSize(int *x, int *y) const
{
#if USE_DEFERRED_SIZING
    if ( IsTopLevel() || m_pendingSize == wxDefaultSize )
#endif
    {
        // top level windows resizing is never deferred, so we can safely use
        // the current size here
        RECT rect = wxGetClientRect(GetHwnd());

        if ( x )
            *x = rect.right;
        if ( y )
            *y = rect.bottom;
    }
#if USE_DEFERRED_SIZING
    else // non top level and using deferred sizing
    {
        // we need to calculate the *pending* client size here
        RECT rect;
        rect.left = m_pendingPosition.x;
        rect.top = m_pendingPosition.y;
        rect.right = rect.left + m_pendingSize.x;
        rect.bottom = rect.top + m_pendingSize.y;

        ::SendMessage(GetHwnd(), WM_NCCALCSIZE, FALSE, (LPARAM)&rect);

        if ( x )
            *x = rect.right - rect.left;
        if ( y )
            *y = rect.bottom - rect.top;
    }
#endif
}

void wxWindowMSW::DoGetPosition(int *x, int *y) const
{
    wxWindow * const parent = GetParent();

    wxPoint pos;
    if ( m_pendingPosition != wxDefaultPosition )
    {
        pos = m_pendingPosition;
    }
    else // use current position
    {
        RECT rect = wxGetWindowRect(GetHwnd());

        POINT point;
        point.x = rect.left;
        point.y = rect.top;

        // we do the adjustments with respect to the parent only for the "real"
        // children, not for the dialogs/frames
        if ( !IsTopLevel() )
        {
            // Since we now have the absolute screen coords, if there's a
            // parent we must subtract its top left corner
            if ( parent )
            {
                ::ScreenToClient(GetHwndOf(parent), &point);
            }
        }

        pos.x = point.x;
        pos.y = point.y;
    }

    // we also must adjust by the client area offset: a control which is just
    // under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx
    if ( parent && !IsTopLevel() )
    {
        const wxPoint pt(parent->GetClientAreaOrigin());
        pos.x -= pt.x;
        pos.y -= pt.y;
    }

    if ( x )
        *x = pos.x;
    if ( y )
        *y = pos.y;
}

void wxWindowMSW::DoScreenToClient(int *x, int *y) const
{
    POINT pt;
    if ( x )
        pt.x = *x;
    if ( y )
        pt.y = *y;

    ::ScreenToClient(GetHwnd(), &pt);

    if ( x )
        *x = pt.x;
    if ( y )
        *y = pt.y;
}

void wxWindowMSW::DoClientToScreen(int *x, int *y) const
{
    POINT pt;
    if ( x )
        pt.x = *x;
    if ( y )
        pt.y = *y;

    ::ClientToScreen(GetHwnd(), &pt);

    if ( x )
        *x = pt.x;
    if ( y )
        *y = pt.y;
}

bool
wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
{
#if USE_DEFERRED_SIZING
    // if our parent had prepared a defer window handle for us, use it (unless
    // we are a top level window)
    wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();

    HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL;
    if ( hdwp )
    {
        hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height,
                                SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
        if ( !hdwp )
        {
            wxLogLastError(_T("DeferWindowPos"));
        }
	}

    if ( parent )
    {
        // hdwp must be updated as it may have been changed
        parent->m_hDWP = (WXHANDLE)hdwp;
    }

    if ( hdwp )
    {
        // did deferred move, remember new coordinates of the window as they're
        // different from what Windows would return for it
        return true;
    }

    // otherwise (or if deferring failed) move the window in place immediately
#endif // USE_DEFERRED_SIZING
    if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) )
    {
        wxLogLastError(wxT("MoveWindow"));
    }

    // if USE_DEFERRED_SIZING, indicates that we didn't use deferred move,
    // ignored otherwise
    return false;
}

void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
{
    // TODO: is this consistent with other platforms?
    // Still, negative width or height shouldn't be allowed
    if (width < 0)
        width = 0;
    if (height < 0)
        height = 0;

    if ( DoMoveSibling(m_hWnd, x, y, width, height) )
    {
#if USE_DEFERRED_SIZING
        m_pendingPosition = wxPoint(x, y);
        m_pendingSize = wxSize(width, height);
#endif // USE_DEFERRED_SIZING
    }
}

// set the size of the window: if the dimensions are positive, just use them,
// but if any of them is equal to -1, it means that we must find the value for
// it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
// which case -1 is a valid value for x and y)
//
// If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
// the width/height to best suit our contents, otherwise we reuse the current
// width/height
void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
{

⌨️ 快捷键说明

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