From 08a2a60993f9f9e313501feb1aaad67bb3f91d5e Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Fri, 2 Dec 2005 13:00:01 +0100 Subject: [PATCH] Implemented scrolling during drag&drop for the shellview class. --- dlls/shell32/shlview.c | 69 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/dlls/shell32/shlview.c b/dlls/shell32/shlview.c index 0c85aed677c..99ca8629f3b 100644 --- a/dlls/shell32/shlview.c +++ b/dlls/shell32/shlview.c @@ -103,6 +103,7 @@ typedef struct IDropTarget* pCurDropTarget; /* The sub-item, which is currently dragged over */ IDataObject* pCurDataObject; /* The dragged data-object */ LONG iDragOverItem; /* Dragged over item's index, iff pCurDropTarget != NULL */ + UINT iActiveTimersMask; /* Bookkeeping of activated timers for drag scrolling */ } IShellViewImpl; static const IShellViewVtbl svvt; @@ -196,6 +197,7 @@ IShellView * IShellView_Constructor( IShellFolder * pFolder) sv->pCurDropTarget = NULL; sv->pCurDataObject = NULL; sv->iDragOverItem = 0; + sv->iActiveTimersMask = 0; TRACE("(%p)->(%p)\n",sv, pFolder); return (IShellView *) sv; @@ -2176,12 +2178,57 @@ static ULONG WINAPI ISVDropTarget_Release( IDropTarget *iface) return IShellFolder_Release((IShellFolder*)This); } +/****************************************************************************** + * scroll_timer_proc [Internal] + * + * Timer callback function for drag&drop scrolling + */ + +#define IDT_UP 0x1u +#define IDT_DOWN 0x2u +#define IDT_LEFT 0x4u +#define IDT_RIGHT 0x8u + +VOID CALLBACK scroll_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idTimer, DWORD dwTimer) { + switch (idTimer) { + case IDT_UP: + SendMessageW(hwnd, WM_VSCROLL, SB_LINEUP, 0); + break; + case IDT_DOWN: + SendMessageW(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); + break; + case IDT_LEFT: + SendMessageW(hwnd, WM_HSCROLL, SB_LINEUP, 0); + break; + case IDT_RIGHT: + SendMessageW(hwnd, WM_HSCROLL, SB_LINEDOWN, 0); + break; + } +} + +/****************************************************************************** + * start_stop_timer [Internal] + */ +static inline void start_stop_timer(IShellViewImpl *This, UINT_PTR idTimer, BOOL fStart) { + if (fStart && !(This->iActiveTimersMask & idTimer)) { + SetTimer(This->hWndList, idTimer, 200, scroll_timer_proc); + This->iActiveTimersMask |= idTimer; + } + if (!fStart && This->iActiveTimersMask & idTimer) { + KillTimer(This->hWndList, idTimer); + This->iActiveTimersMask &= ~idTimer; + } +} + /****************************************************************************** * drag_notify_subitem [Internal] * * Figure out the shellfolder object, which is currently under the mouse cursor * and notify it via the IDropTarget interface. */ + +#define SCROLLAREAWIDTH 20 + static HRESULT drag_notify_subitem(IShellViewImpl *This, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { @@ -2189,15 +2236,23 @@ static HRESULT drag_notify_subitem(IShellViewImpl *This, DWORD grfKeyState, POIN LVITEMA lvItem; LONG lResult; HRESULT hr; + RECT clientRect; /* Map from global to client coordinates and query the index of the listview-item, which is * currently under the mouse cursor. */ htinfo.pt.x = pt.x; htinfo.pt.y = pt.y; htinfo.flags = LVHT_ONITEM; - MapWindowPoints(NULL, This->hWndList, &htinfo.pt, 1); + ScreenToClient(This->hWndList, &htinfo.pt); lResult = SendMessageW(This->hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo); + /* Start or stop the drag scrolling timers */ + GetClientRect(This->hWndList, &clientRect); + start_stop_timer(This, IDT_LEFT, htinfo.pt.x < SCROLLAREAWIDTH); + start_stop_timer(This, IDT_RIGHT, htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH); + start_stop_timer(This, IDT_UP, htinfo.pt.y < SCROLLAREAWIDTH); + start_stop_timer(This, IDT_DOWN, htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH); + /* If we are still over the previous sub-item, notify it via DragOver and return. */ if (This->pCurDropTarget && lResult == This->iDragOverItem) return IDropTarget_DragOver(This->pCurDropTarget, grfKeyState, pt, pdwEffect); @@ -2265,7 +2320,12 @@ static HRESULT WINAPI ISVDropTarget_DragLeave(IDropTarget *iface) { This->pCurDataObject = NULL; This->pCurDropTarget = NULL; This->iDragOverItem = 0; - + + start_stop_timer(This, IDT_LEFT, FALSE); + start_stop_timer(This, IDT_RIGHT, FALSE); + start_stop_timer(This, IDT_UP, FALSE); + start_stop_timer(This, IDT_DOWN, FALSE); + return S_OK; } @@ -2282,6 +2342,11 @@ static HRESULT WINAPI ISVDropTarget_Drop(IDropTarget *iface, IDataObject* pDataO This->pCurDropTarget = NULL; This->iDragOverItem = 0; + start_stop_timer(This, IDT_LEFT, FALSE); + start_stop_timer(This, IDT_RIGHT, FALSE); + start_stop_timer(This, IDT_UP, FALSE); + start_stop_timer(This, IDT_DOWN, FALSE); + return S_OK; }