ReactOS  0.4.15-dev-489-g75a0787
draglist.c
Go to the documentation of this file.
1 /*
2  * Drag List control
3  *
4  * Copyright 1999 Eric Kohl
5  * Copyright 2004 Robert Shearman
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * NOTES
22  *
23  * This code was audited for completeness against the documented features
24  * of Comctl32.dll version 6.0 on Mar. 10, 2004, by Robert Shearman.
25  *
26  * Unless otherwise noted, we believe this code to be complete, as per
27  * the specification mentioned above.
28  * If you discover missing features or bugs please note them below.
29  *
30  */
31 
32 #include <stdarg.h>
33 
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wingdi.h"
37 #include "winuser.h"
38 #include "winnls.h"
39 #include "commctrl.h"
40 #include "comctl32.h"
41 #include "wine/debug.h"
42 
44 
45 #define DRAGLIST_SUBCLASSID 0
46 #define DRAGLIST_SCROLLPERIOD 200
47 #define DRAGLIST_TIMERID 666
48 
49 /* properties relating to IDI_DRAGICON */
50 #define DRAGICON_HOTSPOT_X 17
51 #define DRAGICON_HOTSPOT_Y 7
52 #define DRAGICON_HEIGHT 32
53 
54 /* internal Wine specific data for the drag list control */
55 typedef struct _DRAGLISTDATA
56 {
57  /* are we currently in dragging mode? */
59 
60  /* cursor to use as determined by DL_DRAGGING notification.
61  * NOTE: as we use LoadCursor we don't have to use DeleteCursor
62  * when we are finished with it */
64 
65  /* optimisation so that we don't have to load the cursor
66  * all of the time whilst dragging */
68 
69  /* prevents flicker with drawing drag arrow */
71 } DRAGLISTDATA;
72 
73 UINT uDragListMessage = 0; /* registered window message code */
76 
77 /***********************************************************************
78  * DragList_Notify (internal)
79  *
80  * Sends notification messages to the parent control. Note that it
81  * does not use WM_NOTIFY like the rest of the controls, but a registered
82  * window message.
83  */
84 static LRESULT DragList_Notify(HWND hwndLB, UINT uNotification)
85 {
86  DRAGLISTINFO dli;
87  dli.hWnd = hwndLB;
88  dli.uNotification = uNotification;
89  GetCursorPos(&dli.ptCursor);
90  return SendMessageW(GetParent(hwndLB), uDragListMessage, GetDlgCtrlID(hwndLB), (LPARAM)&dli);
91 }
92 
93 /* cleans up after dragging */
95 {
98  /* clear any drag insert icon present */
99  InvalidateRect(GetParent(hwnd), &data->last_drag_icon_rect, TRUE);
100  /* clear data for next use */
101  memset(data, 0, sizeof(*data));
102 }
103 
104 /***********************************************************************
105  * DragList_SubclassWindowProc (internal)
106  *
107  * Handles certain messages to enable dragging for the ListBox and forwards
108  * the rest to the ListBox.
109  */
110 static LRESULT CALLBACK
112 {
114  switch (uMsg)
115  {
116  case WM_LBUTTONDOWN:
117  SetFocus(hwnd);
118  data->dragging = DragList_Notify(hwnd, DL_BEGINDRAG);
119  if (data->dragging)
120  {
121  SetCapture(hwnd);
123  }
124  /* note that we don't absorb this message to let the list box
125  * do its thing (normally selecting an item) */
126  break;
127 
128  case WM_KEYDOWN:
129  case WM_RBUTTONDOWN:
130  /* user cancelled drag by either right clicking or
131  * by pressing the escape key */
132  if ((data->dragging) &&
133  ((uMsg == WM_RBUTTONDOWN) || (wParam == VK_ESCAPE)))
134  {
135  /* clean up and absorb message */
138  return 0;
139  }
140  break;
141 
142  case WM_MOUSEMOVE:
143  case WM_TIMER:
144  if (data->dragging)
145  {
147  /* optimisation so that we don't have to load the cursor
148  * all of the time whilst dragging */
149  if (data->last_dragging_response != cursor)
150  {
151  switch (cursor)
152  {
153  case DL_STOPCURSOR:
154  data->cursor = LoadCursorW(NULL, (LPCWSTR)IDC_NO);
155  SetCursor(data->cursor);
156  break;
157  case DL_COPYCURSOR:
159  SetCursor(data->cursor);
160  break;
161  case DL_MOVECURSOR:
162  data->cursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
163  SetCursor(data->cursor);
164  break;
165  }
166  data->last_dragging_response = cursor;
167  }
168  /* don't pass this message on to List Box */
169  return 0;
170  }
171  break;
172 
173  case WM_LBUTTONUP:
174  if (data->dragging)
175  {
178  }
179  break;
180 
181  case WM_GETDLGCODE:
182  /* tell dialog boxes that we want to receive WM_KEYDOWN events
183  * for keys like VK_ESCAPE */
184  if (data->dragging)
185  return DLGC_WANTALLKEYS;
186  break;
187  case WM_NCDESTROY:
189  Free(data);
190  break;
191  }
192  return DefSubclassProc(hwnd, uMsg, wParam, lParam);
193 }
194 
195 /***********************************************************************
196  * MakeDragList (COMCTL32.13)
197  *
198  * Makes a normal ListBox into a DragList by subclassing it.
199  *
200  * RETURNS
201  * Success: Non-zero
202  * Failure: Zero
203  */
205 {
206  DRAGLISTDATA *data = Alloc(sizeof(DRAGLISTDATA));
207 
208  TRACE("(%p)\n", hwndLB);
209 
210  if (!uDragListMessage)
212 
214 }
215 
216 /***********************************************************************
217  * DrawInsert (COMCTL32.15)
218  *
219  * Draws insert arrow by the side of the ListBox item in the parent window.
220  *
221  * RETURNS
222  * Nothing.
223  */
225 {
226  RECT rcItem, rcListBox, rcDragIcon;
227  HDC hdc;
228  DRAGLISTDATA * data;
229 
230  TRACE("(%p %p %d)\n", hwndParent, hwndLB, nItem);
231 
232  if (!hDragArrow)
234 
235  if (LB_ERR == SendMessageW(hwndLB, LB_GETITEMRECT, nItem, (LPARAM)&rcItem))
236  return;
237 
238  if (!GetWindowRect(hwndLB, &rcListBox))
239  return;
240 
241  /* convert item rect to parent co-ordinates */
242  if (!MapWindowPoints(hwndLB, hwndParent, (LPPOINT)&rcItem, 2))
243  return;
244 
245  /* convert list box rect to parent co-ordinates */
246  if (!MapWindowPoints(HWND_DESKTOP, hwndParent, (LPPOINT)&rcListBox, 2))
247  return;
248 
249  rcDragIcon.left = rcListBox.left - DRAGICON_HOTSPOT_X;
250  rcDragIcon.top = rcItem.top - DRAGICON_HOTSPOT_Y;
251  rcDragIcon.right = rcListBox.left;
252  rcDragIcon.bottom = rcDragIcon.top + DRAGICON_HEIGHT;
253 
255  return;
256 
257  if (nItem < 0)
258  SetRectEmpty(&rcDragIcon);
259 
260  /* prevent flicker by only redrawing when necessary */
261  if (!EqualRect(&rcDragIcon, &data->last_drag_icon_rect))
262  {
263  /* get rid of any previous inserts drawn */
264  RedrawWindow(hwndParent, &data->last_drag_icon_rect, NULL,
266 
267  data->last_drag_icon_rect = rcDragIcon;
268 
269  if (nItem >= 0)
270  {
271  hdc = GetDC(hwndParent);
272 
273  DrawIcon(hdc, rcDragIcon.left, rcDragIcon.top, hDragArrow);
274 
276  }
277  }
278 }
279 
280 /***********************************************************************
281  * LBItemFromPt (COMCTL32.14)
282  *
283  * Gets the index of the ListBox item under the specified point,
284  * scrolling if bAutoScroll is TRUE and pt is outside of the ListBox.
285  *
286  * RETURNS
287  * The ListBox item ID if pt is over a list item or -1 otherwise.
288  */
289 INT WINAPI LBItemFromPt (HWND hwndLB, POINT pt, BOOL bAutoScroll)
290 {
291  RECT rcClient;
292  INT nIndex;
293  DWORD dwScrollTime;
294 
295  TRACE("(%p %d x %d %s)\n",
296  hwndLB, pt.x, pt.y, bAutoScroll ? "TRUE" : "FALSE");
297 
298  ScreenToClient (hwndLB, &pt);
299  GetClientRect (hwndLB, &rcClient);
300  nIndex = (INT)SendMessageW (hwndLB, LB_GETTOPINDEX, 0, 0);
301 
302  if (PtInRect (&rcClient, pt))
303  {
304  /* point is inside -- get the item index */
305  while (TRUE)
306  {
307  if (SendMessageW (hwndLB, LB_GETITEMRECT, nIndex, (LPARAM)&rcClient) == LB_ERR)
308  return -1;
309 
310  if (PtInRect (&rcClient, pt))
311  return nIndex;
312 
313  nIndex++;
314  }
315  }
316  else
317  {
318  /* point is outside */
319  if (!bAutoScroll)
320  return -1;
321 
322  if ((pt.x > rcClient.right) || (pt.x < rcClient.left))
323  return -1;
324 
325  if (pt.y < 0)
326  nIndex--;
327  else
328  nIndex++;
329 
330  dwScrollTime = GetTickCount ();
331 
332  if ((dwScrollTime - dwLastScrollTime) < DRAGLIST_SCROLLPERIOD)
333  return -1;
334 
335  dwLastScrollTime = dwScrollTime;
336 
337  SendMessageW (hwndLB, LB_SETTOPINDEX, nIndex, 0);
338  }
339 
340  return -1;
341 }
#define DL_CANCELDRAG
Definition: commctrl.h:2096
static LRESULT CALLBACK DragList_SubclassWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
Definition: draglist.c:111
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
BOOL WINAPI RedrawWindow(_In_opt_ HWND, _In_opt_ LPCRECT, _In_opt_ HRGN, _In_ UINT)
#define DL_BEGINDRAG
Definition: commctrl.h:2093
#define DRAGLIST_SCROLLPERIOD
Definition: draglist.c:46
HCURSOR cursor
Definition: draglist.c:63
static HICON
Definition: imagelist.c:84
#define TRUE
Definition: types.h:120
#define DRAGLIST_SUBCLASSID
Definition: draglist.c:45
#define WM_GETDLGCODE
Definition: winuser.h:1671
int WINAPI MapWindowPoints(_In_opt_ HWND hWndFrom, _In_opt_ HWND hWndTo, _Inout_updates_(cPoints) LPPOINT lpPoints, _In_ UINT cPoints)
INT WINAPI LBItemFromPt(HWND hwndLB, POINT pt, BOOL bAutoScroll)
Definition: draglist.c:289
#define WM_LBUTTONDOWN
Definition: winuser.h:1758
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
HDC WINAPI GetDC(_In_opt_ HWND)
#define pt(x, y)
Definition: drawing.c:79
#define IDC_NO
Definition: winuser.h:692
_In_ SUBCLASSPROC _In_ UINT_PTR _In_ DWORD_PTR dwRefData
Definition: commctrl.h:5052
struct _DRAGLISTDATA DRAGLISTDATA
BOOL dragging
Definition: draglist.c:58
#define INT
Definition: polytest.cpp:20
#define DL_STOPCURSOR
Definition: commctrl.h:2099
static HDC
Definition: imagelist.c:92
#define CALLBACK
Definition: compat.h:27
LRESULT last_dragging_response
Definition: draglist.c:67
static LRESULT DragList_Notify(HWND hwndLB, UINT uNotification)
Definition: draglist.c:84
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
LONG top
Definition: windef.h:307
HWND WINAPI SetFocus(_In_opt_ HWND)
UINT_PTR WPARAM
Definition: windef.h:207
#define DL_DRAGGING
Definition: commctrl.h:2094
LONG left
Definition: windef.h:306
HICON HCURSOR
Definition: windef.h:299
#define DL_MOVECURSOR
Definition: commctrl.h:2101
#define VK_ESCAPE
Definition: winuser.h:2189
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:2635
LONG right
Definition: windef.h:308
static const WCHAR DRAGLISTMSGSTRINGW[]
Definition: commctrl.h:27
#define DRAGLIST_TIMERID
Definition: draglist.c:47
static HICON hDragArrow
Definition: draglist.c:75
int32_t INT
Definition: typedefs.h:57
WPARAM wParam
Definition: combotst.c:138
_In_opt_ PALLOCATE_FUNCTION _In_opt_ PFREE_FUNCTION Free
Definition: exfuncs.h:814
WINE_DEFAULT_DEBUG_CHANNEL(commctrl)
UINT uNotification
Definition: commctrl.h:2088
int WINAPI GetDlgCtrlID(_In_ HWND)
BOOL WINAPI GetWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID, DWORD_PTR *pdwRef)
Definition: commctrl.c:1348
BOOL WINAPI MakeDragList(HWND hwndLB)
Definition: draglist.c:204
#define IDI_DRAGARROW
Definition: comctl32.h:93
#define LB_ERR
Definition: winuser.h:2407
unsigned int BOOL
Definition: ntddk_ex.h:94
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
#define DRAGICON_HOTSPOT_X
Definition: draglist.c:50
static void DragList_EndDrag(HWND hwnd, DRAGLISTDATA *data)
Definition: draglist.c:94
smooth NULL
Definition: ftsmooth.c:416
static HWND hwndParent
Definition: cryptui.c:300
#define WM_KEYDOWN
Definition: winuser.h:1697
LONG_PTR LPARAM
Definition: windef.h:208
RECT last_drag_icon_rect
Definition: draglist.c:70
#define DL_DROPPED
Definition: commctrl.h:2095
LRESULT WINAPI DefSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: commctrl.c:1496
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define WM_RBUTTONDOWN
Definition: winuser.h:1761
BOOL WINAPI SetWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uIDSubclass, DWORD_PTR dwRef)
Definition: commctrl.c:1261
#define DRAGICON_HOTSPOT_Y
Definition: draglist.c:51
#define TRACE(s)
Definition: solgame.cpp:4
#define LB_SETTOPINDEX
Definition: winuser.h:2052
#define RDW_ERASE
Definition: winuser.h:1197
#define WM_TIMER
Definition: winuser.h:1724
#define WM_NCDESTROY
Definition: winuser.h:1666
#define WINAPI
Definition: msvc.h:6
#define DRAGICON_HEIGHT
Definition: draglist.c:52
BOOL WINAPI InvalidateRect(_In_opt_ HWND, _In_opt_ LPCRECT, _In_ BOOL)
PVOID Alloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: main.c:63
#define IDC_COPY
Definition: resource.h:17
unsigned long DWORD
Definition: ntddk_ex.h:95
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2074
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
#define DL_COPYCURSOR
Definition: commctrl.h:2100
HDC hdc
Definition: main.c:9
#define RDW_INTERNALPAINT
Definition: winuser.h:1199
BOOL WINAPI SetRectEmpty(_Out_ LPRECT)
uint32_t DWORD_PTR
Definition: typedefs.h:64
#define DLGC_WANTALLKEYS
Definition: winuser.h:2587
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
HWND WINAPI GetParent(_In_ HWND)
UINT WINAPI RegisterWindowMessageW(_In_ LPCWSTR)
HWND WINAPI SetCapture(_In_ HWND hWnd)
BOOL WINAPI DrawIcon(_In_ HDC, _In_ int, _In_ int, _In_ HICON)
Definition: cursoricon.c:1987
BOOL WINAPI EqualRect(_In_ LPCRECT, _In_ LPCRECT)
const char cursor[]
Definition: icontest.c:13
BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
Definition: commctrl.c:1390
HMODULE COMCTL32_hModule
Definition: commctrl.c:79
HCURSOR WINAPI SetCursor(_In_opt_ HCURSOR)
#define LB_GETTOPINDEX
Definition: winuser.h:2033
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_LBUTTONUP
Definition: winuser.h:1759
#define HWND_DESKTOP
Definition: winuser.h:1195
unsigned int UINT
Definition: ndis.h:50
#define WM_MOUSEMOVE
Definition: winuser.h:1757
BOOL WINAPI PtInRect(_In_ LPCRECT, _In_ POINT)
#define RDW_UPDATENOW
Definition: winuser.h:1206
#define IDC_ARROW
Definition: winuser.h:682
BOOL WINAPI ReleaseCapture(void)
Definition: message.c:2889
UINT uDragListMessage
Definition: draglist.c:73
HICON WINAPI LoadIconW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2044
LONG bottom
Definition: windef.h:309
BOOL WINAPI GetWindowRect(_In_ HWND, _Out_ LPRECT)
#define LB_GETITEMRECT
Definition: winuser.h:2025
BOOL WINAPI ScreenToClient(_In_ HWND, _Inout_ LPPOINT)
LONG_PTR LRESULT
Definition: windef.h:209
VOID WINAPI DrawInsert(HWND hwndParent, HWND hwndLB, INT nItem)
Definition: draglist.c:224
#define memset(x, y, z)
Definition: compat.h:39
LPARAM lParam
Definition: combotst.c:139
_In_ SUBCLASSPROC _In_ UINT_PTR uIdSubclass
Definition: commctrl.h:5052
static DWORD dwLastScrollTime
Definition: draglist.c:74
#define RDW_INVALIDATE
Definition: winuser.h:1200