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

📄 mtldragdrop.h

📁 一个使用wtl写的完整的多窗口浏览器
💻 H
📖 第 1 页 / 共 2 页
字号:
#ifndef __MTLDRAGDROP_H__
#define __MTLDRAGDROP_H__

#pragma once

////////////////////////////////////////////////////////////////////////////
// MTL Version 0.10
// Copyright (C) 2001 MB<mb2@geocities.co.jp>
// All rights unreserved.
//
// This file is a part of Mb Template Library.
// The code and information is *NOT* provided "as-is" without
// warranty of any kind, either expressed or implied.
//
// MtlDragDrop.h: Last updated: March 19, 2001
/////////////////////////////////////////////////////////////////////////////
namespace MTL
{

typedef DWORD DROPEFFECT;

/////////////////////////////////////////////////////////////////////////////
// IDropSourceImpl
//
// for debug
#ifdef _DEBUG
	const bool _Mtl_DropSourceImpl_traceOn = false;
	#define DSTRACE if (_Mtl_DropSourceImpl_traceOn) ATLTRACE
#else
	#define DSTRACE
#endif

class ATL_NO_VTABLE _IDropSource
{
public:
	//this method needs a different name than QueryInterface
	STDMETHOD(_LocDSQueryInterface)(REFIID riid, void ** ppvObject) = 0;
	virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
	virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
};

class ATL_NO_VTABLE _IDropSourceLocator : public _IDropSource
{
public:
};

class IDropSourceImplBase
{
public:
	static bool s_bStaticInit;

	// metrics for drag start determination
	static UINT s_nDragMinDist;  // min. amount mouse must move for drag
	static UINT s_nDragDelay;    // delay before drag starts

