⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dragdrp.cpp

📁 Windows CE 6.0 Word Application 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
 *	Purpose:
 *		allows the data transfer engine to cache important information
 *		about a drag drop with this drop target.
 *
 *	Arguments:
 *		publdr		-- the undo builder for the operation.  With this
 *					   intra-instance drag drop operations can be treated
 *					   as a single user action
 *		cpMin		-- the minimim character position of the range that is
 *					   being dragged.  With this and cpMost, we can disable
 *					   dragging into the range that is being dragged!
 *		cpMost		-- the max character position
 *
 *	Notes:
 *		this method must be called again in order to clear the cached info
 *
 *		-1 for cpMin and cpMost will "clear" those values (as 0 is a valid cp)
 */

void CDropTarget::SetDragInfo( IUndoBuilder *publdr, LONG cpMin, LONG cpMost )
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::SetDragInfo");

	_publdr = publdr;
	_cpMin 	= cpMin;
	_cpMost	= cpMost;
}

/*
 *	CDropTarget::Zombie
 *
 *	@mfunc	This method clears the state in this drop target object.  It is
 *			used to recover 'gracefully' from reference counting errors
 */
void CDropTarget::Zombie()
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::Zombie");

	_ped = NULL;
	if( _pcallmgr )
	{
		delete _pcallmgr;
		_pcallmgr = NULL;
	}
}

//
//	CDropTarget PRIVATE methods
//

/*
 *	CDropTarget::~CDropTarget
 */
CDropTarget::~CDropTarget()
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::~CDropTarget");

	;
}

/*
 *	CDropTarget::ConvertScreenPtToClientPt (pptScreen, pptClient)
 *
 *	Purpose:
 *		OLE drag drop sends points in using screen coordinates.  However,
 *		all of our display code internally relies on client coordinates
 *		(i.e. the coordinates relative to the window that we are being
 *		drawn in).  This routine will convert between the two
 *
 *	Notes:
 *		the client coordinates use a POINT structure instead of POINTL.
 *		while nominally they are the same, OLE uses POINTL and the display
 *		engine uses POINT. 
 *
 */

void CDropTarget::ConvertScreenPtToClientPt( POINTL *pptScreen, 
	POINT *pptClient )
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::ConvertScreenPtToClientPt");

	POINT ptS;

	pptClient->x = ptS.x = pptScreen->x;
	pptClient->y = ptS.y = pptScreen->y;

	_ped->TxScreenToClient(pptClient);

	return;
}

/*
 *	CDropTarget::UpdateEffect (grfKeyState, pt, pdwEffect)
 *
 *	Purpose:
 *		given the keyboard state and point, and knowledge of what
 *		the data object being transferred can offer, calculate
 *		the correct drag drop feedback.
 *
 *	Requires:
 *		this function should only be called during a drag drop 
 *		operation; doing otherwise will simply result in a return
 *		of DROPEFFECT_NONE.
 *
 */

