On Tue, 2005-01-11 at 04:20, Jez White wrote: > Hi, > > >From what I understand of dragging (which isn't a lot!) most of the > functionality that you would need for this explorer example is present > within Win32::GUI at the moment.
> Basically, dragging is a very manual process - you have to do most of the > work - and I think most of the methods to do this work is part of the > imagelist control (BeginDrag, DragEnter,DragMove and EndDrag). You have to > work out when the user starts the drag, when they finish, so on Hi All, dragging, found this.... frightening but here goes... On WM_LBUTTONDOWN If dragging begins over an item, the list-view control selects and sets the focus to the item. Then it sends an LVN_BEGINDRAG notification message to the parent window. The parent window is responsible for actually carrying out the drag operation. If dragging begins over the window background, the list-view control enters another modal message loop, enabling the user to form a rectangle by dragging the mouse. Items within the rectangle are selected. On WM_RBUTTONDOWN Processed the same way as the WM_LBUTTONDOWN message, except that the control sends an NM_RCLICK notification message (instead of NM_CLICK (list view)) and an LVN_BEGINRDRAG notification message (instead of LVN_BEGINDRAG). Note that the control processes the corresponding WM_RBUTTONUP message, and does not dispatch it. Applications thus cannot see this message, even by subclassing the control. All the below codes are assumed to be in your MainWndProc() function. When user keeps pressing the mouse button down, and moves his mouse a little, a notification message (LVN_BEGINDRAG) will be sent to your MainWndProc() via WM_NOTIFY. You should handle this message by: 1. Create a drag-image for all selected items. ListView provides a function to create a single-row drag-image. We will use this function to create multiple drag-images for each row, and merge them together. 2. Call ImageList_Begin to initialize a drag-and-drop, then ImageList_DragEnter to start a drag action. You must call SetCapture() to get the subsequent mouse message inside your application. Example code segment: case WM_NOTIFY: switch (((LPNMHDR)lParam)->code) { case LVN_BEGINDRAG: // You can set your customized cursor here p.x = 8; p.y = 8; // Ok, now we create a drag-image for all selected items bFirst = TRUE; iPos = ListView_GetNextItem(hListView, -1, LVNI_SELECTED); while (iPos != -1) { if (bFirst) { // For the first selected item, // we simply create a single-line drag image hDragImageList = ListView_CreateDragImage(hListView, iPos, &p); ImageList_GetImageInfo(hDragImageList, 0, &imf); iHeight = imf.rcImage.bottom; bFirst = FALSE; }else { // For the rest selected items, // we create a single-line drag image, then // append it to the bottom of the complete drag image hOneImageList = ListView_CreateDragImage(hListView, iPos, &p); hTempImageList = ImageList_Merge(hDragImageList, 0, hOneImageList, 0, 0, iHeight); ImageList_Destroy(hDragImageList); ImageList_Destroy(hOneImageList); hDragImageList = hTempImageList; ImageList_GetImageInfo(hDragImageList, 0, &imf); iHeight = imf.rcImage.bottom; } iPos = ListView_GetNextItem(hListView, iPos, LVNI_SELECTED); } // Now we can initialize then start the drag action ImageList_BeginDrag(hDragImageList, 0, 0, 0); pt = ((NM_LISTVIEW*) ((LPNMHDR)lParam))->ptAction; ClientToScreen(hListView, &pt); ImageList_DragEnter(GetDesktopWindow(), pt.x, pt.y); bDragging = TRUE; // Don't forget to capture the mouse SetCapture(hWndMain); break; Then we handle WM_MOUSEMOVE message to move the drag-image along the mouse movement. There is no need to explain the example code segment: case WM_MOUSEMOVE: if (!bDragging) break; p.x = LOWORD(lParam); p.y = HIWORD(lParam); ClientToScreen(hWndMain, &p); ImageList_DragMove(p.x, p.y); break; OK, now we reach the final step. When user releases the mouse button, we will end the drag-and-drop action and do the rearrangement work. 1. Call ImageList_DragLeave and Image_EndDrag to end the drag-and-drop process. Don't forget to release the mouse capture and destroy the drag image to free the memory it uses. 2. Determine the item onto where the user drops the selected items. If the dropped item is selected, you should terminate. 3. Move all the selected items to the dropped item's position by copying and deleting. Here's the example code segment: case WM_LBUTTONUP: // End the drag-and-drop process bDragging = FALSE; ImageList_DragLeave(hListView); ImageList_EndDrag(); ImageList_Destroy(hDragImageList); ReleaseCapture(); // Determine the dropped item lvhti.pt.x = LOWORD(lParam); lvhti.pt.y = HIWORD(lParam); ClientToScreen(hWndMain, &lvhti.pt); ScreenToClient(hListView, &lvhti.pt); ListView_HitTest(hListView, &lvhti); // Out of the ListView? if (lvhti.iItem == -1) break; // Not in an item? if ((lvhti.flags & LVHT_ONITEMLABEL == 0) && (lvhti.flags & LVHT_ONITEMSTATEICON == 0)) break; // Dropped item is selected? lvi.iItem = lvhti.iItem; lvi.iSubItem = 0; lvi.mask = LVIF_STATE; lvi.stateMask = LVIS_SELECTED; ListView_GetItem(hListView, &lvi); if (lvi.state & LVIS_SELECTED) break; // Rearrange the items iPos = ListView_GetNextItem(hListView, -1, LVNI_SELECTED); while (iPos != -1) { // First, copy one item lvi.iItem = iPos; lvi.iSubItem = 0; lvi.cchTextMax = MAX_TARGET_LEN; lvi.pszText = buf; lvi.stateMask = ~LVIS_SELECTED; lvi.mask = LVIF_STATE | LVIF_IMAGE | LVIF_INDENT | LVIF_PARAM | LVIF_TEXT; ListView_GetItem(hListView, &lvi); lvi.iItem = lvhti.iItem; // Insert the main item iRet = ListView_InsertItem(hListView, &lvi); if (lvi.iItem < iPos) lvhti.iItem++; if (iRet <= iPos) iPos++; // Set the subitem text for (i = 1; i < JOB_WIN_COLUMN_NUM; i++) { ListView_GetItemText(hListView, iPos, i, buf, MAX_TARGET_LEN); ListView_SetItemText(hListView, iRet, i, buf); } // Delete from original position ListView_DeleteItem(hListView, iPos); iPos = ListView_GetNextItem(hListView, -1, LVNI_SELECTED); } break; Here are variable definitions: int iHeight; static HIMAGELIST hDragImageList; HIMAGELIST hOneImageList, hTempImageList; LPNMHDR pnmhdr; static BOOL bDragging; LVHITTESTINFO lvhti; BOOL bFirst; IMAGEINFO imf; And of course, hListView and hMainWnd are HWND variables.