	IDropSourceImplBase()
	{
		// init static variables
		if (!s_bStaticInit) {
			::EnterCriticalSection(&_Module.m_csStaticDataInit);
			if (!s_bStaticInit) {
				// get drag metrics from win.ini
				static const TCHAR szWindows[] = _T("windows");
				static const TCHAR szDragMinDist[] = _T("DragMinDist");
				static const TCHAR szDragDelay[] = _T("DragDelay");

				s_nDragMinDist = ::GetProfileInt(szWindows, szDragMinDist, DD_DEFDRAGMINDIST);
				s_nDragDelay = ::GetProfileInt(szWindows, szDragDelay, DD_DEFDRAGDELAY);

				s_bStaticInit = true;
			}
			::LeaveCriticalSection(&_Module.m_csStaticDataInit);
		}
	}
};

__declspec(selectany) bool IDropSourceImplBase::s_bStaticInit = false;
__declspec(selectany) UINT IDropSourceImplBase::s_nDragMinDist = DD_DEFDRAGMINDIST;
__declspec(selectany) UINT IDropSourceImplBase::s_nDragDelay = DD_DEFDRAGDELAY;

template <class T>
class ATL_NO_VTABLE IDropSourceImpl
	: public _IDropSourceLocator, public IDropSourceImplBase
{
public:
// COM Identity
	STDMETHOD(_LocDSQueryInterface)(REFIID riid, void ** ppvObject)
	{
		if (InlineIsEqualUnknown(riid) ||
			InlineIsEqualGUID(riid, IID_IDropSource))
		{
			if (ppvObject == NULL)
				return E_POINTER;
			*ppvObject = this;
			AddRef();
#ifdef _ATL_DEBUG_INTERFACES
			_Module.AddThunk((IUnknown**)ppvObject, _T("IDropSourceImpl"), riid);
#endif // _ATL_DEBUG_INTERFACES
			return S_OK;
		}
		else
			return E_NOINTERFACE;
	}
	virtual ULONG STDMETHODCALLTYPE AddRef()
	{
		return 1;
	}
	virtual ULONG STDMETHODCALLTYPE Release()
	{
		return 1;
	}

// Data members
	CRect m_rectStartDrag;  // when mouse leaves this rect, drag drop starts
	bool m_bDragStarted;    // has drag really started yet?
	DWORD m_dwButtonCancel; // which button will cancel (going down)
	DWORD m_dwButtonDrop;   // which button will confirm (going up)

// Ctor/dtor
	IDropSourceImpl() : m_bDragStarted(false), m_dwButtonCancel(0), m_dwButtonDrop(0)
	{
	}

// Attributes
	static bool IsSamePoint(CPoint ptNew, CPoint ptPrev)
	{
		CRect rc(ptPrev.x, ptPrev.y, ptPrev.x, ptPrev.y);
		rc.InflateRect(s_nDragMinDist, s_nDragMinDist);

		return rc.PtInRect(ptNew) == TRUE ? true : false;
	}

// IDropSource
	STDMETHOD(QueryContinueDrag)(BOOL bEscapePressed, DWORD dwKeyState)
	{
		// check escape key or right button -- and cancel
		if (bEscapePressed || (dwKeyState & m_dwButtonCancel) != 0)	{
			m_bDragStarted = false; // avoid unecessary cursor setting
			return DRAGDROP_S_CANCEL;
		}

		// check left-button up to end drag/drop and do the drop
		if ((dwKeyState & m_dwButtonDrop) == 0)
			return m_bDragStarted ? DRAGDROP_S_DROP : DRAGDROP_S_CANCEL;

		// otherwise, keep polling...
		return S_OK;
	}
	STDMETHOD(GiveFeedback)(DWORD)
	{
		// don't change the cursor until drag is officially started
		return m_bDragStarted ? DRAGDROP_S_USEDEFAULTCURSORS : S_OK;
	}

// Mothods
	DROPEFFECT DoDragDrop(IDataObject* pDataObject, DWORD dwOKEffects = DROPEFFECT_COPY|DROPEFFECT_MOVE|DROPEFFECT_LINK)
	{
		// call global OLE api to do the drag drop
		DWORD dwResultEffect = DROPEFFECT_NONE;
		::DoDragDrop(pDataObject, (IDropSource*)this, dwOKEffects, &dwResultEffect);
		return dwResultEffect;
	}
	
	bool PreDoDragDrop(HWND hWnd, LPRECT lpRectStartDrag = NULL, bool bUseDragDelay = false)
	{// cf. MFC6::COleDataSource::DoDragDrop
		m_bDragStarted = false;

		if (lpRectStartDrag != NULL) {
			// set drop source drag start rect to parameter provided
			m_rectStartDrag.CopyRect(lpRectStartDrag);
		}
		else {
			// otherwise start with default empty rectangle around current point
			CPoint ptCursor; ::GetCursorPos(&ptCursor);
			m_rectStartDrag.SetRect(ptCursor.x, ptCursor.y, ptCursor.x, ptCursor.y);
		}

		if (m_rectStartDrag.IsRectNull()) {
			// null rect specifies no OnBeginDrag wait loop
			m_bDragStarted = true;
		}
		else if (m_rectStartDrag.IsRectEmpty()) {
			// empty rect specifies drag drop around starting point
			m_rectStartDrag.InflateRect(
				s_nDragMinDist*2, s_nDragMinDist*2);
		}

		// before calling OLE drag/drop code, wait for mouse to move outside
		//  the rectangle
		return OnBeginDrag(hWnd, bUseDragDelay);
	}

/*	MFC wants pDataObject which can't be used, it sucks.
	DROPEFFECT DoDragDrop(IDataObject* pDataObject, HWND hWnd, DWORD dwOKEffects = DROPEFFECT_COPY|DROPEFFECT_MOVE|DROPEFFECT_LINK,
		LPRECT lpRectStartDrag = NULL)
	{
		m_bDragStarted = false;

		if (lpRectStartDrag != NULL) {
			// set drop source drag start rect to parameter provided
			m_rectStartDrag.CopyRect(lpRectStartDrag);
		}
		else {
			// otherwise start with default empty rectangle around current point
			CPoint ptCursor; ::GetCursorPos(&ptCursor);
			m_rectStartDrag.SetRect(ptCursor.x, ptCursor.y, ptCursor.x, ptCursor.y);
		}

		if (m_rectStartDrag.IsRectNull()) {
			// null rect specifies no OnBeginDrag wait loop
			m_bDragStarted = true;
		}
		else if (m_rectStartDrag.IsRectEmpty()) {
			// empty rect specifies drag drop around starting point
			m_rectStartDrag.InflateRect(
				s_nDragMinDist, s_nDragMinDist);
		}

		// before calling OLE drag/drop code, wait for mouse to move outside
		//  the rectangle
		T* pT = static_cast<T*>(this);
		if (!pT->OnBeginDrag(hWnd))
			return DROPEFFECT_NONE;

		// call global OLE api to do the drag drop
		DWORD dwResultEffect = DROPEFFECT_NONE;
		IDataObject* pDataObject = NULL;
		HRESULT hr = pT->OnBeginDragNow(&pDataObject);
		if (SUCCEEDED(hr))
			::DoDragDrop(pDataObject, (IDropSource*)this, dwOKEffects, &dwResultEffect);
		return dwResultEffect;
	}
*/

// Implementation
	bool OnBeginDrag(HWND hWnd, bool bUseDragDelay)
	{
		DSTRACE(_T("IDropSrouceImpl::OnBeginDrag\n"));
	
		m_bDragStarted = false;

		// opposite button cancels drag operation
		m_dwButtonCancel = 0;
		m_dwButtonDrop = 0;
		if (::GetKeyState(VK_LBUTTON) < 0) {
			m_dwButtonDrop |= MK_LBUTTON;
			m_dwButtonCancel |= MK_RBUTTON;
		}
		else if (::GetKeyState(VK_RBUTTON) < 0)	{
			m_dwButtonDrop |= MK_RBUTTON;
			m_dwButtonCancel |= MK_LBUTTON;
		}

		DWORD dwLastTick = GetTickCount();
		::SetCapture(hWnd);

		while (!m_bDragStarted) {
			// some applications steal capture away at random times
			if (::GetCapture() != hWnd) {
				DSTRACE(_T(" some applications steal capture away at random times\n"));
				break;
			}

			// peek for next input message
			MSG msg;

			// Your system has to know about Filter message,
			// For example, you can never give WM_MOUSEWHEEL to PeekMessage on win95.
			if (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) ||
				PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
			{
				// check for button cancellation (any button down will cancel)
				if (msg.message == WM_LBUTTONUP || msg.message == WM_RBUTTONUP ||
					msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN) {
					DSTRACE(_T(" button cancellation\n"));
//					_LButtonDblClickMessenger(msg, hWnd);
					break;
				}

				// check for keyboard cancellation
				if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) {
					DSTRACE(_T(" keyboard cancellation\n"));
					break;
				}

				// check for drag start transition
				DSTRACE(_T(" check for drag start transition : pt(%d, %d) rect(%d, %d, %d, %d)\n"),
					msg.pt.x, msg.pt.y, m_rectStartDrag.left, m_rectStartDrag.top, m_rectStartDrag.right, m_rectStartDrag.bottom);
				m_bDragStarted = !m_rectStartDrag.PtInRect(msg.pt);
			}

			// if the user sits here long enough, we eventually start the drag
			if (bUseDragDelay && ::GetTickCount() - dwLastTick > s_nDragDelay) {
				DSTRACE(_T(" we eventually start the drag!\n"));
				m_bDragStarted = true;
			}
		}
		::ReleaseCapture();

		return m_bDragStarted;
	}

