ReactOS 0.4.16-dev-340-g0540c21
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 */
55typedef 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 */
72
73UINT 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 */
84static LRESULT DragList_Notify(HWND hwndLB, UINT uNotification)
85{
86 DRAGLISTINFO dli;
87 dli.hWnd = hwndLB;
88 dli.uNotification = uNotification;
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 */
110static LRESULT CALLBACK
112{
114 switch (uMsg)
115 {
116 case WM_LBUTTONDOWN:
117 SetFocus(hwnd);
119 if (data->dragging)
120 {
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:
158#ifndef __REACTOS__
160#else
162#endif
163 SetCursor(data->cursor);
164 break;
165 case DL_MOVECURSOR:
167 SetCursor(data->cursor);
168 break;
169 }
170 data->last_dragging_response = cursor;
171 }
172 /* don't pass this message on to List Box */
173 return 0;
174 }
175 break;
176
177 case WM_LBUTTONUP:
178 if (data->dragging)
179 {
182 }
183 break;
184
185 case WM_GETDLGCODE:
186 /* tell dialog boxes that we want to receive WM_KEYDOWN events
187 * for keys like VK_ESCAPE */
188 if (data->dragging)
189 return DLGC_WANTALLKEYS;
190 break;
191 case WM_NCDESTROY:
193 Free(data);
194 break;
195 }
196 return DefSubclassProc(hwnd, uMsg, wParam, lParam);
197}
198
199/***********************************************************************
200 * MakeDragList (COMCTL32.13)
201 *
202 * Makes a normal ListBox into a DragList by subclassing it.
203 *
204 * RETURNS
205 * Success: Non-zero
206 * Failure: Zero
207 */
209{
211
212 TRACE("(%p)\n", hwndLB);
213
214 if (!uDragListMessage)
216
218}
219
220/***********************************************************************
221 * DrawInsert (COMCTL32.15)
222 *
223 * Draws insert arrow by the side of the ListBox item in the parent window.
224 *
225 * RETURNS
226 * Nothing.
227 */
229{
230 RECT rcItem, rcListBox, rcDragIcon;
231 HDC hdc;
233
234 TRACE("(%p %p %d)\n", hwndParent, hwndLB, nItem);
235
236 if (!hDragArrow)
238
239 if (LB_ERR == SendMessageW(hwndLB, LB_GETITEMRECT, nItem, (LPARAM)&rcItem))
240 return;
241
242 if (!GetWindowRect(hwndLB, &rcListBox))
243 return;
244
245 /* convert item rect to parent co-ordinates */
246 if (!MapWindowPoints(hwndLB, hwndParent, (LPPOINT)&rcItem, 2))
247 return;
248
249 /* convert list box rect to parent co-ordinates */
250 if (!MapWindowPoints(HWND_DESKTOP, hwndParent, (LPPOINT)&rcListBox, 2))
251 return;
252
253 rcDragIcon.left = rcListBox.left - DRAGICON_HOTSPOT_X;
254 rcDragIcon.top = rcItem.top - DRAGICON_HOTSPOT_Y;
255 rcDragIcon.right = rcListBox.left;
256 rcDragIcon.bottom = rcDragIcon.top + DRAGICON_HEIGHT;
257
259 return;
260
261 if (nItem < 0)
262 SetRectEmpty(&rcDragIcon);
263
264 /* prevent flicker by only redrawing when necessary */
265 if (!EqualRect(&rcDragIcon, &data->last_drag_icon_rect))
266 {
267 /* get rid of any previous inserts drawn */
268 RedrawWindow(hwndParent, &data->last_drag_icon_rect, NULL,
270
271 data->last_drag_icon_rect = rcDragIcon;
272
273 if (nItem >= 0)
274 {
276
277 DrawIcon(hdc, rcDragIcon.left, rcDragIcon.top, hDragArrow);
278
280 }
281 }
282}
283
284/***********************************************************************
285 * LBItemFromPt (COMCTL32.14)
286 *
287 * Gets the index of the ListBox item under the specified point,
288 * scrolling if bAutoScroll is TRUE and pt is outside of the ListBox.
289 *
290 * RETURNS
291 * The ListBox item ID if pt is over a list item or -1 otherwise.
292 */
293INT WINAPI LBItemFromPt (HWND hwndLB, POINT pt, BOOL bAutoScroll)
294{
295 RECT rcClient;
296 INT nIndex;
297 DWORD dwScrollTime;
298
299 TRACE("(%p %d x %d %s)\n",
300 hwndLB, pt.x, pt.y, bAutoScroll ? "TRUE" : "FALSE");
301
302 ScreenToClient (hwndLB, &pt);
303 GetClientRect (hwndLB, &rcClient);
304 nIndex = (INT)SendMessageW (hwndLB, LB_GETTOPINDEX, 0, 0);
305
306 if (PtInRect (&rcClient, pt))
307 {
308 /* point is inside -- get the item index */
309 while (TRUE)
310 {
311 if (SendMessageW (hwndLB, LB_GETITEMRECT, nIndex, (LPARAM)&rcClient) == LB_ERR)
312 return -1;
313
314 if (PtInRect (&rcClient, pt))
315 return nIndex;
316
317 nIndex++;
318 }
319 }
320 else
321 {
322 /* point is outside */
323 if (!bAutoScroll)
324 return -1;
325
326 if ((pt.x > rcClient.right) || (pt.x < rcClient.left))
327 return -1;
328
329 if (pt.y < 0)
330 nIndex--;
331 else
332 nIndex++;
333
334 dwScrollTime = GetTickCount ();
335
336 if ((dwScrollTime - dwLastScrollTime) < DRAGLIST_SCROLLPERIOD)
337 return -1;
338
339 dwLastScrollTime = dwScrollTime;
340
341 SendMessageW (hwndLB, LB_SETTOPINDEX, nIndex, 0);
342 }
343
344 return -1;
345}
#define IDC_COPY
Definition: resource.h:17
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
PVOID Alloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: main.c:63
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define IDI_DRAGARROW
Definition: comctl32.h:103
BOOL WINAPI GetWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID, DWORD_PTR *pdwRef)
Definition: commctrl.c:1355
HMODULE COMCTL32_hModule
Definition: commctrl.c:79
BOOL WINAPI SetWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uIDSubclass, DWORD_PTR dwRef)
Definition: commctrl.c:1268
BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
Definition: commctrl.c:1397
LRESULT WINAPI DefSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: commctrl.c:1503
static HWND hwndParent
Definition: cryptui.c:300
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define CALLBACK
Definition: compat.h:35
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
static LRESULT CALLBACK DragList_SubclassWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
Definition: draglist.c:111
static DWORD dwLastScrollTime
Definition: draglist.c:74
struct _DRAGLISTDATA DRAGLISTDATA
#define DRAGLIST_SUBCLASSID
Definition: draglist.c:45
#define DRAGICON_HOTSPOT_Y
Definition: draglist.c:51
static LRESULT DragList_Notify(HWND hwndLB, UINT uNotification)
Definition: draglist.c:84
UINT uDragListMessage
Definition: draglist.c:73
#define DRAGLIST_TIMERID
Definition: draglist.c:47
BOOL WINAPI MakeDragList(HWND hwndLB)
Definition: draglist.c:208
#define DRAGICON_HOTSPOT_X
Definition: draglist.c:50
VOID WINAPI DrawInsert(HWND hwndParent, HWND hwndLB, INT nItem)
Definition: draglist.c:228
static HICON hDragArrow
Definition: draglist.c:75
#define DRAGLIST_SCROLLPERIOD
Definition: draglist.c:46
#define DRAGICON_HEIGHT
Definition: draglist.c:52
static void DragList_EndDrag(HWND hwnd, DRAGLISTDATA *data)
Definition: draglist.c:94
INT WINAPI LBItemFromPt(HWND hwndLB, POINT pt, BOOL bAutoScroll)
Definition: draglist.c:293
#define pt(x, y)
Definition: drawing.c:79
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
const char cursor[]
Definition: icontest.c:13
HDC hdc
Definition: main.c:9
static HDC
Definition: imagelist.c:88
static HICON
Definition: imagelist.c:80
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
unsigned int UINT
Definition: ndis.h:50
#define INT
Definition: polytest.cpp:20
#define DL_BEGINDRAG
Definition: commctrl.h:2102
#define DL_MOVECURSOR
Definition: commctrl.h:2110
_In_ SUBCLASSPROC _In_ UINT_PTR uIdSubclass
Definition: commctrl.h:5062
#define DL_CANCELDRAG
Definition: commctrl.h:2105
#define DL_COPYCURSOR
Definition: commctrl.h:2109
#define DL_DRAGGING
Definition: commctrl.h:2103
_In_ SUBCLASSPROC _In_ UINT_PTR _In_ DWORD_PTR dwRefData
Definition: commctrl.h:5063
#define DL_STOPCURSOR
Definition: commctrl.h:2108
#define DL_DROPPED
Definition: commctrl.h:2104
static const WCHAR DRAGLISTMSGSTRINGW[]
Definition: commctrl.h:27
#define memset(x, y, z)
Definition: compat.h:39
#define TRACE(s)
Definition: solgame.cpp:4
RECT last_drag_icon_rect
Definition: draglist.c:70
BOOL dragging
Definition: draglist.c:58
LRESULT last_dragging_response
Definition: draglist.c:67
HCURSOR cursor
Definition: draglist.c:63
UINT uNotification
Definition: commctrl.h:2097
LONG right
Definition: windef.h:308
LONG bottom
Definition: windef.h:309
LONG top
Definition: windef.h:307
LONG left
Definition: windef.h:306
uint32_t DWORD_PTR
Definition: typedefs.h:65
int32_t INT
Definition: typedefs.h:58
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
HICON HCURSOR
Definition: windef.h:299
#define WINAPI
Definition: msvc.h:6
#define LB_ERR
Definition: winuser.h:2435
HWND WINAPI SetCapture(_In_ HWND hWnd)
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
BOOL WINAPI RedrawWindow(_In_opt_ HWND, _In_opt_ LPCRECT, _In_opt_ HRGN, _In_ UINT)
BOOL WINAPI ReleaseCapture(void)
Definition: message.c:2890
#define LB_SETTOPINDEX
Definition: winuser.h:2073
BOOL WINAPI GetWindowRect(_In_ HWND, _Out_ LPRECT)
BOOL WINAPI DrawIcon(_In_ HDC, _In_ int, _In_ int, _In_ HICON)
Definition: cursoricon.c:2070
#define IDC_NO
Definition: winuser.h:697
#define DLGC_WANTALLKEYS
Definition: winuser.h:2615
#define LB_GETITEMRECT
Definition: winuser.h:2046
#define IDC_ARROW
Definition: winuser.h:687
#define LB_GETTOPINDEX
Definition: winuser.h:2054
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:2722
HCURSOR WINAPI SetCursor(_In_opt_ HCURSOR)
#define WM_MOUSEMOVE
Definition: winuser.h:1778
#define RDW_UPDATENOW
Definition: winuser.h:1223
#define RDW_ERASE
Definition: winuser.h:1214
#define WM_LBUTTONDOWN
Definition: winuser.h:1779
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2157
int WINAPI MapWindowPoints(_In_opt_ HWND hWndFrom, _In_opt_ HWND hWndTo, _Inout_updates_(cPoints) LPPOINT lpPoints, _In_ UINT cPoints)
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define HWND_DESKTOP
Definition: winuser.h:1212
#define WM_RBUTTONDOWN
Definition: winuser.h:1782
BOOL WINAPI PtInRect(_In_ LPCRECT, _In_ POINT)
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
HWND WINAPI SetFocus(_In_opt_ HWND)
#define WM_TIMER
Definition: winuser.h:1745
UINT WINAPI RegisterWindowMessageW(_In_ LPCWSTR)
HDC WINAPI GetDC(_In_opt_ HWND)
#define WM_LBUTTONUP
Definition: winuser.h:1780
BOOL WINAPI SetRectEmpty(_Out_ LPRECT)
HWND WINAPI GetParent(_In_ HWND)
#define WM_NCDESTROY
Definition: winuser.h:1687
int WINAPI GetDlgCtrlID(_In_ HWND)
#define WM_KEYDOWN
Definition: winuser.h:1718
BOOL WINAPI InvalidateRect(_In_opt_ HWND, _In_opt_ LPCRECT, _In_ BOOL)
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
#define RDW_INTERNALPAINT
Definition: winuser.h:1216
#define VK_ESCAPE
Definition: winuser.h:2217
BOOL WINAPI EqualRect(_In_ LPCRECT, _In_ LPCRECT)
HICON WINAPI LoadIconW(_In_opt_ HINSTANCE hInstance, _In_ LPCWSTR lpIconName)
Definition: cursoricon.c:2127
#define RDW_INVALIDATE
Definition: winuser.h:1217
#define WM_GETDLGCODE
Definition: winuser.h:1692
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL WINAPI ScreenToClient(_In_ HWND, _Inout_ LPPOINT)
_In_opt_ PALLOCATE_FUNCTION _In_opt_ PFREE_FUNCTION Free
Definition: exfuncs.h:815
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185