2184 lines
67 KiB
C++
2184 lines
67 KiB
C++
// ====================================================================================
|
|
// Class Specification :
|
|
// COXSHBDropSource & COXSHBDropTarget
|
|
// ====================================================================================
|
|
|
|
// Header file : OXDragDropSupport.h
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if !defined(_OX_DRAGDROPSUPPORT_)
|
|
#define _OX_DRAGDROPSUPPORT_
|
|
|
|
#if _MSC_VER >= 1000
|
|
#pragma once
|
|
#endif // _MSC_VER >= 1000
|
|
|
|
#include "OXDllExt.h"
|
|
#include "OXMainRes.h"
|
|
|
|
#ifndef __AFXTEMPL_H__
|
|
#include <afxtempl.h>
|
|
#define __AFXTEMPL_H__
|
|
#endif
|
|
|
|
#ifndef __AFXOLE_H__
|
|
#include <afxole.h> // MFC OLE classes
|
|
#define __AFXOLE_H__
|
|
#endif
|
|
|
|
// All folowing notifications has to do with OLE drag and drop. Refer to the
|
|
// documentation on COleDropSource and COleDropTarget to get full description of
|
|
// drag and drop operation.
|
|
//
|
|
// COleDropTarget based notifications
|
|
//
|
|
// These notifications can be sent by child windows and shortcut bar. lParam of
|
|
// NMSHORTCUTBAR always points to SHBDROPTARGETACTION structure which is described later.
|
|
// If you handle these notifications and don't want to run the default implementation
|
|
// of them then you must return non-zero value and set result element of
|
|
// SHBDROPTARGETACTION structure to corresponding value which is depend on the
|
|
// particular notification.
|
|
// You can distinguish the sender of the notification by hGroup element of NMSHORTCUTBAR
|
|
// structure: if sender is shortcut bar then hGroup will be set to NULL; if sender is
|
|
// child window then hGroup will be set to corresponding child window parent group.
|
|
//
|
|
//
|
|
// Sent to parent window to notify that the cursor is first dragged into the window.
|
|
// Set result element of SHBDROPTARGETACTION to the effect that would result if a drop
|
|
// were attempted at the location specified by point element of SHBDROPTARGETACTION.
|
|
// It can be one or more of the following:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, dwKeyState, point
|
|
//
|
|
//SHBN_DRAGENTER
|
|
//
|
|
// Sent to parent window to notify that the cursor leaves the window while a dragging
|
|
// operation is in effect.
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd
|
|
//
|
|
//SHBN_DRAGLEAVE
|
|
//
|
|
// Sent to parent window to notify that the cursor is dragged over the window. This
|
|
// notification should be handled to allow drop operations to occur in the window. The
|
|
// default implementation returns DROPEFFECT_NONE by default. Because this notification is
|
|
// called frequently during a drag-and-drop operation, it should be optimized as much
|
|
// as possible. Set result element of SHBDROPTARGETACTION to the effect that would
|
|
// result if a drop were attempted at the location specified by point element of
|
|
// SHBDROPTARGETACTION. It can be one or more of the following:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, dwKeyState, point
|
|
//
|
|
//SHBN_DRAGOVER
|
|
//
|
|
// Sent to parent window before sending SHBN_DRAGENTER or SHBN_DRAGOVER notifications
|
|
// to determine whether point is in the scrolling region. Handle this notification when
|
|
// you want to provide special behavior for this event. The default implementation
|
|
// returns DROPEFFECT_NONE and scrolls the window when the cursor is dragged into the
|
|
// scroll region inside the border of the window. Set result element of
|
|
// SHBDROPTARGETACTION to the effect that would result if a drop were attempted at
|
|
// the location specified by point element of SHBDROPTARGETACTION. It can be one or
|
|
// more of the following:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, dwKeyState, point.
|
|
//
|
|
//SHBN_DRAGSCROLL
|
|
//
|
|
// Sent to parent window to notify that a drop operation is about to occur. Set result
|
|
// element of SHBDROPTARGETACTION to the TRUE if drop operation was successful or
|
|
// FALSE otherwise.
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, point, dropEffect
|
|
//
|
|
//SHBN_DROP
|
|
//
|
|
// Sent to parent window to notify that a drop operation is about to occur. This
|
|
// notification will be sent before SHBDTM_DROP. If you does not handle it, then
|
|
// SHBN_DROP notification will be sent. Typically, you will handle SHBN_DROPEX to
|
|
// support right mouse-button drag and drop. Typically, SHBN_DROP notification is used
|
|
// to handle the case of support for simple drag and drop.
|
|
// By default, we simply return a dummy value to indicate the SHBN_DROP notification
|
|
// should be sent. Set result element of SHBDROPTARGETACTION to the drop effects that
|
|
// describe the action associated with a drop operation. See the following list of
|
|
// drop effects:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, point,
|
|
// dropEffect, dropList.
|
|
//SHBN_DROPEX
|
|
//
|
|
//
|
|
// COleDropSource based notifications
|
|
//
|
|
// These notifications can be sent only by child windows. lParam of NMSHORTCUTBAR
|
|
// always points to SHBDROPSOURCEACTION structure which is described later.
|
|
// If you handle these notifications and don't want to run the default implementation
|
|
// of them then you must return non-zero value and set result element of
|
|
// SHBDROPSOURCEACTION structure to corresponding value which is depend on the
|
|
// particular notification.
|
|
//
|
|
//
|
|
// Handle SHBN_GIVEFEEDBACK notification to provide feedback to the user about what
|
|
// would happen if a drop occurred at this point. The default implementation uses
|
|
// the OLE default cursors. For more information on drag-and-drop operations using
|
|
// OLE, see the article Drag and Drop (OLE) in Visual C++ Programmer's Guide.
|
|
// Set result element of SHBDROPSOURCEACTION to the DRAGDROP_S_USEDEFAULTCURSORS if
|
|
// dragging is in progress, NOERROR if it is not.
|
|
// Next elements of SHBDROPSOURCEACTION are filled: dropEffect.
|
|
//
|
|
//SHBN_GIVEFEEDBACK
|
|
//
|
|
// SHBN_BEGINDRAG notification is sent to the parent window when an event occurs that
|
|
// could begin a drag operation, such as pressing the left mouse button. Handle this
|
|
// notification if you want to modify the way the dragging process is started. The default
|
|
// implementation captures the mouse and stays in drag mode until the user clicks the
|
|
// left or right mouse button or hits ESC, at which time it releases the mouse.
|
|
// Set result element of SHBDROPSOURCEACTION to TRUE if dragging is allowed,
|
|
// otherwise FALSE.
|
|
// Next elements of SHBDROPSOURCEACTION are filled: pWnd.
|
|
// SHBN_BEGINDRAG
|
|
//
|
|
// SHBN_QUERYCONTINUEDRAG notification is sent to the parent window after dragging has
|
|
// begun, this notification will be sent repeatedly until the drag operation is either
|
|
// canceled or completed. Handle this notification if you want to change the point at
|
|
// which dragging is canceled or a drop occurs. The default implementation initiates
|
|
// the drop or cancels the drag as follows. It cancels a drag operation when the ESC
|
|
// key or the right mouse button is pressed. It initiates a drop operation when the
|
|
// left mouse button is raised after dragging has started. Otherwise, it returns
|
|
// S_OK and performs no further operations. Because this notification is called frequently,
|
|
// it should be optimized as much as possible.
|
|
// Set result element of SHBDROPSOURCEACTION to DRAGDROP_S_CANCEL if the ESC key or
|
|
// right button is pressed, or left button is raised before dragging starts,
|
|
// to DRAGDROP_S_DROP if a drop operation should occur, or otherwise to S_OK.
|
|
// Next elements of SHBDROPSOURCEACTION are filled: bEscapePressed, dwKeyState .
|
|
//SHBN_QUERYCONTINUEDRAG
|
|
|
|
|
|
// Structure that is used in messages sending from COXSHBDropTarget object
|
|
// to its owner window
|
|
//
|
|
typedef struct _tagSHBDROPTARGETACTION
|
|
{
|
|
//
|
|
// Points to the window the cursor is currently over
|
|
CWnd* pWnd;
|
|
//
|
|
// Points to the data object that contains the data to be dropped
|
|
COleDataObject* pDataObject;
|
|
//
|
|
// Contains the state of the modifier keys. This is a combination of any number of
|
|
// the following:
|
|
// MK_CONTROL
|
|
// MK_SHIFT
|
|
// MK_ALT
|
|
// MK_LBUTTON
|
|
// MK_MBUTTON
|
|
// MK_RBUTTON
|
|
//
|
|
DWORD dwKeyState;
|
|
//
|
|
// Contains the current location of the cursor in client coordinates.
|
|
CPoint point;
|
|
//
|
|
// The effect that the user chose for the drop operation. It can be one or more of
|
|
// the following:
|
|
//
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original
|
|
// data would be established.
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_SCROLL Indicates that a drag scroll operation is about
|
|
// to occur or is occurring in the target.
|
|
//
|
|
DROPEFFECT dropEffect;
|
|
//
|
|
// A list of the drop effects that the drop source supports. Drop effect values
|
|
// can be combined using the bitwise OR (|) operation. Drop effects are discussed
|
|
// above
|
|
DROPEFFECT dropList;
|
|
//
|
|
// result of message handling (differ for different messages)
|
|
LRESULT result;
|
|
|
|
_tagSHBDROPTARGETACTION()
|
|
{
|
|
ZeroMemory(this,sizeof(_tagSHBDROPTARGETACTION));
|
|
}
|
|
|
|
} SHBDROPTARGETACTION, * LPSHBDROPTARGETACTION;
|
|
|
|
|
|
// Following messages are sent to any window that registered as drop target object
|
|
// using our COXSHBDropTarget class. For every message wParam is set to NULL and
|
|
// lParam points to SHBDROPTARGETACTION structure. Return TRUE if you handle the
|
|
// message and FALSE if you want to run the default implementation.
|
|
//
|
|
// Sent to owner window to notify that the cursor is first dragged into the window.
|
|
// Set result element of SHBDROPTARGETACTION to the effect that would result if a drop
|
|
// were attempted at the location specified by point element of SHBDROPTARGETACTION.
|
|
// It can be one or more of the following:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, dwKeyState, point
|
|
//
|
|
//SHBDTM_DRAGENTER
|
|
//
|
|
// Sent to owner window to notify that the cursor leaves the window while a dragging
|
|
// operation is in effect.
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd
|
|
//
|
|
//SHBDTM_DRAGLEAVE
|
|
//
|
|
// Sent to owner window to notify that the cursor is dragged over the window. This
|
|
// message should be handled to allow drop operations to occur in the window. The
|
|
// default implementation returns DROPEFFECT_NONE by default. Because this message is
|
|
// called frequently during a drag-and-drop operation, it should be optimized as much
|
|
// as possible. Set result element of SHBDROPTARGETACTION to the effect that would
|
|
// result if a drop were attempted at the location specified by point element of
|
|
// SHBDROPTARGETACTION. It can be one or more of the following:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, dwKeyState, point
|
|
//
|
|
//SHBDTM_DRAGOVER
|
|
//
|
|
// Sent to owner window before sending SHBDTM_DRAGENTER or SHBDTM_DRAGOVER messages
|
|
// to determine whether point is in the scrolling region. Handle this message when
|
|
// you want to provide special behavior for this event. The default implementation
|
|
// returns DROPEFFECT_NONE and scrolls the window when the cursor is dragged into the
|
|
// scroll region inside the border of the window. Set result element of
|
|
// SHBDROPTARGETACTION to the effect that would result if a drop were attempted at
|
|
// the location specified by point element of SHBDROPTARGETACTION. It can be one or
|
|
// more of the following:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, dwKeyState, point.
|
|
//
|
|
//SHBDTM_DRAGSCROLL
|
|
//
|
|
// Sent to owner window to notify that a drop operation is about to occur. Set result
|
|
// element of SHBDROPTARGETACTION to the TRUE if drop operation was successful or
|
|
// FALSE otherwise.
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, point, dropEffect
|
|
//
|
|
//SHBDTM_DROP
|
|
//
|
|
// Sent to owner window to notify that a drop operation is about to occur. This
|
|
// message will be sent before SHBDTM_DROP. If you does not handle it, then
|
|
// SHBDTM_DROP message will be sent. Typically, you will handle SHBDTM_DROPEX in
|
|
// your child window class to support right mouse-button drag and drop. Typically,
|
|
// SHBDTM_DROP message is used to handle the case of support for simple drag and drop.
|
|
// By default, we simply return a dummy value to indicate the SHBDTM_DROP message
|
|
// should be sent. Set result element of SHBDROPTARGETACTION to the drop effects that
|
|
// describe the action associated with a drop operation. See the following list of
|
|
// drop effects:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, point,
|
|
// dropEffect, dropList.
|
|
//SHBDTM_DROPEX
|
|
|
|
|
|
// Structure that is used in messages sending from COXSHBDropSource object
|
|
// to its owner window
|
|
//
|
|
typedef struct _tagSHBDROPSOURCEACTION
|
|
{
|
|
//
|
|
// Points to the window that contains the selected data.
|
|
CWnd* pWnd;
|
|
//
|
|
// Contains the state of the modifier keys. This is a combination of any number of
|
|
// the following:
|
|
// MK_CONTROL
|
|
// MK_SHIFT
|
|
// MK_ALT
|
|
// MK_LBUTTON
|
|
// MK_MBUTTON
|
|
// MK_RBUTTON
|
|
//
|
|
DWORD dwKeyState;
|
|
//
|
|
// Used only with SHBDS_QUERYCONTINUEDRAG and states whether the ESC key has been
|
|
// pressed since the last time this message was sent.
|
|
BOOL bEscapePressed;
|
|
//
|
|
// The effect you would like to display to the user, usually indicating what
|
|
// would happen if a drop occurred at this point with the selected data. It can
|
|
// be one or more of the following:
|
|
//
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original
|
|
// data would be established.
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_SCROLL Indicates that a drag scroll operation is about
|
|
// to occur or is occurring in the target.
|
|
//
|
|
DROPEFFECT dropEffect;
|
|
//
|
|
// result of message handling (differ for different messages)
|
|
LRESULT result;
|
|
|
|
_tagSHBDROPSOURCEACTION()
|
|
{
|
|
ZeroMemory(this,sizeof(_tagSHBDROPSOURCEACTION));
|
|
}
|
|
|
|
} SHBDROPSOURCEACTION, * LPSHBDROPSOURCEACTION;
|
|
|
|
|
|
// Following messages are sent to any window that uses COXSHBDropSource class in
|
|
// its drag'n'drop operations. For every message wParam is set to NULL and
|
|
// lParam points to SHBDROPSOURCEACTION structure. Return TRUE if you handle the
|
|
// message and FALSE if you want to run the default implementation.
|
|
//
|
|
// Handle SHBDSM_GIVEFEEDBACK message to provide feedback to the user about what
|
|
// would happen if a drop occurred at this point. The default implementation uses
|
|
// the OLE default cursors. For more information on drag-and-drop operations using
|
|
// OLE, see the article Drag and Drop (OLE) in Visual C++ Programmer's Guide.
|
|
// Set result element of SHBDROPSOURCEACTION to the DRAGDROP_S_USEDEFAULTCURSORS if
|
|
// dragging is in progress, NOERROR if it is not.
|
|
// Next elements of SHBDROPSOURCEACTION are filled: dropEffect.
|
|
//
|
|
//SHBDSM_GIVEFEEDBACK
|
|
//
|
|
// SHBDSM_BEGINDRAG message is sent to the owner window when an event occurs that
|
|
// could begin a drag operation, such as pressing the left mouse button. Handle this
|
|
// message if you want to modify the way the dragging process is started. The default
|
|
// implementation captures the mouse and stays in drag mode until the user clicks the
|
|
// left or right mouse button or hits ESC, at which time it releases the mouse.
|
|
// Set result element of SHBDROPSOURCEACTION to TRUE if dragging is allowed,
|
|
// otherwise FALSE.
|
|
// Next elements of SHBDROPSOURCEACTION are filled: pWnd.
|
|
//SHBDSM_BEGINDRAG
|
|
//
|
|
// SHBDSM_QUERYCONTINUEDRAG message is sent to the owner window after dragging has
|
|
// begun, this message will be sent repeatedly until the drag operation is either
|
|
// canceled or completed. Handle this message if you want to change the point at
|
|
// which dragging is canceled or a drop occurs. The default implementation initiates
|
|
// the drop or cancels the drag as follows. It cancels a drag operation when the ESC
|
|
// key or the right mouse button is pressed. It initiates a drop operation when the
|
|
// left mouse button is raised after dragging has started. Otherwise, it returns
|
|
// S_OK and performs no further operations. Because this message is called frequently,
|
|
// it should be optimized as much as possible.
|
|
// Set result element of SHBDROPSOURCEACTION to DRAGDROP_S_CANCEL if the ESC key or
|
|
// right button is pressed, or left button is raised before dragging starts,
|
|
// to DRAGDROP_S_DROP if a drop operation should occur, or otherwise to S_OK.
|
|
// Next elements of SHBDROPSOURCEACTION are filled: bEscapePressed, dwKeyState .
|
|
//
|
|
//SHBDSM_QUERYCONTINUEDRAG
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXSHBDropSource
|
|
|
|
/*
|
|
|
|
COXSHBDropSource is designed to provide a standard way of handling OLE drag and drop
|
|
operation in any window. COXSHBDropSource is derived from standard COleDropSource class,
|
|
and you can use it as common COleDropSource object in COleDataSource::DoDragDrop
|
|
function. The only thing you have to do is to register the window that launch drag and
|
|
drop operation as COXSHBDropSource owner window using
|
|
COXSHBDropSource::SetOwner(CWnd* pWnd) function:
|
|
|
|
CWnd* SetOwner(CWnd* pWnd);
|
|
// --- In : pWnd - pointer to the window which will be the recipient
|
|
// of all COXSHBDropSource specific messages
|
|
// --- Out :
|
|
// --- Returns: pointer to the previous recipient window
|
|
// --- Effect :
|
|
|
|
|
|
As long as window is registered as COXSHBDropSource owner and as soon as the drag and
|
|
drop operation has been started our COXSHBDropSource class will send to this window
|
|
(we call it recipient window) next messages:
|
|
|
|
SHBDSM_GIVEFEEDBACK
|
|
SHBDSM_BEGINDRAG
|
|
SHBDSM_QUERYCONTINUEDRAG
|
|
|
|
For every message wParam is set to NULL and lParam points to SHBDROPSOURCEACTION
|
|
structure. Return TRUE if you handle the message and FALSE if you want to run the
|
|
default implementation.
|
|
|
|
Structure that is used in messages sending from COXSHBDropSource object is defined
|
|
as follows:
|
|
|
|
typedef struct _tagSHBDROPSOURCEACTION
|
|
{
|
|
//
|
|
// Points to the window that contains the selected data.
|
|
CWnd* pWnd;
|
|
//
|
|
// Contains the state of the modifier keys. This is a combination of any number of
|
|
// the following:
|
|
// MK_CONTROL
|
|
// MK_SHIFT
|
|
// MK_ALT
|
|
// MK_LBUTTON
|
|
// MK_MBUTTON
|
|
// MK_RBUTTON
|
|
//
|
|
DWORD dwKeyState;
|
|
//
|
|
// Used only with SHBDS_QUERYCONTINUEDRAG and states whether the ESC key has been
|
|
// pressed since the last time this message was sent.
|
|
BOOL bEscapePressed;
|
|
//
|
|
// The effect you would like to display to the user, usually indicating what
|
|
// would happen if a drop occurred at this point with the selected data. It can
|
|
// be one or more of the following:
|
|
//
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original
|
|
// data would be established.
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_SCROLL Indicates that a drag scroll operation is about
|
|
// to occur or is occurring in the target.
|
|
//
|
|
DROPEFFECT dropEffect;
|
|
//
|
|
// result of message handling (differ for different messages)
|
|
LRESULT result;
|
|
|
|
. . . . . . . . . . . .
|
|
|
|
} SHBDROPSOURCEACTION, * LPSHBDROPSOURCEACTION;
|
|
|
|
|
|
Below you will find detailed description of all messages sent by COXSHBDropSource:
|
|
|
|
|
|
/////////////////////////
|
|
SHBDSM_GIVEFEEDBACK
|
|
//
|
|
//
|
|
// Handle SHBDSM_GIVEFEEDBACK message to provide feedback to the user about what
|
|
// would happen if a drop occurred at this point. The default implementation uses
|
|
// the OLE default cursors. For more information on drag-and-drop operations using
|
|
// OLE, see the article Drag and Drop (OLE) in Visual C++ Programmer's Guide.
|
|
// Set result element of SHBDROPSOURCEACTION to the DRAGDROP_S_USEDEFAULTCURSORS if
|
|
// dragging is in progress, NOERROR if it is not.
|
|
// Next elements of SHBDROPSOURCEACTION are filled: dropEffect.
|
|
|
|
/////////////////////////
|
|
SHBDSM_BEGINDRAG
|
|
//
|
|
//
|
|
// SHBDSM_BEGINDRAG message is sent to the owner window when an event occurs that
|
|
// could begin a drag operation, such as pressing the left mouse button. Handle this
|
|
// message if you want to modify the way the dragging process is started. The default
|
|
// implementation captures the mouse and stays in drag mode until the user clicks the
|
|
// left or right mouse button or hits ESC, at which time it releases the mouse.
|
|
// Set result element of SHBDROPSOURCEACTION to TRUE if dragging is allowed,
|
|
// otherwise FALSE.
|
|
// Next elements of SHBDROPSOURCEACTION are filled: pWnd.
|
|
|
|
/////////////////////////
|
|
SHBDSM_QUERYCONTINUEDRAG
|
|
//
|
|
//
|
|
// SHBDSM_QUERYCONTINUEDRAG message is sent to the owner window after dragging has
|
|
// begun, this message will be sent repeatedly until the drag operation is either
|
|
// canceled or completed. Handle this message if you want to change the point at
|
|
// which dragging is canceled or a drop occurs. The default implementation initiates
|
|
// the drop or cancels the drag as follows. It cancels a drag operation when the ESC
|
|
// key or the right mouse button is pressed. It initiates a drop operation when the
|
|
// left mouse button is raised after dragging has started. Otherwise, it returns
|
|
// S_OK and performs no further operations. Because this message is called frequently,
|
|
// it should be optimized as much as possible.
|
|
// Set result element of SHBDROPSOURCEACTION to DRAGDROP_S_CANCEL if the ESC key or
|
|
// right button is pressed, or left button is raised before dragging starts,
|
|
// to DRAGDROP_S_DROP if a drop operation should occur, or otherwise to S_OK.
|
|
// Next elements of SHBDROPSOURCEACTION are filled: bEscapePressed, dwKeyState .
|
|
|
|
|
|
You can handle whatever messages you would like to, unhandled messages will be
|
|
handled using default implementation.
|
|
|
|
*/
|
|
|
|
class OX_CLASS_DECL COXSHBDropSource : public COleDropSource
|
|
{
|
|
public:
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns:
|
|
// --- Effect : Constructor of the object
|
|
COXSHBDropSource() : m_pOwnerWnd(NULL) {};
|
|
|
|
protected:
|
|
// pointer to the window that owns this object
|
|
CWnd* m_pOwnerWnd;
|
|
|
|
public:
|
|
// --- In : pWnd - pointer to the window which will be the recipient
|
|
// of all COXSHBDropSource specific messages
|
|
// --- Out :
|
|
// --- Returns: pointer to the previous recipient window
|
|
// --- Effect : sets recipient window for drop operation
|
|
CWnd* SetOwner(CWnd* pWnd)
|
|
{
|
|
ASSERT(pWnd);
|
|
// owner window (recipient window) must exist at that moment
|
|
ASSERT(::IsWindow(pWnd->GetSafeHwnd()));
|
|
|
|
CWnd* pOldWnd=m_pOwnerWnd;
|
|
m_pOwnerWnd=pWnd;
|
|
|
|
// return old owner window
|
|
return pOldWnd;
|
|
}
|
|
|
|
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns: pointer to the recipient window
|
|
// --- Effect : retrieves a pointer to the recipient window for drop operation
|
|
inline CWnd* GetOwner() const { return m_pOwnerWnd; }
|
|
|
|
|
|
// --- In : nMsgID - message ID to send to recipient window
|
|
// pSHBDSAction - pointer to SHBDROPSOURCEACTION structure
|
|
// --- Out :
|
|
// --- Returns: result of handling of the message
|
|
// --- Effect : Sends COXSHBDropSource specific message to its recipient window
|
|
LRESULT SendSHBDSMessage(UINT nMsgID, LPSHBDROPSOURCEACTION pSHBDSAction)
|
|
{
|
|
ASSERT(m_pOwnerWnd);
|
|
ASSERT(::IsWindow(m_pOwnerWnd->GetSafeHwnd()));
|
|
ASSERT(pSHBDSAction!=NULL);
|
|
|
|
// send message to drop target owner window using NMSHBDROPTARGET structure
|
|
// as lParam. Let the owner (recipient) window to handle the message
|
|
return m_pOwnerWnd->SendMessage(nMsgID,(WPARAM)0,(LPARAM)pSHBDSAction);
|
|
}
|
|
|
|
// Overrides
|
|
//
|
|
// See DRAG and DROP section of OLE classes reference and
|
|
// COleDragTarget reference
|
|
//
|
|
virtual SCODE QueryContinueDrag(BOOL bEscapePressed, DWORD dwKeyState)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// send corresponding message to the owner window
|
|
SHBDROPSOURCEACTION SHBDSAction;
|
|
SHBDSAction.bEscapePressed=bEscapePressed;
|
|
SHBDSAction.dwKeyState=dwKeyState;
|
|
|
|
if(SendSHBDSMessage(SHBDSM_QUERYCONTINUEDRAG,&SHBDSAction))
|
|
return (SCODE)SHBDSAction.result;
|
|
|
|
// Call the base class implementation
|
|
return COleDropSource::QueryContinueDrag(bEscapePressed,dwKeyState);
|
|
}
|
|
|
|
virtual SCODE GiveFeedback(DROPEFFECT dropEffect)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// send corresponding message to the owner window
|
|
SHBDROPSOURCEACTION SHBDSAction;
|
|
SHBDSAction.dropEffect=dropEffect;
|
|
|
|
if(SendSHBDSMessage(SHBDSM_GIVEFEEDBACK,&SHBDSAction))
|
|
return (SCODE)SHBDSAction.result;
|
|
|
|
// Call the base class implementation
|
|
return COleDropSource::GiveFeedback(dropEffect);
|
|
}
|
|
|
|
virtual BOOL OnBeginDrag(CWnd* pWnd)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// send corresponding message to the owner window
|
|
SHBDROPSOURCEACTION SHBDSAction;
|
|
SHBDSAction.pWnd=pWnd;
|
|
|
|
if(SendSHBDSMessage(SHBDSM_BEGINDRAG,&SHBDSAction))
|
|
return (BOOL)SHBDSAction.result;
|
|
|
|
// Call the base class implementation
|
|
return COleDropSource::OnBeginDrag(pWnd);
|
|
}
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXSHBDropTarget
|
|
|
|
/*
|
|
|
|
COXSHBDropTarget is designed to provide a standard way of handling OLE drag and drop
|
|
operation in any window. COXSHBDropTarget is derived from standard COleDropTarget class,
|
|
so the only thing you need to do to make it work for you is just to register whatever
|
|
window you need as drop target using COleDropTarget::Register(CWnd* pWnd) function
|
|
(you can do it for example in this window OnCreate function).
|
|
|
|
As long as window is registered as drop target and as soon as any OLE object will be
|
|
dragged on that window our COXSHBDropTarget class will send to this window( we call
|
|
it owner window) next messages:
|
|
|
|
SHBDTM_DRAGENTER
|
|
SHBDTM_DRAGLEAVE
|
|
SHBDTM_DRAGOVER
|
|
SHBDTM_DRAGSCROLL
|
|
SHBDTM_DROP
|
|
SHBDTM_DROPEX
|
|
|
|
For every message wParam is set to NULL and lParam points to SHBDROPTARGETACTION
|
|
structure. Return TRUE if you handle the message and FALSE if you want to run the
|
|
default implementation.
|
|
|
|
Structure that is used in messages sending from COXSHBDropTarget object is defined
|
|
as follows:
|
|
|
|
typedef struct _tagSHBDROPTARGETACTION
|
|
{
|
|
//
|
|
// Points to the window the cursor is currently over
|
|
CWnd* pWnd;
|
|
//
|
|
// Points to the data object that contains the data to be dropped
|
|
COleDataObject* pDataObject;
|
|
//
|
|
// Contains the state of the modifier keys. This is a combination of any number of
|
|
// the following:
|
|
// MK_CONTROL
|
|
// MK_SHIFT
|
|
// MK_ALT
|
|
// MK_LBUTTON
|
|
// MK_MBUTTON
|
|
// MK_RBUTTON
|
|
//
|
|
DWORD dwKeyState;
|
|
//
|
|
// Contains the current location of the cursor in client coordinates.
|
|
CPoint point;
|
|
//
|
|
// The effect that the user chose for the drop operation. It can be one or more of
|
|
// the following:
|
|
//
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original
|
|
// data would be established.
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_SCROLL Indicates that a drag scroll operation is about
|
|
// to occur or is occurring in the target.
|
|
//
|
|
DROPEFFECT dropEffect;
|
|
//
|
|
// A list of the drop effects that the drop source supports. Drop effect values
|
|
// can be combined using the bitwise OR (|) operation. Drop effects are discussed
|
|
// above
|
|
DROPEFFECT dropList;
|
|
//
|
|
// result of message handling (differ for different messages)
|
|
LRESULT result;
|
|
|
|
. . . . . . . . . . . . . . . . . . .
|
|
|
|
} SHBDROPTARGETACTION, * LPSHBDROPTARGETACTION;
|
|
|
|
|
|
|
|
Below you will find detailed description of all messages sent by COXSHBDropTarget:
|
|
|
|
|
|
/////////////////////////
|
|
SHBDTM_DRAGENTER
|
|
//
|
|
//
|
|
// Sent to owner window to notify that the cursor is first dragged into the window.
|
|
// Set result element of SHBDROPTARGETACTION to the effect that would result if a drop
|
|
// were attempted at the location specified by point element of SHBDROPTARGETACTION.
|
|
// It can be one or more of the following:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, dwKeyState, point
|
|
|
|
/////////////////////////
|
|
SHBDTM_DRAGLEAVE
|
|
//
|
|
//
|
|
// Sent to owner window to notify that the cursor leaves the window while a dragging
|
|
// operation is in effect.
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd
|
|
|
|
/////////////////////////
|
|
SHBDTM_DRAGOVER
|
|
//
|
|
//
|
|
// Sent to owner window to notify that the cursor is dragged over the window. This
|
|
// message should be handled to allow drop operations to occur in the window. The
|
|
// default implementation returns DROPEFFECT_NONE by default. Because this message is
|
|
// called frequently during a drag-and-drop operation, it should be optimized as much
|
|
// as possible. Set result element of SHBDROPTARGETACTION to the effect that would
|
|
// result if a drop were attempted at the location specified by point element of
|
|
// SHBDROPTARGETACTION. It can be one or more of the following:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, dwKeyState, point
|
|
|
|
/////////////////////////
|
|
SHBDTM_DRAGSCROLL
|
|
//
|
|
//
|
|
// Sent to owner window before sending SHBDTM_DRAGENTER or SHBDTM_DRAGOVER messages
|
|
// to determine whether point is in the scrolling region. Handle this message when
|
|
// you want to provide special behavior for this event. The default implementation
|
|
// returns DROPEFFECT_NONE and scrolls the window when the cursor is dragged into the
|
|
// scroll region inside the border of the window. Set result element of
|
|
// SHBDROPTARGETACTION to the effect that would result if a drop were attempted at
|
|
// the location specified by point element of SHBDROPTARGETACTION. It can be one or
|
|
// more of the following:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, dwKeyState, point.
|
|
|
|
/////////////////////////
|
|
SHBDTM_DROP
|
|
//
|
|
//
|
|
// Sent to owner window to notify that a drop operation is about to occur. Set result
|
|
// element of SHBDROPTARGETACTION to the TRUE if drop operation was successful or
|
|
// FALSE otherwise.
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, point, dropEffect
|
|
|
|
/////////////////////////
|
|
SHBDTM_DROPEX
|
|
//
|
|
//
|
|
// Sent to owner window to notify that a drop operation is about to occur. This
|
|
// message will be sent before SHBDTM_DROP. If you does not handle it, then
|
|
// SHBDTM_DROP message will be sent. Typically, you will handle SHBDTM_DROPEX in
|
|
// your child window class to support right mouse-button drag and drop. Typically,
|
|
// SHBDTM_DROP message is used to handle the case of support for simple drag and drop.
|
|
// By default, we simply return a dummy value to indicate the SHBDTM_DROP message
|
|
// should be sent. Set result element of SHBDROPTARGETACTION to the drop effects that
|
|
// describe the action associated with a drop operation. See the following list of
|
|
// drop effects:
|
|
//
|
|
// DROPEFFECT_NONE A drop would not be allowed.
|
|
// DROPEFFECT_COPY A copy operation would be performed.
|
|
// DROPEFFECT_MOVE A move operation would be performed.
|
|
// DROPEFFECT_LINK A link from the dropped data to the original data would
|
|
// be established.
|
|
// DROPEFFECT_SCROLL A drag scroll operation is about to occur or is occurring
|
|
// in the target.
|
|
//
|
|
// Next elements of SHBDROPTARGETACTION are filled: pWnd, pDataObject, point,
|
|
// dropEffect, dropList.
|
|
|
|
|
|
|
|
You can handle whatever messages you would like to, unhandled messages will be
|
|
handled using default implementation.
|
|
|
|
An example of using of this class can be found in the source code of our COXSHBListCtrl
|
|
and COXShortcutBar classes.
|
|
|
|
COXSHBListCtrl uses COXSHBDropTarget to provide drag and drop of its items and handle
|
|
next messages: SHBDTM_DRAGENTER, SHBDTM_DRAGLEAVE, SHBDTM_DRAGOVER, SHBDTM_DROP
|
|
|
|
COXShortcutBar uses COXSHBDropTarget to support any drag and drop operation and handle
|
|
next messages: SHBDTM_DRAGLEAVE, SHBDTM_DRAGOVER
|
|
|
|
|
|
*/
|
|
|
|
class OX_CLASS_DECL COXSHBDropTarget : public COleDropTarget
|
|
{
|
|
// Construction
|
|
public:
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns:
|
|
// --- Effect : Constructor of the object
|
|
COXSHBDropTarget() {};
|
|
|
|
// Implementation
|
|
public:
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns:
|
|
// --- Effect : Destructor of object
|
|
virtual ~COXSHBDropTarget() {};
|
|
|
|
|
|
// --- In : nMsgID - message ID to send to owner window
|
|
// pSHBDTAction - pointer to SHBDROPTARGETACTION structure
|
|
// --- Out :
|
|
// --- Returns: result of handling of the message
|
|
// --- Effect : Sends COXSHBDropTarget specific message to its owner window
|
|
LRESULT SendSHBDTMessage(UINT nMsgID, LPSHBDROPTARGETACTION pSHBDTAction)
|
|
{
|
|
ASSERT(pSHBDTAction->pWnd);
|
|
ASSERT(::IsWindow(pSHBDTAction->pWnd->GetSafeHwnd()));
|
|
ASSERT(pSHBDTAction!=NULL);
|
|
|
|
// send message to the pSHBDTAction->pWnd window which is registered as drop
|
|
// target using NMSHBDROPTARGET structure as lParam.
|
|
return pSHBDTAction->pWnd->SendMessage(nMsgID,(WPARAM)0,(LPARAM)pSHBDTAction);
|
|
}
|
|
|
|
|
|
// Overridables
|
|
|
|
//
|
|
// These members can be overridden for an OLE drop target
|
|
// See DRAG and DROP section of OLE classes reference and COleDragTarget reference
|
|
//
|
|
virtual DROPEFFECT OnDragScroll(CWnd* pWnd, DWORD dwKeyState, CPoint point)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// notify pWnd about DragScroll event
|
|
SHBDROPTARGETACTION SHBDTAction;
|
|
SHBDTAction.pWnd=pWnd;
|
|
SHBDTAction.dwKeyState=dwKeyState;
|
|
SHBDTAction.point=point;
|
|
|
|
SendSHBDTMessage(SHBDTM_DRAGSCROLL,&SHBDTAction);
|
|
|
|
// DROPEFFECT_SCROLL means do the default
|
|
if((DROPEFFECT)SHBDTAction.result!=DROPEFFECT_SCROLL)
|
|
{
|
|
return (DROPEFFECT)SHBDTAction.result;
|
|
}
|
|
|
|
if(pWnd->IsKindOf(RUNTIME_CLASS(CView)))
|
|
{
|
|
return COleDropTarget::OnDragScroll(pWnd,dwKeyState,point);
|
|
}
|
|
|
|
// get client rectangle of destination window
|
|
CRect rectClient;
|
|
pWnd->GetClientRect(&rectClient);
|
|
CRect rect=rectClient;
|
|
|
|
// hit-test against inset region
|
|
UINT nTimerID=MAKEWORD(-1, -1);
|
|
rect.InflateRect(-nScrollInset, -nScrollInset);
|
|
if(rectClient.PtInRect(point) && !rect.PtInRect(point))
|
|
{
|
|
// check if need to scroll
|
|
BOOL bHasScrollHorz=((pWnd->GetStyle()&WS_HSCROLL)==WS_HSCROLL);
|
|
BOOL bHasScrollVert=((pWnd->GetStyle()&WS_VSCROLL)==WS_VSCROLL);
|
|
SCROLLINFO scrollInfo={ sizeof(SCROLLINFO) };
|
|
|
|
if(pWnd->GetScrollInfo(SB_HORZ,&scrollInfo))
|
|
{
|
|
if(bHasScrollHorz)
|
|
{
|
|
if(scrollInfo.nMax==0 || scrollInfo.nPage==0 ||
|
|
scrollInfo.nMax<(int)scrollInfo.nPage)
|
|
{
|
|
bHasScrollHorz=FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(scrollInfo.nMax>0 && scrollInfo.nPage>0 &&
|
|
scrollInfo.nMax>=(int)scrollInfo.nPage)
|
|
{
|
|
bHasScrollHorz=TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pWnd->GetScrollInfo(SB_VERT,&scrollInfo))
|
|
{
|
|
if(bHasScrollVert)
|
|
{
|
|
if(scrollInfo.nMax==0 || scrollInfo.nPage==0 ||
|
|
scrollInfo.nMax<(int)scrollInfo.nPage)
|
|
{
|
|
bHasScrollVert=FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(scrollInfo.nMax>0 && scrollInfo.nPage>0 &&
|
|
scrollInfo.nMax>=(int)scrollInfo.nPage)
|
|
{
|
|
bHasScrollVert=TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// determine which way to scroll along both X & Y axis
|
|
if(bHasScrollHorz && point.x<rect.left)
|
|
{
|
|
nTimerID=MAKEWORD(LOBYTE(nTimerID),SB_LINEUP);
|
|
}
|
|
else if(bHasScrollHorz && point.x>=rect.right)
|
|
{
|
|
nTimerID=MAKEWORD(LOBYTE(nTimerID), SB_LINEDOWN);
|
|
}
|
|
if(bHasScrollVert && point.y<rect.top)
|
|
{
|
|
nTimerID=MAKEWORD(SB_LINEUP,HIBYTE(nTimerID));
|
|
}
|
|
else if(bHasScrollVert && point.y>=rect.bottom)
|
|
{
|
|
nTimerID=MAKEWORD(SB_LINEDOWN,HIBYTE(nTimerID));
|
|
}
|
|
}
|
|
|
|
if(nTimerID==MAKEWORD(-1,-1))
|
|
{
|
|
if(m_nTimerID!=MAKEWORD(-1,-1))
|
|
{
|
|
// send fake OnDragEnter when transition from scroll->normal
|
|
COleDataObject dataObject;
|
|
dataObject.Attach(m_lpDataObject,FALSE);
|
|
OnDragEnter(pWnd,&dataObject,dwKeyState,point);
|
|
m_nTimerID=MAKEWORD(-1,-1);
|
|
}
|
|
return DROPEFFECT_NONE;
|
|
}
|
|
|
|
// save tick count when timer ID changes
|
|
DWORD dwTick=GetTickCount();
|
|
if(nTimerID!=m_nTimerID)
|
|
{
|
|
m_dwLastTick=dwTick;
|
|
m_nScrollDelay=nScrollDelay;
|
|
}
|
|
|
|
// scroll if necessary
|
|
if((dwTick-m_dwLastTick)>m_nScrollDelay)
|
|
{
|
|
BOOL bScrollHorz=(LOBYTE(nTimerID)==-1);
|
|
if(bScrollHorz)
|
|
{
|
|
pWnd->SendMessage(
|
|
WM_HSCROLL,MAKEWPARAM(HIBYTE(nTimerID),0),(LPARAM)NULL);
|
|
}
|
|
else
|
|
{
|
|
pWnd->SendMessage(
|
|
WM_VSCROLL,MAKEWPARAM(LOBYTE(nTimerID),0),(LPARAM)NULL);
|
|
}
|
|
m_dwLastTick=dwTick;
|
|
m_nScrollDelay=nScrollInterval;
|
|
}
|
|
if (m_nTimerID == MAKEWORD(-1, -1))
|
|
{
|
|
// send fake OnDragLeave when transitioning from normal->scroll
|
|
OnDragLeave(pWnd);
|
|
}
|
|
|
|
m_nTimerID=nTimerID;
|
|
// check for force link
|
|
if((SHBDTAction.dwKeyState & (MK_CONTROL|MK_SHIFT))==(MK_CONTROL|MK_SHIFT))
|
|
{
|
|
SHBDTAction.result=(LRESULT)(DROPEFFECT_SCROLL|DROPEFFECT_LINK);
|
|
}
|
|
// check for force copy
|
|
else if((SHBDTAction.dwKeyState & MK_CONTROL)==MK_CONTROL)
|
|
{
|
|
SHBDTAction.result=(LRESULT)(DROPEFFECT_SCROLL|DROPEFFECT_COPY);
|
|
}
|
|
// check for force move
|
|
else if((SHBDTAction.dwKeyState & MK_ALT)==MK_ALT ||
|
|
(SHBDTAction.dwKeyState & MK_SHIFT)==MK_SHIFT)
|
|
{
|
|
SHBDTAction.result=(LRESULT)(DROPEFFECT_SCROLL|DROPEFFECT_MOVE);
|
|
}
|
|
// default
|
|
else
|
|
{
|
|
SHBDTAction.result=(LRESULT)(DROPEFFECT_SCROLL|DROPEFFECT_NONE);
|
|
}
|
|
|
|
return (DROPEFFECT)SHBDTAction.result;
|
|
}
|
|
|
|
|
|
virtual DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject,
|
|
DWORD dwKeyState, CPoint point)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// notify pWnd about DragEnter event
|
|
SHBDROPTARGETACTION SHBDTAction;
|
|
SHBDTAction.pWnd=pWnd;
|
|
SHBDTAction.pDataObject=pDataObject;
|
|
SHBDTAction.dwKeyState=dwKeyState;
|
|
SHBDTAction.point=point;
|
|
SHBDTAction.dropEffect=DROPEFFECT_NONE;
|
|
|
|
if(SendSHBDTMessage(SHBDTM_DRAGENTER,&SHBDTAction))
|
|
return (DROPEFFECT)SHBDTAction.result;
|
|
|
|
// default implementation
|
|
return DROPEFFECT_NONE;
|
|
}
|
|
|
|
|
|
virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject,
|
|
DWORD dwKeyState, CPoint point)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// notify pWnd about DragOver event
|
|
SHBDROPTARGETACTION SHBDTAction;
|
|
SHBDTAction.pWnd=pWnd;
|
|
SHBDTAction.pDataObject=pDataObject;
|
|
SHBDTAction.dwKeyState=dwKeyState;
|
|
SHBDTAction.point=point;
|
|
SHBDTAction.dropEffect=DROPEFFECT_NONE;
|
|
|
|
if(SendSHBDTMessage(SHBDTM_DRAGOVER,&SHBDTAction))
|
|
return (DROPEFFECT)SHBDTAction.result;
|
|
|
|
// default implementation
|
|
return DROPEFFECT_NONE;
|
|
}
|
|
|
|
|
|
virtual void OnDragLeave(CWnd* pWnd)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// notify pWnd about DragLeave event
|
|
SHBDROPTARGETACTION SHBDTAction;
|
|
SHBDTAction.pWnd=pWnd;
|
|
|
|
if(SendSHBDTMessage(SHBDTM_DRAGLEAVE,&SHBDTAction))
|
|
return;
|
|
|
|
// Call base class implementation
|
|
COleDropTarget::OnDragLeave(pWnd);
|
|
}
|
|
|
|
|
|
virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
|
|
DROPEFFECT dropEffect, CPoint point)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// notify pWnd about Drop event
|
|
SHBDROPTARGETACTION SHBDTAction;
|
|
SHBDTAction.pWnd=pWnd;
|
|
SHBDTAction.pDataObject=pDataObject;
|
|
SHBDTAction.point=point;
|
|
SHBDTAction.dropEffect=dropEffect;
|
|
|
|
if(SendSHBDTMessage(SHBDTM_DROP,&SHBDTAction))
|
|
return (BOOL)SHBDTAction.result;
|
|
|
|
// default implementation
|
|
return FALSE;
|
|
}
|
|
|
|
virtual DROPEFFECT OnDropEx(CWnd* pWnd, COleDataObject* pDataObject,
|
|
DROPEFFECT dropDefault, DROPEFFECT dropList, CPoint point)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
// notify pWnd about DropEx event
|
|
SHBDROPTARGETACTION SHBDTAction;
|
|
SHBDTAction.pWnd=pWnd;
|
|
SHBDTAction.pDataObject=pDataObject;
|
|
SHBDTAction.point=point;
|
|
SHBDTAction.dropEffect=dropDefault;
|
|
SHBDTAction.dropList=dropList;
|
|
|
|
if(SendSHBDTMessage(SHBDTM_DROPEX,&SHBDTAction))
|
|
return (DROPEFFECT)SHBDTAction.result;
|
|
|
|
// Call base class implementation
|
|
return COleDropTarget::OnDropEx(pWnd,pDataObject,dropDefault,dropList,point);
|
|
}
|
|
//
|
|
//////////////////////////////////////////////////
|
|
};
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXBaseDragDropWnd window
|
|
|
|
template<class PARENTWND>
|
|
class COXBaseDragDropWnd : public PARENTWND
|
|
{
|
|
// Construction
|
|
public:
|
|
COXBaseDragDropWnd();
|
|
|
|
// Attributes
|
|
protected:
|
|
// default COleDropSource for drag'n'drop operation
|
|
COXSHBDropSource m_oleDropSource;
|
|
// default COleDropTarget for drag'n'drop operation
|
|
COXSHBDropTarget m_oleDropTarget;
|
|
// flag that specifies if any drag and drop operation is undergoing
|
|
BOOL m_bDragDropOperation;
|
|
// flag that specifies whether this object launched current drag'n'drop
|
|
// operation or not
|
|
BOOL m_bDragDropOwner;
|
|
|
|
|
|
// Operations
|
|
public:
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns: A pointer to internal COleDropSource object
|
|
// --- Effect : Retrieves a pointer to internal COleDropSource object that will
|
|
// allow this object to handle drag'n'drop operation
|
|
virtual COleDropSource* GetDropSource()
|
|
{
|
|
// owner window must exist at that moment
|
|
ASSERT(::IsWindow(GetSafeHwnd()));
|
|
m_oleDropSource.SetOwner(this);
|
|
return &m_oleDropSource;
|
|
}
|
|
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns: TRUE if this object has started current drag'n'drop operation;
|
|
// otherwise FALSE
|
|
// --- Effect : Retrieves the flag that specifies whether this object has
|
|
// started current drag'n'drop operation
|
|
inline BOOL IsDragDropOwner() const { return m_bDragDropOwner; }
|
|
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns: A pointer to internal COleDropTarget object
|
|
// --- Effect : Retrieves a pointer to internal COleDropTarget object that will
|
|
// allow this object to handle drag'n'drop operation
|
|
virtual COleDropTarget* GetDropTarget() { return &m_oleDropTarget; }
|
|
|
|
|
|
// registers control as drop target
|
|
virtual void RegisterAsDropTarget();
|
|
|
|
|
|
protected:
|
|
// Overrides
|
|
// ClassWizard generated virtual function overrides
|
|
//{{AFX_VIRTUAL(COXBaseDragDropWnd)
|
|
//}}AFX_VIRTUAL
|
|
|
|
// Implementation
|
|
public:
|
|
virtual ~COXBaseDragDropWnd();
|
|
|
|
protected:
|
|
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
|
|
|
|
// drag and drop support
|
|
virtual LONG OnDragScroll(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDragEnter(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDragOver(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDragLeave(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDrop(WPARAM wParam, LPARAM lParam);
|
|
|
|
// drop files support
|
|
virtual void OnDropFiles(HDROP hDropInfo);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PARENTWND>
|
|
COXBaseDragDropWnd<PARENTWND>::COXBaseDragDropWnd() :
|
|
m_bDragDropOperation(FALSE),
|
|
m_bDragDropOwner(FALSE)
|
|
{
|
|
// has to be derived from CWnd or its derivates
|
|
if(!IsKindOf(RUNTIME_CLASS(CWnd)))
|
|
{
|
|
TRACE(_T("COXBaseDragDropWnd has to be derived from CWnd or its derivates\n"));
|
|
AfxThrowNotSupportedException();
|
|
}
|
|
}
|
|
|
|
|
|
template<class PARENTWND>
|
|
COXBaseDragDropWnd<PARENTWND>::~COXBaseDragDropWnd()
|
|
{
|
|
}
|
|
|
|
|
|
template<class PARENTWND>
|
|
LRESULT COXBaseDragDropWnd<PARENTWND>::WindowProc(UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
#if defined (_WINDLL)
|
|
#if defined (_AFXDLL)
|
|
AFX_MANAGE_STATE(AfxGetAppModuleState());
|
|
#else
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
#endif
|
|
#endif
|
|
|
|
LRESULT lResult=0;
|
|
|
|
switch(message)
|
|
{
|
|
case SHBDTM_DRAGSCROLL:
|
|
{
|
|
lResult=OnDragScroll(wParam,lParam);
|
|
}
|
|
break;
|
|
|
|
case SHBDTM_DRAGENTER:
|
|
{
|
|
// set flag that specifies that drag'n'drop operation is active
|
|
m_bDragDropOperation=TRUE;
|
|
lResult=OnDragEnter(wParam,lParam);
|
|
}
|
|
break;
|
|
|
|
case SHBDTM_DRAGLEAVE:
|
|
{
|
|
lResult=OnDragLeave(wParam,lParam);
|
|
// reset flag that specifies that drag'n'drop operation is active
|
|
m_bDragDropOperation=FALSE;
|
|
}
|
|
break;
|
|
|
|
case SHBDTM_DRAGOVER:
|
|
{
|
|
lResult=OnDragOver(wParam,lParam);
|
|
}
|
|
break;
|
|
|
|
case SHBDTM_DROP:
|
|
{
|
|
lResult=OnDrop(wParam,lParam);
|
|
if(!IsDragDropOwner())
|
|
{
|
|
// reset flag that specifies that drag'n'drop operation is active
|
|
m_bDragDropOperation=FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_DROPFILES:
|
|
{
|
|
OnDropFiles((HDROP)wParam);
|
|
lResult=0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
lResult=PARENTWND::WindowProc(message,wParam,lParam);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
template<class PARENTWND>
|
|
LONG COXBaseDragDropWnd<PARENTWND>::OnDragScroll(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
template<class PARENTWND>
|
|
LONG COXBaseDragDropWnd<PARENTWND>::OnDragEnter(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
template<class PARENTWND>
|
|
LONG COXBaseDragDropWnd<PARENTWND>::OnDragOver(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
template<class PARENTWND>
|
|
LONG COXBaseDragDropWnd<PARENTWND>::OnDragLeave(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
template<class PARENTWND>
|
|
LONG COXBaseDragDropWnd<PARENTWND>::OnDrop(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
template<class PARENTWND>
|
|
void COXBaseDragDropWnd<PARENTWND>::RegisterAsDropTarget()
|
|
{
|
|
COleDropTarget* pOleDropTarget=GetDropTarget();
|
|
ASSERT(pOleDropTarget!=NULL);
|
|
if(!pOleDropTarget->Register(this))
|
|
{
|
|
TRACE(_T("COXBaseDragDropWnd::RegisterAsDropTarget: failed to register with COleDropTarget object. You've probably forgotten to initialize OLE libraries using AfxOleInit() function\n"));
|
|
}
|
|
}
|
|
|
|
|
|
template<class PARENTWND>
|
|
void COXBaseDragDropWnd<PARENTWND>::OnDropFiles(HDROP hDropInfo)
|
|
{
|
|
UNREFERENCED_PARAMETER(hDropInfo);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#ifndef OXDROPDOWNTREE_AUTOEXPAND_TIMER_ID
|
|
#define OXDROPDOWNTREE_AUTOEXPAND_TIMER_ID 238
|
|
#endif
|
|
#ifndef OXDROPDOWNTREE_AUTOEXPAND_TIMER_DELAY
|
|
#define OXDROPDOWNTREE_AUTOEXPAND_TIMER_DELAY 1500
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXBaseDragDropTree window
|
|
|
|
template<class PARENTTREE>
|
|
class COXBaseDragDropTree : public COXBaseDragDropWnd<PARENTTREE>
|
|
{
|
|
// Construction
|
|
public:
|
|
COXBaseDragDropTree();
|
|
|
|
// Attributes
|
|
protected:
|
|
// timer id for autoexpansion as a result of drag'n'drop operation
|
|
UINT m_nAutoExpandTimer;
|
|
|
|
// Operations
|
|
protected:
|
|
// Overrides
|
|
// ClassWizard generated virtual function overrides
|
|
//{{AFX_VIRTUAL(COXBaseDragDropTree)
|
|
//}}AFX_VIRTUAL
|
|
|
|
// Implementation
|
|
public:
|
|
virtual ~COXBaseDragDropTree();
|
|
|
|
protected:
|
|
// drag and drop support
|
|
virtual LONG OnDragScroll(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDragEnter(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDragOver(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDragLeave(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDrop(WPARAM wParam, LPARAM lParam);
|
|
|
|
// drop files support
|
|
virtual void OnDropFiles(HDROP hDropInfo);
|
|
|
|
// drop overridables
|
|
virtual BOOL CanAcceptDrop(HTREEITEM hItem, HTREEITEM hParentItem,
|
|
BOOL bDropAfter, LPSHBDROPTARGETACTION pSHBDTAction);
|
|
virtual void AcceptDrop(HTREEITEM hItem, HTREEITEM hParentItem,
|
|
BOOL bDropAfter, LPSHBDROPTARGETACTION pSHBDTAction);
|
|
virtual BOOL CanAcceptDropFiles(HTREEITEM hItem, HTREEITEM hParentItem,
|
|
BOOL bDropAfter, HDROP hDropInfo);
|
|
virtual void AcceptDropFiles(HTREEITEM hItem, HTREEITEM hParentItem,
|
|
BOOL bDropAfter, HDROP hDropInfo);
|
|
|
|
protected:
|
|
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
|
|
};
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PARENTTREE>
|
|
COXBaseDragDropTree<PARENTTREE>::COXBaseDragDropTree() :
|
|
m_nAutoExpandTimer(0)
|
|
{
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
COXBaseDragDropTree<PARENTTREE>::~COXBaseDragDropTree()
|
|
{
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
LRESULT COXBaseDragDropTree<PARENTTREE>::WindowProc(UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
#if defined (_WINDLL)
|
|
#if defined (_AFXDLL)
|
|
AFX_MANAGE_STATE(AfxGetAppModuleState());
|
|
#else
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
#endif
|
|
#endif
|
|
|
|
LRESULT lResult=0;
|
|
|
|
switch(message)
|
|
{
|
|
case WM_TIMER:
|
|
{
|
|
if(wParam==m_nAutoExpandTimer)
|
|
{
|
|
HTREEITEM hDropItem=GetDropHilightItem();
|
|
if(hDropItem!=NULL)
|
|
{
|
|
// check if mouse is still over the drop highlighted item
|
|
CPoint ptMouse;
|
|
::GetCursorPos(&ptMouse);
|
|
ScreenToClient(&ptMouse);
|
|
UINT uiFlags=0;
|
|
HTREEITEM hHitTestItem=HitTest(ptMouse,&uiFlags);
|
|
if(hHitTestItem==hDropItem && (uiFlags & TVHT_ONITEM ))
|
|
{
|
|
// reset timer
|
|
VERIFY(KillTimer(m_nAutoExpandTimer));
|
|
m_nAutoExpandTimer=0;
|
|
// expand node
|
|
VERIFY(Expand(hDropItem,TVE_EXPAND));
|
|
}
|
|
}
|
|
lResult=0;
|
|
}
|
|
else
|
|
{
|
|
lResult=COXBaseDragDropWnd<PARENTTREE>::WindowProc(
|
|
message,wParam,lParam);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
lResult=COXBaseDragDropWnd<PARENTTREE>::WindowProc(message,wParam,lParam);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
LONG COXBaseDragDropTree<PARENTTREE>::OnDragScroll(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(COXBaseDragDropWnd<PARENTTREE>::OnDragScroll(wParam,lParam))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// lParam is the pointer to SHBDROPTARGETACTION structure
|
|
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
|
|
ASSERT(pSHBDTAction!=NULL);
|
|
|
|
ASSERT(pSHBDTAction->pWnd);
|
|
ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());
|
|
|
|
pSHBDTAction->result=(LRESULT)DROPEFFECT_SCROLL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
LONG COXBaseDragDropTree<PARENTTREE>::OnDragEnter(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(COXBaseDragDropWnd<PARENTTREE>::OnDragEnter(wParam,lParam))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return OnDragOver(wParam,lParam);
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
LONG COXBaseDragDropTree<PARENTTREE>::OnDragOver(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(COXBaseDragDropWnd<PARENTTREE>::OnDragOver(wParam,lParam))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// lParam is the pointer to SHBDROPTARGETACTION structure
|
|
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
|
|
ASSERT(pSHBDTAction!=NULL);
|
|
|
|
ASSERT(pSHBDTAction->pWnd);
|
|
ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());
|
|
|
|
// Check if the control key was pressed
|
|
if((pSHBDTAction->dwKeyState & MK_CONTROL)==MK_CONTROL)
|
|
{
|
|
pSHBDTAction->result=(LRESULT)DROPEFFECT_COPY;
|
|
}
|
|
else
|
|
{
|
|
pSHBDTAction->result=(LRESULT)DROPEFFECT_MOVE;
|
|
}
|
|
|
|
BOOL bAcceptDrop=FALSE;
|
|
|
|
UINT uFlags=0;
|
|
// get the item that is below cursor
|
|
HTREEITEM hDropItem=HitTest(pSHBDTAction->point,&uFlags);
|
|
if(hDropItem!=NULL)
|
|
{
|
|
HTREEITEM hOldDropItem=GetDropHilightItem();
|
|
if(hOldDropItem!=hDropItem)
|
|
{
|
|
// reset the timer for autoexpansion
|
|
if(m_nAutoExpandTimer!=0)
|
|
{
|
|
KillTimer(m_nAutoExpandTimer);
|
|
m_nAutoExpandTimer=0;
|
|
}
|
|
|
|
// highlight it
|
|
SelectDropTarget(hDropItem);
|
|
|
|
if((GetItemState(hDropItem,TVIS_EXPANDED) & TVIS_EXPANDED)==0 &&
|
|
ItemHasChildren(hDropItem))
|
|
{
|
|
m_nAutoExpandTimer=SetTimer(OXDROPDOWNTREE_AUTOEXPAND_TIMER_ID,
|
|
OXDROPDOWNTREE_AUTOEXPAND_TIMER_DELAY,NULL);
|
|
ASSERT(m_nAutoExpandTimer==OXDROPDOWNTREE_AUTOEXPAND_TIMER_ID);
|
|
}
|
|
}
|
|
|
|
// check if this item accepts drop operation
|
|
HTREEITEM hParentItem=GetParentItem(hDropItem);
|
|
CRect rectItem;
|
|
GetItemRect(hDropItem,rectItem,FALSE);
|
|
bAcceptDrop=CanAcceptDrop(hDropItem,hParentItem,
|
|
(pSHBDTAction->point.y > rectItem.top+rectItem.Height()/2),pSHBDTAction);
|
|
}
|
|
else
|
|
{
|
|
// no item to drop on, ask root item to insert as last child
|
|
bAcceptDrop=CanAcceptDrop(TVI_LAST,TVI_ROOT,TRUE,pSHBDTAction);
|
|
}
|
|
|
|
if(!bAcceptDrop)
|
|
{
|
|
pSHBDTAction->result=(LRESULT)DROPEFFECT_NONE;
|
|
}
|
|
|
|
return bAcceptDrop;
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
LONG COXBaseDragDropTree<PARENTTREE>::OnDragLeave(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(COXBaseDragDropWnd<PARENTTREE>::OnDragLeave(wParam,lParam))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
SelectDropTarget(NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
LONG COXBaseDragDropTree<PARENTTREE>::OnDrop(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(COXBaseDragDropWnd<PARENTTREE>::OnDrop(wParam,lParam))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// lParam is the pointer to SHBDROPTARGETACTION structure
|
|
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
|
|
ASSERT(pSHBDTAction!=NULL);
|
|
|
|
ASSERT(pSHBDTAction->pWnd);
|
|
ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());
|
|
|
|
pSHBDTAction->result=(LRESULT)FALSE;
|
|
|
|
// if dragged item is to be copied or moved
|
|
if((pSHBDTAction->dropEffect&DROPEFFECT_COPY)!=0 ||
|
|
(pSHBDTAction->dropEffect&DROPEFFECT_MOVE)!=0)
|
|
{
|
|
UINT uFlags=0;
|
|
HTREEITEM hDropItem=HitTest(pSHBDTAction->point,&uFlags);
|
|
if(hDropItem!=NULL)
|
|
{
|
|
ASSERT(hDropItem==GetDropHilightItem());
|
|
|
|
// remove highlight
|
|
SelectDropTarget(NULL);
|
|
|
|
// check if this item accepts drop operation
|
|
HTREEITEM hParentItem=GetParentItem(hDropItem);
|
|
CRect rectItem;
|
|
GetItemRect(hDropItem,rectItem,FALSE);
|
|
if(CanAcceptDrop(hDropItem,hParentItem,
|
|
(pSHBDTAction->point.y > rectItem.top+rectItem.Height()/2),
|
|
pSHBDTAction))
|
|
{
|
|
AcceptDrop(hDropItem,hParentItem,
|
|
(pSHBDTAction->point.y > rectItem.top+rectItem.Height()/2),
|
|
pSHBDTAction);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no item to drop on, ask root item to insert as last child
|
|
if(CanAcceptDrop(TVI_LAST,TVI_ROOT,TRUE,pSHBDTAction))
|
|
{
|
|
AcceptDrop(TVI_LAST,TVI_ROOT,TRUE,pSHBDTAction);
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
void COXBaseDragDropTree<PARENTTREE>::OnDropFiles(HDROP hDropInfo)
|
|
{
|
|
// retrieve number of files
|
|
UINT nFileCount=::DragQueryFile(hDropInfo,(UINT)-1,NULL,0);
|
|
|
|
if(nFileCount>0)
|
|
{
|
|
CPoint ptDrop;
|
|
if(::DragQueryPoint(hDropInfo,&ptDrop))
|
|
{
|
|
// analyze drop position
|
|
UINT uFlags=0;
|
|
HTREEITEM hDropItem=HitTest(ptDrop,&uFlags);
|
|
if(hDropItem!=NULL)
|
|
{
|
|
// check if this item accepts drop operation
|
|
HTREEITEM hParentItem=GetParentItem(hDropItem);
|
|
CRect rectItem;
|
|
GetItemRect(hDropItem,rectItem,FALSE);
|
|
if(CanAcceptDropFiles(hDropItem,hParentItem,
|
|
(ptDrop.y > rectItem.top+rectItem.Height()/2),hDropInfo))
|
|
{
|
|
AcceptDropFiles(hDropItem,hParentItem,
|
|
(ptDrop.y > rectItem.top+rectItem.Height()/2),hDropInfo);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no item to drop on, ask root item to insert as last child
|
|
if(CanAcceptDropFiles(TVI_LAST,TVI_ROOT,TRUE,hDropInfo))
|
|
{
|
|
AcceptDropFiles(TVI_LAST,TVI_ROOT,TRUE,hDropInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
::DragFinish(hDropInfo);
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
BOOL COXBaseDragDropTree<PARENTTREE>::CanAcceptDrop(HTREEITEM hItem,
|
|
HTREEITEM hParentItem,
|
|
BOOL bDropAfter,
|
|
LPSHBDROPTARGETACTION pSHBDTAction)
|
|
{
|
|
UNREFERENCED_PARAMETER(hItem);
|
|
UNREFERENCED_PARAMETER(hParentItem);
|
|
UNREFERENCED_PARAMETER(bDropAfter);
|
|
UNREFERENCED_PARAMETER(pSHBDTAction);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
void COXBaseDragDropTree<PARENTTREE>::AcceptDrop(HTREEITEM hItem,
|
|
HTREEITEM hParentItem,
|
|
BOOL bDropAfter,
|
|
LPSHBDROPTARGETACTION pSHBDTAction)
|
|
{
|
|
UNREFERENCED_PARAMETER(hItem);
|
|
UNREFERENCED_PARAMETER(hParentItem);
|
|
UNREFERENCED_PARAMETER(bDropAfter);
|
|
UNREFERENCED_PARAMETER(pSHBDTAction);
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
BOOL COXBaseDragDropTree<PARENTTREE>::CanAcceptDropFiles(HTREEITEM hItem,
|
|
HTREEITEM hParentItem,
|
|
BOOL bDropAfter,
|
|
HDROP hDropInfo)
|
|
{
|
|
UNREFERENCED_PARAMETER(hItem);
|
|
UNREFERENCED_PARAMETER(hParentItem);
|
|
UNREFERENCED_PARAMETER(bDropAfter);
|
|
UNREFERENCED_PARAMETER(hDropInfo);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
template<class PARENTTREE>
|
|
void COXBaseDragDropTree<PARENTTREE>::AcceptDropFiles(HTREEITEM hItem,
|
|
HTREEITEM hParentItem,
|
|
BOOL bDropAfter,
|
|
HDROP hDropInfo)
|
|
{
|
|
UNREFERENCED_PARAMETER(hItem);
|
|
UNREFERENCED_PARAMETER(hParentItem);
|
|
UNREFERENCED_PARAMETER(bDropAfter);
|
|
UNREFERENCED_PARAMETER(hDropInfo);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXBaseDragDropList window
|
|
|
|
template<class PARENTLIST>
|
|
class COXBaseDragDropList : public COXBaseDragDropWnd<PARENTLIST>
|
|
{
|
|
// Construction
|
|
public:
|
|
COXBaseDragDropList();
|
|
|
|
// Attributes
|
|
protected:
|
|
|
|
// Operations
|
|
protected:
|
|
// Overrides
|
|
// ClassWizard generated virtual function overrides
|
|
//{{AFX_VIRTUAL(COXBaseDragDropList)
|
|
//}}AFX_VIRTUAL
|
|
|
|
// Implementation
|
|
public:
|
|
virtual ~COXBaseDragDropList();
|
|
|
|
protected:
|
|
// drag and drop support
|
|
virtual LONG OnDragScroll(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDragEnter(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDragOver(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDragLeave(WPARAM wParam, LPARAM lParam);
|
|
virtual LONG OnDrop(WPARAM wParam, LPARAM lParam);
|
|
|
|
// drop files support
|
|
virtual void OnDropFiles(HDROP hDropInfo);
|
|
|
|
// drop overridables
|
|
virtual BOOL CanAcceptDrop(
|
|
int nItemIndex, BOOL bDropAfter, LPSHBDROPTARGETACTION pSHBDTAction);
|
|
virtual void AcceptDrop(
|
|
int nItemIndex, BOOL bDropAfter, LPSHBDROPTARGETACTION pSHBDTAction);
|
|
virtual BOOL CanAcceptDropFiles(
|
|
int nItemIndex, BOOL bDropAfter, HDROP hDropInfo);
|
|
virtual void AcceptDropFiles(
|
|
int nItemIndex, BOOL bDropAfter, HDROP hDropInfo);
|
|
};
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class PARENTLIST>
|
|
COXBaseDragDropList<PARENTLIST>::COXBaseDragDropList()
|
|
{
|
|
}
|
|
|
|
|
|
template<class PARENTLIST>
|
|
COXBaseDragDropList<PARENTLIST>::~COXBaseDragDropList()
|
|
{
|
|
}
|
|
|
|
|
|
template<class PARENTLIST>
|
|
LONG COXBaseDragDropList<PARENTLIST>::OnDragScroll(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(COXBaseDragDropWnd<PARENTLIST>::OnDragScroll(wParam,lParam))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// lParam is the pointer to SHBDROPTARGETACTION structure
|
|
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
|
|
ASSERT(pSHBDTAction!=NULL);
|
|
|
|
ASSERT(pSHBDTAction->pWnd);
|
|
ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());
|
|
|
|
pSHBDTAction->result=(LRESULT)DROPEFFECT_SCROLL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
template<class PARENTLIST>
|
|
LONG COXBaseDragDropList<PARENTLIST>::OnDragEnter(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(COXBaseDragDropWnd<PARENTLIST>::OnDragEnter(wParam,lParam))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return OnDragOver(wParam,lParam);
|
|
}
|
|
|
|
|
|
template<class PARENTLIST>
|
|
LONG COXBaseDragDropList<PARENTLIST>::OnDragOver(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(COXBaseDragDropWnd<PARENTLIST>::OnDragOver(wParam,lParam))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// lParam is the pointer to SHBDROPTARGETACTION structure
|
|
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
|
|
ASSERT(pSHBDTAction!=NULL);
|
|
|
|
ASSERT(pSHBDTAction->pWnd);
|
|
ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());
|
|
|
|
// Check if the control key was pressed
|
|
if((pSHBDTAction->dwKeyState & MK_CONTROL)==MK_CONTROL)
|
|
{
|
|
pSHBDTAction->result=(LRESULT)DROPEFFECT_COPY;
|
|
}
|
|
else
|
|
{
|
|
pSHBDTAction->result=(LRESULT)DROPEFFECT_MOVE;
|
|
}
|
|
|
|
BOOL bAcceptDrop=FALSE;
|
|
|
|
UINT uFlags=0;
|
|
// get the item that is below cursor
|
|
int nItemIndex=HitTest(pSHBDTAction->point,&uFlags);
|
|
if(nItemIndex!=-1)
|
|
{
|
|
int nDropItemIndex=GetNextItem(-1,LVNI_DROPHILITED);
|
|
if(nDropItemIndex!=nItemIndex)
|
|
{
|
|
SetItemState(nDropItemIndex,0,LVIS_DROPHILITED);
|
|
SetItemState(nItemIndex,LVIS_DROPHILITED,LVIS_DROPHILITED);
|
|
}
|
|
|
|
CRect rectItem;
|
|
GetItemRect(nItemIndex,rectItem,LVIR_BOUNDS);
|
|
bAcceptDrop=CanAcceptDrop(nItemIndex,
|
|
(pSHBDTAction->point.y > rectItem.top+rectItem.Height()/2),pSHBDTAction);
|
|
}
|
|
else
|
|
{
|
|
// no item to drop on, ask to insert as last item
|
|
bAcceptDrop=CanAcceptDrop(GetItemCount(),FALSE,pSHBDTAction);
|
|
}
|
|
|
|
if(!bAcceptDrop)
|
|
{
|
|
pSHBDTAction->result=(LRESULT)DROPEFFECT_NONE;
|
|
}
|
|
|
|
return bAcceptDrop;
|
|
}
|
|
|
|
|
|
template<class PARENTLIST>
|
|
LONG COXBaseDragDropList<PARENTLIST>::OnDragLeave(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(COXBaseDragDropWnd<PARENTLIST>::OnDragLeave(wParam,lParam))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
int nDropItemIndex=GetNextItem(-1,LVNI_DROPHILITED);
|
|
if(nDropItemIndex!=-1)
|
|
{
|
|
// remove highlight
|
|
SetItemState(nDropItemIndex,0,LVIS_DROPHILITED);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
template<class PARENTLIST>
|
|
LONG COXBaseDragDropList<PARENTLIST>::OnDrop(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(COXBaseDragDropWnd<PARENTLIST>::OnDrop(wParam,lParam))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// lParam is the pointer to SHBDROPTARGETACTION structure
|
|
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
|
|
ASSERT(pSHBDTAction!=NULL);
|
|
|
|
ASSERT(pSHBDTAction->pWnd);
|
|
ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());
|
|
|
|
pSHBDTAction->result=(LRESULT)FALSE;
|
|
|
|
// if dragged item is to be copied or moved
|
|
if((pSHBDTAction->dropEffect&DROPEFFECT_COPY)!=0 ||
|
|
(pSHBDTAction->dropEffect&DROPEFFECT_MOVE)!=0)
|
|
{
|
|
UINT uFlags=0;
|
|
int nDropItemIndex=HitTest(pSHBDTAction->point,&uFlags);
|
|
if(nDropItemIndex!=-1)
|
|
{
|
|
ASSERT(nDropItemIndex==GetNextItem(-1,LVNI_DROPHILITED));
|
|
// remove highlight
|
|
SetItemState(nDropItemIndex,0,LVIS_DROPHILITED);
|
|
|
|
// check if this item accepts drop operation
|
|
CRect rectItem;
|
|
GetItemRect(nDropItemIndex,rectItem,LVIR_BOUNDS);
|
|
if(CanAcceptDrop(nDropItemIndex,
|
|
(pSHBDTAction->point.y > rectItem.top+rectItem.Height()/2),
|
|
pSHBDTAction))
|
|
{
|
|
AcceptDrop(nDropItemIndex,
|
|
(pSHBDTAction->point.y > rectItem.top+rectItem.Height()/2),
|
|
pSHBDTAction);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no item to drop on, ask to insert as last item
|
|
if(CanAcceptDrop(GetItemCount(),FALSE,pSHBDTAction))
|
|
{
|
|
AcceptDrop(GetItemCount(),FALSE,pSHBDTAction);
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
template<class PARENTLIST>
|
|
void COXBaseDragDropList<PARENTLIST>::OnDropFiles(HDROP hDropInfo)
|
|
{
|
|
// retrieve number of files
|
|
UINT nFileCount=::DragQueryFile(hDropInfo,(UINT)-1,NULL,0);
|
|
|
|
if(nFileCount>0)
|
|
{
|
|
CPoint ptDrop;
|
|
if(::DragQueryPoint(hDropInfo,&ptDrop))
|
|
{
|
|
// analyze drop position
|
|
UINT uFlags=0;
|
|
int nDropItemIndex=HitTest(ptDrop,&uFlags);
|
|
if(nDropItemIndex!=-1)
|
|
{
|
|
// check if this item accepts drop operation
|
|
CRect rectItem;
|
|
GetItemRect(nDropItemIndex,rectItem,LVIR_BOUNDS);
|
|
if(CanAcceptDropFiles(nDropItemIndex,
|
|
(ptDrop.y > rectItem.top+rectItem.Height()/2),hDropInfo))
|
|
{
|
|
AcceptDropFiles(nDropItemIndex,
|
|
(ptDrop.y > rectItem.top+rectItem.Height()/2),hDropInfo);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no item to drop on, ask to insert as last item
|
|
if(CanAcceptDropFiles(GetItemCount(),FALSE,hDropInfo))
|
|
{
|
|
AcceptDropFiles(GetItemCount(),FALSE,hDropInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
::DragFinish(hDropInfo);
|
|
}
|
|
|
|
|
|
template<class PARENTLIST>
|
|
BOOL COXBaseDragDropList<PARENTLIST>::CanAcceptDrop(int nItemIndex,
|
|
BOOL bDropAfter,
|
|
LPSHBDROPTARGETACTION pSHBDTAction)
|
|
{
|
|
UNREFERENCED_PARAMETER(nItemIndex);
|
|
UNREFERENCED_PARAMETER(bDropAfter);
|
|
UNREFERENCED_PARAMETER(pSHBDTAction);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
template<class PARENTLIST>
|
|
void COXBaseDragDropList<PARENTLIST>::AcceptDrop(int nItemIndex,
|
|
BOOL bDropAfter,
|
|
LPSHBDROPTARGETACTION pSHBDTAction)
|
|
{
|
|
UNREFERENCED_PARAMETER(nItemIndex);
|
|
UNREFERENCED_PARAMETER(bDropAfter);
|
|
UNREFERENCED_PARAMETER(pSHBDTAction);
|
|
}
|
|
|
|
|
|
template<class PARENTLIST>
|
|
BOOL COXBaseDragDropList<PARENTLIST>::CanAcceptDropFiles(int nItemIndex,
|
|
BOOL bDropAfter,
|
|
HDROP hDropInfo)
|
|
{
|
|
UNREFERENCED_PARAMETER(nItemIndex);
|
|
UNREFERENCED_PARAMETER(bDropAfter);
|
|
UNREFERENCED_PARAMETER(hDropInfo);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
template<class PARENTLIST>
|
|
void COXBaseDragDropList<PARENTLIST>::AcceptDropFiles(int nItemIndex,
|
|
BOOL bDropAfter,
|
|
HDROP hDropInfo)
|
|
{
|
|
UNREFERENCED_PARAMETER(nItemIndex);
|
|
UNREFERENCED_PARAMETER(bDropAfter);
|
|
UNREFERENCED_PARAMETER(hDropInfo);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//{{AFX_INSERT_LOCATION}}
|
|
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
|
|
|
|
#endif // !defined(_OX_DRAGDROPSUPPORT_)
|