	void _LButtonDblClickMessenger(MSG msgSrc, HWND hWnd)
	{
		if (msgSrc.message != WM_LBUTTONUP)
			return;

		// eat next message if click is on the same button
		MSG msg;
		if(::PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
		{
			if (msg.message == WM_LBUTTONDOWN && CPoint(msgSrc.pt) == CPoint(msg.pt)) {// same point
				CPoint pt = msg.pt;
				::ScreenToClient(hWnd, &pt);
				::PostMessage(hWnd, WM_LBUTTONDBLCLK, msg.wParam, MAKELPARAM(pt.x, pt.y));
			}
		}
	}
};


/////////////////////////////////////////////////////////////////////////////
// IDropTargetImpl
//
#ifdef _DEBUG
	const bool _bDropTargetImplTraceOn = false;
	#define DTTRACE if (_bDropTargetImplTraceOn) ATLTRACE
#else
	#define DTTRACE
#endif

// helper to filter out invalid DROPEFFECTs
inline DROPEFFECT _MtlFilterDropEffect(DROPEFFECT dropEffect, DROPEFFECT dwEffects)
{
	// return allowed dropEffect and DROPEFFECT_NONE
	if ((dropEffect & dwEffects) != 0)
		return dropEffect;

	// map common operations (copy/move) to alternates, but give negative
	//  feedback for DROPEFFECT_LINK.
	switch (dropEffect)
	{
	case DROPEFFECT_COPY:
		if (dwEffects & DROPEFFECT_MOVE)
			return DROPEFFECT_MOVE;
		else if (dwEffects & DROPEFFECT_LINK)
			return DROPEFFECT_LINK;
		break;
	case DROPEFFECT_MOVE:
		if (dwEffects & DROPEFFECT_COPY)
			return DROPEFFECT_COPY;
		else if (dwEffects & DROPEFFECT_LINK)
			return DROPEFFECT_LINK;
		break;
	case DROPEFFECT_LINK:
		break;
	}

	return DROPEFFECT_NONE;
}

// helper to get a standard effect
inline DROPEFFECT _MtlStandardDropEffect(DWORD dwKeyState)
{
	DROPEFFECT dropEffect;

	// check for force link
	if ((dwKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
		dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_LINK;
	// check for force copy
	else if ((dwKeyState & MK_CONTROL) == MK_CONTROL)
		dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_COPY;
	// check for force move
	else if ((dwKeyState & MK_ALT) == MK_ALT ||
		(dwKeyState & MK_SHIFT) == MK_SHIFT)
		dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
	// default -- recommended action is move
	else
		dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
	return dropEffect;
}

inline DROPEFFECT _MtlFollowDropEffect(DROPEFFECT dwEffects)
{
	dwEffects &= ~DROPEFFECT_SCROLL;

	if (dwEffects == DROPEFFECT_COPY)		// only copy
		return DROPEFFECT_COPY;
	else if (dwEffects == DROPEFFECT_LINK)	// only link
		return DROPEFFECT_LINK;
	else
		return 0;	// no need to add
}

class ATL_NO_VTABLE _IDropTarget // = emulates IDropTarget's vtable
{
public:
	//this method needs a different name than QueryInterface
	STDMETHOD(_LocDTQueryInterface)(REFIID riid, void ** ppvObject) = 0;
	virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
	virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
};

class ATL_NO_VTABLE _IDropTargetLocator : public _IDropTarget
{
public:
};

⌨️ 快捷键说明

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