void CDropTarget::UpdateEffect( DWORD grfKeyState, POINTL ptl, 
		DWORD *pdwEffect)
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::UpdateEffect");

	POINT pt;
	BOOL fHot;
	WORD nScrollInset;
	HRESULT hr;
	LPRICHEDITOLECALLBACK const precall = _ped->GetRECallback();

	pt.x = ptl.x;
	pt.y = ptl.y;

	// first, find out where we are
	ConvertScreenPtToClientPt(&ptl, &pt);

	_cpCur = _ped->_pdp->CpFromPoint(pt, NULL, NULL, NULL, FALSE);

	// if we are on top of the range that is being
	// dragged, then remeber it for later
	_dwFlags &= ~DF_OVERSOURCE;
	if( _cpCur > _cpMin && _cpCur < _cpMost )
	{
		_dwFlags |= DF_OVERSOURCE;
	}

	// Scroll if we need to and remember if we are in the hot zone.
	nScrollInset = sysparam.GetScrollInset();

	if (_pdrgcrt != NULL)
	{
		_pdrgcrt->HideCaret();
	}

	fHot = _ped->_pdp->AutoScroll(pt, nScrollInset, nScrollInset);

	if (_pdrgcrt != NULL)
	{
		if (((_dwFlags & DF_OVERSOURCE) == 0) && !fHot)
		{
			_pdrgcrt->ShowCaret();
		}
		else
		{
			// The hide above restored the caret so we just
			// need to turn off the caret while we are over the
			// source.
			_pdrgcrt->CancelRestoreCaretArea();
		}
	}

	// Let the client set the effect if it wants, but first, we need
	// to check for protection.

	if( _ped->IsRich() )
	{
		// we don't allow dropping onto protected text.  Note that
		// the _edges_ of a protected range may be dragged to; therefore,
		// we need to check for protection at _cpCur and _cpCur-1.
		// If both cp's are protected, then we are inside a protected
		// range.
		CTxtRange rg(_ped, _cpCur, 0);
		LONG iProt;

		if( (iProt = rg.IsProtected(1)) == CTxtRange::PROTECTED_YES || 
			iProt == CTxtRange::PROTECTED_ASK )
		{
		  	rg.Advance(-1);

			// if we're at the BOD or if the CF of the preceding cp
			// is PROTECTED
			if(!_cpCur || 
				(iProt = rg.IsProtected(-1)) == CTxtRange::PROTECTED_YES ||
				iProt == CTxtRange::PROTECTED_ASK)
			{
				// give the caller a chance to do something if the
				// ENM_PROTECTED mask is set.
				if( iProt == CTxtRange::PROTECTED_YES || 
					!_ped->IsProtectionCheckingEnabled() || 
					_ped->QueryUseProtection(&rg, WM_MOUSEMOVE,0, 0) )
				{ 
					*pdwEffect = DROPEFFECT_NONE;
					goto Exit;
				}
			}
		}
	}

	if( precall )
	{
		hr = precall->GetDragDropEffect(FALSE, grfKeyState, pdwEffect);
		// Note : RichEdit 1.0 does not check the return code of this call.
		// If callback specified a single effect, use it.
		// Otherwise pick one ourselves.

		// trick: (x & (x-1)) is non-zero if more than one bit is set.
		if (!(*pdwEffect & (*pdwEffect - 1) ))
		{
			goto Exit;
		}
	}
	
	// If we don't know anything about the data object or the control
	// is read-only, set the effect to none.
	// If the client is handling this, we don't worry about read-only.
	if (!(_dwFlags & DF_CLIENTCONTROL) &&
		 ( !(_dwFlags & DF_CANDROP) || _ped->TxGetReadOnly()))
	{
		*pdwEffect = DROPEFFECT_NONE;
		_cpCur = -1;
		// no need to do anything else
		return;
	}

	// if we are on top of the range that is being
	// dragged, then we can't drop there!
	if( _dwFlags & DF_OVERSOURCE )
	{
		*pdwEffect = DROPEFFECT_NONE;
		goto Exit;
	}


	// now check the keyboard state and the requested drop effects.

	if( (_dwFlags & DF_CANDROP) )
	{
		// if we can paste plain text, then see if a MOVE or COPY
		// operation was requested and set the right effect.  Note
		// that we prefer MOVEs over COPY's in accordance with OLE
		// UI guidelines.

		// we do not yet support linking
		if( (grfKeyState & MK_CONTROL) && (grfKeyState & MK_SHIFT) )
		{
			//COMPATIBILITY: Richedit 1.0 did not appear to support drag
			//linking correctly.
			*pdwEffect = DROPEFFECT_NONE;
		}
		else if( !(grfKeyState & MK_CONTROL) && 
			(*pdwEffect & DROPEFFECT_MOVE) )
		{
			// if the control key is *not* depressed, then assume a "move"
			// operation (note that shift and alt or no keys will also give
			// a move) iff the source supports move.

			*pdwEffect = DROPEFFECT_MOVE;
		}
		else if( (grfKeyState & MK_CONTROL) && !((grfKeyState & MK_ALT) &&
			(grfKeyState & MK_SHIFT)) && (*pdwEffect & DROPEFFECT_COPY) )
		{
			// if only the control key is down and we're allowed to do a copy,
			// then do a copy
			*pdwEffect = DROPEFFECT_COPY;
		}
		else if( !(grfKeyState & MK_CONTROL) && 
			(*pdwEffect & DROPEFFECT_COPY) )
		{
			// if the control key is *not* depressed, and we are *not* allowed
			// to do a move (note that this if comes below the second one), then
			// do a COPY operation (if available)
			*pdwEffect = DROPEFFECT_COPY;
		}
		else
		{
			// not a combination that we support
			*pdwEffect = DROPEFFECT_NONE;
		}
	}
	else
	{
		*pdwEffect = DROPEFFECT_NONE;
	}

