📄 mtldragdrop.h
字号:
#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 + -