From dd729639494ac6e7144836be1cff89f91f05e7d6 Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Tue, 9 Mar 2004 23:26:44 +0000 Subject: [PATCH] - Implement the drag list control. - Fix tabs in LBItemFromPt. --- dlls/comctl32/.cvsignore | 1 + dlls/comctl32/Makefile.in | 1 + dlls/comctl32/comctl32.h | 5 +- dlls/comctl32/draglist.c | 284 ++++++++++++++++++++++++++++++++------ dlls/comctl32/rsrc.rc | 27 ++++ 5 files changed, 272 insertions(+), 46 deletions(-) diff --git a/dlls/comctl32/.cvsignore b/dlls/comctl32/.cvsignore index 606711edb98..486c5fcd2af 100644 --- a/dlls/comctl32/.cvsignore +++ b/dlls/comctl32/.cvsignore @@ -9,6 +9,7 @@ idb_std_large.bmp idb_std_small.bmp idb_view_large.bmp idb_view_small.bmp +idc_copy.cur idc_divider.cur idc_divideropen.cur idi_dragarrow.ico diff --git a/dlls/comctl32/Makefile.in b/dlls/comctl32/Makefile.in index 46e44722a08..3a60a3b2557 100644 --- a/dlls/comctl32/Makefile.in +++ b/dlls/comctl32/Makefile.in @@ -46,6 +46,7 @@ RC_BINARIES = \ idb_std_small.bmp \ idb_view_large.bmp \ idb_view_small.bmp \ + idc_copy.cur \ idc_divider.cur \ idc_divideropen.cur \ idi_dragarrow.ico \ diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h index a9a12ce19a5..a5f2f280aaf 100644 --- a/dlls/comctl32/comctl32.h +++ b/dlls/comctl32/comctl32.h @@ -102,8 +102,9 @@ extern HBRUSH COMCTL32_hPattern55AABrush; #define IDC_DIVIDEROPEN 107 -/* DragList icon */ -#define IDI_DRAGARROW 150 +/* DragList resources */ +#define IDI_DRAGARROW 501 +#define IDC_COPY 502 /* HOTKEY internal strings */ diff --git a/dlls/comctl32/draglist.c b/dlls/comctl32/draglist.c index bc1e45095a9..939a27798c5 100644 --- a/dlls/comctl32/draglist.c +++ b/dlls/comctl32/draglist.c @@ -2,6 +2,7 @@ * Drag List control * * Copyright 1999 Eric Kohl + * Copyright 2004 Robert Shearman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,12 +18,6 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * NOTES - * This is just a dummy control. An author is needed! Any volunteers? - * Eric - * - * TODO: - * - Everything. */ #include @@ -32,13 +27,175 @@ #include "wingdi.h" #include "winuser.h" #include "winnls.h" +#include "winnt.h" #include "commctrl.h" +#include "comctl32.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(commctrl); +#ifndef TEXT +# define TEXT(string) string +#endif +#define DRAGLIST_SUBCLASSID 0 +#define DRAGLIST_SCROLLPERIOD 200 +#define DRAGLIST_TIMERID 666 + +/* properties relating to IDI_DRAGICON */ +#define DRAGICON_HOTSPOT_X 17 +#define DRAGICON_HOTSPOT_Y 7 +#define DRAGICON_HEIGHT 32 + +/* internal Wine specific data for the drag list control */ +typedef struct _DRAGLISTDATA +{ + /* are we currently in dragging mode? */ + BOOL dragging; + + /* cursor to use as determined by DL_DRAGGING notification. + * NOTE: as we use LoadCursor we don't have to use DeleteCursor + * when we are finished with it */ + HCURSOR cursor; + + /* optimisation so that we don't have to load the cursor + * all of the time whilst dragging */ + LRESULT last_dragging_response; + /* prevents flicker with drawing drag arrow */ + RECT last_drag_icon_rect; +} DRAGLISTDATA; + +static UINT uDragListMessage = 0; /* registered window message code */ static DWORD dwLastScrollTime = 0; +static HICON hDragArrow = NULL; + +/*********************************************************************** + * DragList_Notify (internal) + * + * Sends notification messages to the parent control. Note that it + * does not use WM_NOTIFY like the rest of the controls, but a registered + * window message. + */ +static LRESULT DragList_Notify(HWND hwndLB, UINT uNotification) +{ + DRAGLISTINFO dli; + dli.hWnd = hwndLB; + dli.uNotification = uNotification; + GetCursorPos(&dli.ptCursor); + return SendMessageW(GetParent(hwndLB), uDragListMessage, GetDlgCtrlID(hwndLB), (LPARAM)&dli); +} + +/* cleans up after dragging */ +static inline void DragList_EndDrag(HWND hwnd, DRAGLISTDATA * data) +{ + KillTimer(hwnd, DRAGLIST_TIMERID); + ReleaseCapture(); + data->dragging = FALSE; + /* clear any drag insert icon present */ + InvalidateRect(GetParent(hwnd), &data->last_drag_icon_rect, TRUE); +} + +/*********************************************************************** + * DragList_SubclassWindowProc (internal) + * + * Handles certain messages to enable dragging for the ListBox and forwards + * the rest to the ListBox. + */ +static LRESULT CALLBACK +DragList_SubclassWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + DRAGLISTDATA * data = (DRAGLISTDATA*)dwRefData; + switch (uMsg) + { + case WM_LBUTTONDOWN: + SetFocus(hwnd); + data->cursor = NULL; + SetRectEmpty(&data->last_drag_icon_rect); + data->dragging = DragList_Notify(hwnd, DL_BEGINDRAG); + if (data->dragging) + { + SetCapture(hwnd); + SetTimer(hwnd, DRAGLIST_TIMERID, DRAGLIST_SCROLLPERIOD, NULL); + } + /* note that we don't absorb this message to let the list box + * do its thing (normally selecting an item) */ + break; + + case WM_KEYDOWN: + case WM_RBUTTONDOWN: + /* user cancelled drag by either right clicking or + * by pressing the escape key */ + if ((data->dragging) && + ((uMsg == WM_RBUTTONDOWN) || (wParam == VK_ESCAPE))) + { + /* clean up and absorb message */ + DragList_EndDrag(hwnd, data); + DragList_Notify(hwnd, DL_CANCELDRAG); + return 0; + } + break; + + case WM_MOUSEMOVE: + case WM_TIMER: + if (data->dragging) + { + LRESULT cursor = DragList_Notify(hwnd, DL_DRAGGING); + /* optimisation so that we don't have to load the cursor + * all of the time whilst dragging */ + if (data->last_dragging_response != cursor) + { + switch (cursor) + { + case DL_STOPCURSOR: + data->cursor = LoadCursorW(NULL, (LPCWSTR)IDC_NO); + SetCursor(data->cursor); + break; + case DL_COPYCURSOR: + data->cursor = LoadCursorW(COMCTL32_hModule, (LPCWSTR)IDC_COPY); + SetCursor(data->cursor); + break; + case DL_MOVECURSOR: + data->cursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); + SetCursor(data->cursor); + break; + } + data->last_dragging_response = cursor; + } + /* don't pass this message on to List Box */ + return 0; + } + break; + + case WM_LBUTTONUP: + if (data->dragging) + { + DragList_EndDrag(hwnd, data); + DragList_Notify(hwnd, DL_DROPPED); + } + break; + + case WM_SETCURSOR: + /* if app has told us to set a cursor then do so */ + if (data->dragging && data->cursor) + { + SetCursor(data->cursor); + return TRUE; + } + break; + + case WM_GETDLGCODE: + /* tell dialog boxes that we want to receive WM_KEYDOWN events + * for keys like VK_ESCAPE */ + if (data->dragging) + return DLGC_WANTALLKEYS; + break; + case WM_NCDESTROY: + RemoveWindowSubclass(hwnd, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID); + Free(data); + break; + } + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} /*********************************************************************** * MakeDragList (COMCTL32.13) @@ -51,10 +208,14 @@ static DWORD dwLastScrollTime = 0; */ BOOL WINAPI MakeDragList (HWND hwndLB) { - FIXME("(%p)\n", hwndLB); + DRAGLISTDATA * data = Alloc(sizeof(DRAGLISTDATA)); + TRACE("(%p)\n", hwndLB); - return FALSE; + if (!uDragListMessage) + uDragListMessage = RegisterWindowMessageA(DRAGLISTMSGSTRING); + + return SetWindowSubclass(hwndLB, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID, (DWORD_PTR)data); } /*********************************************************************** @@ -67,9 +228,54 @@ BOOL WINAPI MakeDragList (HWND hwndLB) */ VOID WINAPI DrawInsert (HWND hwndParent, HWND hwndLB, INT nItem) { - FIXME("(%p %p %d)\n", hwndParent, hwndLB, nItem); + RECT rcItem, rcListBox, rcDragIcon; + HDC hdc; + DRAGLISTDATA * data; + TRACE("(%p %p %d)\n", hwndParent, hwndLB, nItem); + if (!hDragArrow) + hDragArrow = LoadIconW(COMCTL32_hModule, (LPCWSTR)IDI_DRAGARROW); + + if (LB_ERR == SendMessageW(hwndLB, LB_GETITEMRECT, nItem, (LPARAM)&rcItem)) + return; + + if (!GetWindowRect(hwndLB, &rcListBox)) + return; + + /* convert item rect to parent co-ordinates */ + if (!MapWindowPoints(hwndLB, hwndParent, (LPPOINT)&rcItem, 2)) + return; + + /* convert list box rect to parent co-ordinates */ + if (!MapWindowPoints(HWND_DESKTOP, hwndParent, (LPPOINT)&rcListBox, 2)) + return; + + rcDragIcon.left = rcListBox.left - DRAGICON_HOTSPOT_X; + rcDragIcon.top = rcItem.top - DRAGICON_HOTSPOT_Y; + rcDragIcon.right = rcListBox.left; + rcDragIcon.bottom = rcDragIcon.top + DRAGICON_HEIGHT; + + if (!GetWindowSubclass(hwndLB, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID, (DWORD_PTR*)&data)) + return; + + /* prevent flicker by only redrawing when necessary */ + if (!EqualRect(&rcDragIcon, &data->last_drag_icon_rect)) + { + /* get rid of any previous inserts drawn */ + RedrawWindow(hwndParent, &data->last_drag_icon_rect, NULL, + RDW_INTERNALPAINT | RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW); + + if (nItem >= 0) + { + hdc = GetDC(hwndParent); + + DrawIcon(hdc, rcDragIcon.left, rcDragIcon.top, hDragArrow); + + ReleaseDC(hwndParent, hdc); + } + } + CopyRect(&data->last_drag_icon_rect, &rcDragIcon); } /*********************************************************************** @@ -87,8 +293,8 @@ INT WINAPI LBItemFromPt (HWND hwndLB, POINT pt, BOOL bAutoScroll) INT nIndex; DWORD dwScrollTime; - FIXME("(%p %ld x %ld %s)\n", - hwndLB, pt.x, pt.y, bAutoScroll ? "TRUE" : "FALSE"); + TRACE("(%p %ld x %ld %s)\n", + hwndLB, pt.x, pt.y, bAutoScroll ? "TRUE" : "FALSE"); ScreenToClient (hwndLB, &pt); GetClientRect (hwndLB, &rcClient); @@ -96,51 +302,41 @@ INT WINAPI LBItemFromPt (HWND hwndLB, POINT pt, BOOL bAutoScroll) if (PtInRect (&rcClient, pt)) { - /* point is inside -- get the item index */ - while (TRUE) - { - if (SendMessageA (hwndLB, LB_GETITEMRECT, nIndex, (LPARAM)&rcClient) == LB_ERR) - return -1; + /* point is inside -- get the item index */ + while (TRUE) + { + if (SendMessageA (hwndLB, LB_GETITEMRECT, nIndex, (LPARAM)&rcClient) == LB_ERR) + return -1; - if (PtInRect (&rcClient, pt)) - return nIndex; + if (PtInRect (&rcClient, pt)) + return nIndex; - nIndex++; - } + nIndex++; + } } else { - /* point is outside */ - if (!bAutoScroll) - return -1; + /* point is outside */ + if (!bAutoScroll) + return -1; - if ((pt.x > rcClient.right) || (pt.x < rcClient.left)) - return -1; + if ((pt.x > rcClient.right) || (pt.x < rcClient.left)) + return -1; - if (pt.y < 0) - nIndex--; - else - nIndex++; + if (pt.y < 0) + nIndex--; + else + nIndex++; - dwScrollTime = GetTickCount (); + dwScrollTime = GetTickCount (); - if ((dwScrollTime - dwLastScrollTime) < 200) - return -1; + if ((dwScrollTime - dwLastScrollTime) < DRAGLIST_SCROLLPERIOD) + return -1; - dwLastScrollTime = dwScrollTime; + dwLastScrollTime = dwScrollTime; - SendMessageA (hwndLB, LB_SETTOPINDEX, (WPARAM)nIndex, 0); + SendMessageA (hwndLB, LB_SETTOPINDEX, (WPARAM)nIndex, 0); } return -1; } - - -#if 0 -static LRESULT CALLBACK -DRAGLIST_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - - return FALSE; -} -#endif diff --git a/dlls/comctl32/rsrc.rc b/dlls/comctl32/rsrc.rc index 0bb670fc7c5..b1c28fc5b6b 100644 --- a/dlls/comctl32/rsrc.rc +++ b/dlls/comctl32/rsrc.rc @@ -971,6 +971,33 @@ IDB_HIST_LARGE BITMAP LOADONCALL DISCARDABLE idb_hist_large.bmp } */ +/* BINRES idc_copy.cur */ +IDC_COPY CURSOR LOADONCALL DISCARDABLE idc_copy.cur +/* { + '00 00 02 00 01 00 20 20 00 00 00 00 00 00 30 01' + '00 00 16 00 00 00 28 00 00 00 20 00 00 00 40 00' + '00 00 01 00 01 00 00 00 00 00 00 01 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 FF FF FF 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 C0 00 00 00 C0' + '00 00 01 80 00 00 01 80 00 00 03 00 00 00 43 00' + '00 00 66 00 00 00 76 00 00 00 7E 00 00 00 7F C0' + '00 00 7F 80 00 00 7F 00 00 00 7E 00 00 00 7C 00' + '00 00 78 00 00 00 70 00 00 00 60 00 00 00 40 00' + '00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF' + 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF' + 'FF FF FF FF FF FF FF FD FF FF FF FD FF FF FF F0' + '7F FF FF FD FF FF FF 3D FF FF FE 1F FF FF FE 1F' + 'FF FF FC 3F FF FF 7C 3F FF FF 38 7F FF FF 18 7F' + 'FF FF 00 FF FF FF 00 FF FF FF 00 0F FF FF 00 1F' + 'FF FF 00 3F FF FF 00 7F FF FF 00 FF FF FF 01 FF' + 'FF FF 03 FF FF FF 07 FF FF FF 0F FF FF FF 1F FF' + 'FF FF 3F FF FF FF' +} */ + + /* BINRES idc_divider.cur */ IDC_DIVIDER CURSOR LOADONCALL DISCARDABLE idc_divider.cur /* {