Exit:	

	//Add the scrolling effect if we are in the hot zone.
	if (fHot)
	{
		*pdwEffect |= DROPEFFECT_SCROLL;
	}
}

/*
 *	CDropTarget::DrawFeedback
 *
 *	Purpose:
 *		draws any feeback necessary on the target side (specifically, setting the
 *		cursor
 *
 *	Notes:
 *		assumes _cpCur is correctly set.
 */

void CDropTarget::DrawFeedback(void)
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::DrawFeedback");

	if (_pdrgcrt != NULL)
	{
		// We need to indicate a drop location because a drop is possible
		_pdrgcrt->DrawCaret(_cpCur);
	}
}

/*
 *	CDropTarget::HandleRightMouseDrop
 *
 *	@mfunc	Handles calling back to the client to get a context menu 
 *			for a right-mouse drag drop.
 *
 *	@rdesc	HRESULT
 */
HRESULT CDropTarget::HandleRightMouseDrop(
	IDataObject *pdo,		//@parm the data object to drop
	POINTL ptl)				//@parm the location of the drop (screen coords)
{
	LPRICHEDITOLECALLBACK precall = NULL;
	CHARRANGE cr = {_cpCur, _cpCur};
	HMENU hmenu = NULL;
	HWND hwnd, hwndParent;

	precall = _ped->GetRECallback();

	if( !precall )
	{
		return S_FALSE;
	}

	// Dangerous pointer casting going on here.
	precall->GetContextMenu( GCM_RIGHTMOUSEDROP, (IOleObject *)(void *)pdo, 
			&cr, &hmenu);

	if( hmenu && _ped->TxGetWindow(&hwnd) == NOERROR )
	{
		hwndParent = GetParent(hwnd);
		if( !hwndParent )
		{
			hwndParent = hwnd;
		}

		TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, 
			ptl.x, ptl.y, 0, hwndParent, NULL);

		return NOERROR;
	}
	
	return S_FALSE;
}

/*
 *	CDropCaret::DrawCaret
 *
 *	Purpose:
 *		Draws a "caret" to indicate where the drop will occur.
 *
 */

CDropCaret::CDropCaret(
	CTxtEdit *ped)			//@parm Edit control
		: _ped(ped), _yHeight(-1), _hdcWindow(NULL)
{
	// Header does all the work
}

/*
 *	CDropCaret::~CDropCaret
 *
 *	Purpose:
 *		Clean up caret object
 *
 */

CDropCaret::~CDropCaret()
{
	if (_hdcWindow != NULL)
	{
		// Restore the any updated window area
		HideCaret();

		// Free the DC we held on to
		_ped->_pdp->ReleaseDC(_hdcWindow);
	}
}

/*
 *	CDropCaret::Init
 *
 *	Purpose:
 *		Do initialization that can fail
 *
 */

BOOL CDropCaret::Init()
{
	// Get the DC for the window
	_hdcWindow = _ped->_pdp->GetDC();

	if (NULL == _hdcWindow)
	{
		// Could not get a DC, we are toast.
		AssertSz(FALSE, "CDropCaret::Init could not get hdc"); 
		return FALSE;
	}

	// Keep pixels per inch since we will need it
	_yPixelsPerInch = GetDeviceCaps(_hdcWindow, LOGPIXELSY);

	// Set the default maximum size
	_yHeightMax = DEFAULT_DROPCARET_MAXHEIGHT;

	// Preallocate a bitmap for saving screen
	return (_osdc.Init(
		_hdcWindow,
		WIDTH_DROPCARET,
		DEFAULT_DROPCARET_MAXHEIGHT,
		CLR_INVALID) != NULL);
}


/*
 *	CDropCaret::DrawCaret
 *
 *	Purpose:
 *		Draws a "caret" to indicate where the drop will occur.
 *
 */

