More Advanced Drop Target Hit-Testing

In Cosmo, every point in a document window is a valid drop point. However, in a Patron document (the CPages window, to be exact), a page has unusable margins and is also surrounded by a border. We don't want to allow drops to happen in these areas, so CPages::UTestDroppablePoint (DRAGDROP.CPP) handles this more complex hit-testing. It returns a code from the UDROP_* values Patron defines in PAGES.H. The two most important values are UDROP_NONE (can't drop here) and UDROP_CLIENT (drop is allowed). Other values are for scrolling. (See "Scrolling the Page" later in this chapter.) Basically, UTestDroppablePoint returns UDROP_CLIENT if the mouse is within the intersection of the document's client area and the client-relative rectangle of the usable page regions. Otherwise, it returns UDROP_NONE.


UINT CPages::UTestDroppablePoint(LPPOINTL pptl)
{
POINT pt;
RECT rc, rcT, rcC;
UINT uRet;

POINTFROMPOINTL(pt, *pptl);
ScreenToClient(m_hWnd, &pt);

CalcBoundingRect(&rc, FALSE);

GetClientRect(m_hWnd, &rcC);
IntersectRect(&rcT, &rc, &rcC);

//Check for at least a client area hit.
if (!PtInRect(&rcT, pt))
return UDROP_NONE;

uRet=UDROP_CLIENT;

[Code here for scrolling considerations]

return uRet;
}

UTestDroppablePoint is first called from IDropTarget::DragEnter to set the initial effect. It's then called on entry into IDropTarget::DragOver to set the effect as well as to determine whether further checks for feedback and scrolling are necessary. (See the next sections.) Finally, it's called again from IDropTarget::Drop to ensure that our application doesn't attempt to perform a Paste operation on an invalid drop point. (Note that a POINTL structure, like the RECTL and SIZEL structures described in Chapter 12, is made of 32-bit fields.) Other Windows API functions use the POINT type (which varies with the operating system), so the POINTFROMPOINTL macro (INC\INOLE.H) converts a POINTL to a POINT. The same header file also has POINTLFROMPOINT to go the other way.