How can I enable dragging cells with right mouse button and display a popup-menu when the user release the mouse button? In the popup-menu I would like the user to give the option to copy or move the cells.
Here is the steps how to implement this behavior:
a) Add the following menu resource to your resource file:
IDR_MENU_DNDACTION MENU DISCARDABLE
BEGIN
POPUP "Drop Action"
BEGIN
MENUITEM "&Copy", ID_DND_COPY
MENUITEM "&Move", ID_DND_MOVE
END
END
b) Next, add the following handlers to the message map of your grid view
ON_WM_RBUTTONDOWN()
ON_COMMAND(ID_DND_MOVE, OnDndMove)
ON_COMMAND(ID_DND_COPY, OnDndCopy)
c) In your header file, add the following attributes and overrides:
// Attributes
BOOL m_bRButton;
UINT m_nDndAction;
// Operations
virtual BOOL OnGridDrop(CGXNoOleDataObjectProxy* pDataObject,
DROPEFFECT dropEffect, CPoint point);
virtual BOOL DndDropActionMenu(CGXNoOleDataObjectProxy* pDataObject,
DROPEFFECT dropEffect, CPoint point);
// Generated message map functions
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg void OnDndMove();
afx_msg void OnDndCopy();
d) Here are the implementation of this functions:
void C1stGridView::OnRButtonDown(UINT nFlags, CPoint point)
{
if (GetCapture() == NULL)
{
CRect rectHit;
ROWCOL nRow, nCol;
int ht = HitTest(point, &nRow, &nCol);
if (ht == GX_SELEDGEHIT)
{
if (m_nDndFlags)
{
ROWCOL ncRow = nRow;
ROWCOL ncCol = nCol;
CGXRange rgCovered(nRow, nCol);
if (GetCoveredCellsRowCol(nRow, nCol, rgCovered))
{
ncRow = rgCovered.top;
ncCol = rgCovered.left;
}
m_bRButton = TRUE;
BOOL b = DndStartDragDrop(ncRow, ncCol);
m_bRButton = FALSE;
if (b)
return;
}
}
}
// check, if user clicked on a header or cell in the grid
CGXGridView::OnRButtonDown(nFlags, point);
}
BOOL C1stGridView::OnGridDrop(CGXNoOleDataObjectProxy* pDataObject,
DROPEFFECT dropEffect, CPoint point)
{
// Kill the timer started in OnGridDragEnter.
if (!m_bDndGlobalTimer && m_dwDndDropTargetFlags & GX_DNDEGDESCROLL)
m_pGridWnd->KillTimer(GX_TIMER_DNDSCROLLOTHER);
// kill timer for this window
if (m_bDndGlobalTimer)
{
m_pGridWnd->KillTimer(GX_TIMER_DNDSCROLLSELF);
m_bDndGlobalTimer = FALSE;
}
if (m_bRButton)
dropEffect = DndDropActionMenu(pDataObject, dropEffect, point);
return CGXGridCore::OnGridDrop(pDataObject, dropEffect, point);
}
BOOL C1stGridView::DndDropActionMenu(CGXNoOleDataObjectProxy* pDataObject,
DROPEFFECT dropEffect, CPoint pt)
{
if (dropEffect == DROPEFFECT_MOVE)
{
CMenu CopyMoveMenu;
m_nDndAction = 0;
CopyMoveMenu.LoadMenu(IDR_MENU_DNDACTION);
CMenu* pPopup = CopyMoveMenu.GetSubMenu(0);
ClientToScreen(&pt);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
pt.x, pt.y, this, NULL);
MSG msg;
while (::PeekMessage(&msg, m_hWnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
switch (m_nDndAction)
{
case ID_DND_COPY: dropEffect = DROPEFFECT_COPY; break;
case ID_DND_MOVE: dropEffect = DROPEFFECT_MOVE; break;
default: dropEffect = DROPEFFECT_NONE; break;
}
}
return dropEffect;
}
void C1stGridView::OnDndMove()
{
m_nDndAction = ID_DND_MOVE;
}
void C1stGridView::OnDndCopy()
{
m_nDndAction = ID_DND_COPY;
}