void CDropCaret::DrawCaret(
	LONG cpCur)				//@parm current cp of where drop would occur
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropCaret::DrawCaret");

	CRchTxtPtr tp(_ped, cpCur);
	POINT ptNew;
	RECT rcClient;
	CDisplay *pdp = _ped->_pdp;
	CLinePtr rp(pdp);

	//	Restore the old caret position bits and save the new caret
	//	position bits.
	HideCaret();

	// We no longer have a caret to restore
	_yHeight = -1;

	// Get the new cp from the point
	pdp->PointFromTp(tp, NULL, FALSE, ptNew, &rp, TA_TOP);

	// Get the client rectangle
	_ped->TxGetClientRect(&rcClient);
	
	// Figure out the height of the new caret

	// Get the charformat
	const CCharFormat *pcf = tp.GetCF();

	// Get the zoomed height
	CCcs *pccs = fc().GetCcs(_hdcWindow, pcf, pdp->GetZoomNumerator(),
		pdp->GetZoomDenominator(), _yPixelsPerInch);

	if (NULL == pccs)
	{
		// We can't do anything sensible so give up.
		return;
	}

	// Convert the height in the charformat to height on the screen
	LONG yHeight = pdp->LXtoDX(pcf->yHeight);
	
	// Save the new position
	ptNew.y += (rp->_yHeight - rp->_yDescent 
		+ pccs->_yDescent - yHeight - pccs->_yOffset);

	// Release the cache entry since we are done with it.
	pccs->Release();

	// Check if new point is in the client rectangle
	if (!PtInRect(&rcClient, ptNew))
	{
		return;
	}

	// Save the new height
	_yHeight = yHeight;

	// Save the new caret position
	_ptCaret.x = ptNew.x;
	_ptCaret.y = ptNew.y;

	// Is current bit map big enough to hold the bit map we want to put in?
	if (yHeight > _yHeightMax)
	{
		// No - reallocate the bitmap.
		if (!_osdc.Realloc(WIDTH_DROPCARET, yHeight))
		{
			// Reallocation failed - no visual feedback for now
			AssertSz(FALSE, 
				"CDropCaret::DrawCaret bitmap reallocation failed");
			return;
		}

		_yHeightMax = yHeight;
	}

	// Save the bits at the new position for the caret
	_osdc.Get(_hdcWindow, _ptCaret.x, _ptCaret.y, WIDTH_DROPCARET, yHeight);

	// Actually put the caret on the screen
	ShowCaret();
}


/*
 *	CDropCaret::ShowCaret
 *
 *	Purpose:
 *		Actually draw caret on the screen
 *
 */

void CDropCaret::ShowCaret()
{
#ifdef DEBUG						  	
	BOOL fSuccess;
#endif // DEBUG

	// Don't show the caret if the height says that there is no caret to show.
	if (-1 == _yHeight)
	{
		return;
	}

	// Create a pen
	HPEN hPenCaret = CreatePen(PS_SOLID, WIDTH_DROPCARET, 0);

	if (NULL == hPenCaret)
	{
		// Call failed, this isn't really catastrophic so just don't
		// draw the caret.
		AssertSz(FALSE, "CDropCaret::DrawCaret could not create pen");
		return;
	}

	// Put the dotted pen in the DC
	HPEN hPenOld = (HPEN) SelectObject(_hdcWindow, hPenCaret);
														   
	if (NULL == hPenOld)
	{
		// Call failed, this isn't really catastrophic so just don't
		// draw the caret.
		AssertSz(FALSE, "CDropCaret::DrawCaret SelectObject failed");
		goto DeleteObject;
	}

	// Move the drawing pen to where to draw the caret
#ifdef DEBUG
	fSuccess =
#endif // DEBUG

	MoveToEx(_hdcWindow, _ptCaret.x, _ptCaret.y, NULL);

	AssertSz(fSuccess, "CDropCaret::DrawCaret MoveToEx failed");

	// Draw the line
#ifdef DEBUG
	fSuccess =
#endif // DEBUG

	LineTo(_hdcWindow, _ptCaret.x, _ptCaret.y + _yHeight);

	AssertSz(fSuccess, "CDropCaret::DrawCaret LineTo failed");

	// Restore the current pen
#ifdef DEBUG
	hPenCaret = (HPEN)
#endif // DEBUG

	SelectObject(_hdcWindow, hPenOld);

	AssertSz(hPenCaret != NULL, 
		"CDropCaret::DrawCaret Restore Original Pen failed");

DeleteObject:

	// Dump the pen
#ifdef DEBUG
	fSuccess =
#endif // DEBUG

	DeleteObject(hPenCaret);

	AssertSz(fSuccess, 
		"CDropCaret::DrawCaret Could not delete dotted Pen");
}

/*
 *	CDropCaret::HideCaret
 *
 *	Purpose:
 *		Restore caret area after cursor has moved
 *
 */
void CDropCaret::HideCaret()
{
	if (_yHeight != -1)
	{
		_osdc.RenderBitMap(_hdcWindow, _ptCaret.x, _ptCaret.y, WIDTH_DROPCARET, 
			_yHeight);
	}
}


⌨️ 快捷键说明

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