Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendraglist.c
Go to the documentation of this file.
00001 /* 00002 * Drag List control 00003 * 00004 * Copyright 1999 Eric Kohl 00005 * Copyright 2004 Robert Shearman 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 * 00021 * NOTES 00022 * 00023 * This code was audited for completeness against the documented features 00024 * of Comctl32.dll version 6.0 on Mar. 10, 2004, by Robert Shearman. 00025 * 00026 * Unless otherwise noted, we believe this code to be complete, as per 00027 * the specification mentioned above. 00028 * If you discover missing features or bugs please note them below. 00029 * 00030 */ 00031 00032 #include <stdarg.h> 00033 00034 #include "windef.h" 00035 #include "winbase.h" 00036 #include "wingdi.h" 00037 #include "winuser.h" 00038 #include "winnls.h" 00039 #include "commctrl.h" 00040 #include "comctl32.h" 00041 #include "wine/debug.h" 00042 00043 WINE_DEFAULT_DEBUG_CHANNEL(commctrl); 00044 00045 #define DRAGLIST_SUBCLASSID 0 00046 #define DRAGLIST_SCROLLPERIOD 200 00047 #define DRAGLIST_TIMERID 666 00048 00049 /* properties relating to IDI_DRAGICON */ 00050 #define DRAGICON_HOTSPOT_X 17 00051 #define DRAGICON_HOTSPOT_Y 7 00052 #define DRAGICON_HEIGHT 32 00053 00054 /* internal Wine specific data for the drag list control */ 00055 typedef struct _DRAGLISTDATA 00056 { 00057 /* are we currently in dragging mode? */ 00058 BOOL dragging; 00059 00060 /* cursor to use as determined by DL_DRAGGING notification. 00061 * NOTE: as we use LoadCursor we don't have to use DeleteCursor 00062 * when we are finished with it */ 00063 HCURSOR cursor; 00064 00065 /* optimisation so that we don't have to load the cursor 00066 * all of the time whilst dragging */ 00067 LRESULT last_dragging_response; 00068 00069 /* prevents flicker with drawing drag arrow */ 00070 RECT last_drag_icon_rect; 00071 } DRAGLISTDATA; 00072 00073 UINT uDragListMessage = 0; /* registered window message code */ 00074 static DWORD dwLastScrollTime = 0; 00075 static HICON hDragArrow = NULL; 00076 00077 /*********************************************************************** 00078 * DragList_Notify (internal) 00079 * 00080 * Sends notification messages to the parent control. Note that it 00081 * does not use WM_NOTIFY like the rest of the controls, but a registered 00082 * window message. 00083 */ 00084 static LRESULT DragList_Notify(HWND hwndLB, UINT uNotification) 00085 { 00086 DRAGLISTINFO dli; 00087 dli.hWnd = hwndLB; 00088 dli.uNotification = uNotification; 00089 GetCursorPos(&dli.ptCursor); 00090 return SendMessageW(GetParent(hwndLB), uDragListMessage, GetDlgCtrlID(hwndLB), (LPARAM)&dli); 00091 } 00092 00093 /* cleans up after dragging */ 00094 static void DragList_EndDrag(HWND hwnd, DRAGLISTDATA * data) 00095 { 00096 KillTimer(hwnd, DRAGLIST_TIMERID); 00097 ReleaseCapture(); 00098 /* clear any drag insert icon present */ 00099 InvalidateRect(GetParent(hwnd), &data->last_drag_icon_rect, TRUE); 00100 /* clear data for next use */ 00101 memset(data, 0, sizeof(*data)); 00102 } 00103 00104 /*********************************************************************** 00105 * DragList_SubclassWindowProc (internal) 00106 * 00107 * Handles certain messages to enable dragging for the ListBox and forwards 00108 * the rest to the ListBox. 00109 */ 00110 static LRESULT CALLBACK 00111 DragList_SubclassWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) 00112 { 00113 DRAGLISTDATA * data = (DRAGLISTDATA*)dwRefData; 00114 switch (uMsg) 00115 { 00116 case WM_LBUTTONDOWN: 00117 SetFocus(hwnd); 00118 data->dragging = DragList_Notify(hwnd, DL_BEGINDRAG); 00119 if (data->dragging) 00120 { 00121 SetCapture(hwnd); 00122 SetTimer(hwnd, DRAGLIST_TIMERID, DRAGLIST_SCROLLPERIOD, NULL); 00123 } 00124 /* note that we don't absorb this message to let the list box 00125 * do its thing (normally selecting an item) */ 00126 break; 00127 00128 case WM_KEYDOWN: 00129 case WM_RBUTTONDOWN: 00130 /* user cancelled drag by either right clicking or 00131 * by pressing the escape key */ 00132 if ((data->dragging) && 00133 ((uMsg == WM_RBUTTONDOWN) || (wParam == VK_ESCAPE))) 00134 { 00135 /* clean up and absorb message */ 00136 DragList_EndDrag(hwnd, data); 00137 DragList_Notify(hwnd, DL_CANCELDRAG); 00138 return 0; 00139 } 00140 break; 00141 00142 case WM_MOUSEMOVE: 00143 case WM_TIMER: 00144 if (data->dragging) 00145 { 00146 LRESULT cursor = DragList_Notify(hwnd, DL_DRAGGING); 00147 /* optimisation so that we don't have to load the cursor 00148 * all of the time whilst dragging */ 00149 if (data->last_dragging_response != cursor) 00150 { 00151 switch (cursor) 00152 { 00153 case DL_STOPCURSOR: 00154 data->cursor = LoadCursorW(NULL, (LPCWSTR)IDC_NO); 00155 SetCursor(data->cursor); 00156 break; 00157 case DL_COPYCURSOR: 00158 data->cursor = LoadCursorW(COMCTL32_hModule, (LPCWSTR)IDC_COPY); 00159 SetCursor(data->cursor); 00160 break; 00161 case DL_MOVECURSOR: 00162 data->cursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); 00163 SetCursor(data->cursor); 00164 break; 00165 } 00166 data->last_dragging_response = cursor; 00167 } 00168 /* don't pass this message on to List Box */ 00169 return 0; 00170 } 00171 break; 00172 00173 case WM_LBUTTONUP: 00174 if (data->dragging) 00175 { 00176 DragList_EndDrag(hwnd, data); 00177 DragList_Notify(hwnd, DL_DROPPED); 00178 } 00179 break; 00180 00181 case WM_GETDLGCODE: 00182 /* tell dialog boxes that we want to receive WM_KEYDOWN events 00183 * for keys like VK_ESCAPE */ 00184 if (data->dragging) 00185 return DLGC_WANTALLKEYS; 00186 break; 00187 case WM_NCDESTROY: 00188 RemoveWindowSubclass(hwnd, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID); 00189 Free(data); 00190 break; 00191 } 00192 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 00193 } 00194 00195 /*********************************************************************** 00196 * MakeDragList (COMCTL32.13) 00197 * 00198 * Makes a normal ListBox into a DragList by subclassing it. 00199 * 00200 * RETURNS 00201 * Success: Non-zero 00202 * Failure: Zero 00203 */ 00204 BOOL WINAPI MakeDragList (HWND hwndLB) 00205 { 00206 DRAGLISTDATA *data = Alloc(sizeof(DRAGLISTDATA)); 00207 00208 TRACE("(%p)\n", hwndLB); 00209 00210 if (!uDragListMessage) 00211 uDragListMessage = RegisterWindowMessageW(DRAGLISTMSGSTRINGW); 00212 00213 return SetWindowSubclass(hwndLB, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID, (DWORD_PTR)data); 00214 } 00215 00216 /*********************************************************************** 00217 * DrawInsert (COMCTL32.15) 00218 * 00219 * Draws insert arrow by the side of the ListBox item in the parent window. 00220 * 00221 * RETURNS 00222 * Nothing. 00223 */ 00224 VOID WINAPI DrawInsert (HWND hwndParent, HWND hwndLB, INT nItem) 00225 { 00226 RECT rcItem, rcListBox, rcDragIcon; 00227 HDC hdc; 00228 DRAGLISTDATA * data; 00229 00230 TRACE("(%p %p %d)\n", hwndParent, hwndLB, nItem); 00231 00232 if (!hDragArrow) 00233 hDragArrow = LoadIconW(COMCTL32_hModule, (LPCWSTR)IDI_DRAGARROW); 00234 00235 if (LB_ERR == SendMessageW(hwndLB, LB_GETITEMRECT, nItem, (LPARAM)&rcItem)) 00236 return; 00237 00238 if (!GetWindowRect(hwndLB, &rcListBox)) 00239 return; 00240 00241 /* convert item rect to parent co-ordinates */ 00242 if (!MapWindowPoints(hwndLB, hwndParent, (LPPOINT)&rcItem, 2)) 00243 return; 00244 00245 /* convert list box rect to parent co-ordinates */ 00246 if (!MapWindowPoints(HWND_DESKTOP, hwndParent, (LPPOINT)&rcListBox, 2)) 00247 return; 00248 00249 rcDragIcon.left = rcListBox.left - DRAGICON_HOTSPOT_X; 00250 rcDragIcon.top = rcItem.top - DRAGICON_HOTSPOT_Y; 00251 rcDragIcon.right = rcListBox.left; 00252 rcDragIcon.bottom = rcDragIcon.top + DRAGICON_HEIGHT; 00253 00254 if (!GetWindowSubclass(hwndLB, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID, (DWORD_PTR*)&data)) 00255 return; 00256 00257 if (nItem < 0) 00258 SetRectEmpty(&rcDragIcon); 00259 00260 /* prevent flicker by only redrawing when necessary */ 00261 if (!EqualRect(&rcDragIcon, &data->last_drag_icon_rect)) 00262 { 00263 /* get rid of any previous inserts drawn */ 00264 RedrawWindow(hwndParent, &data->last_drag_icon_rect, NULL, 00265 RDW_INTERNALPAINT | RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW); 00266 00267 CopyRect(&data->last_drag_icon_rect, &rcDragIcon); 00268 00269 if (nItem >= 0) 00270 { 00271 hdc = GetDC(hwndParent); 00272 00273 DrawIcon(hdc, rcDragIcon.left, rcDragIcon.top, hDragArrow); 00274 00275 ReleaseDC(hwndParent, hdc); 00276 } 00277 } 00278 } 00279 00280 /*********************************************************************** 00281 * LBItemFromPt (COMCTL32.14) 00282 * 00283 * Gets the index of the ListBox item under the specified point, 00284 * scrolling if bAutoScroll is TRUE and pt is outside of the ListBox. 00285 * 00286 * RETURNS 00287 * The ListBox item ID if pt is over a list item or -1 otherwise. 00288 */ 00289 INT WINAPI LBItemFromPt (HWND hwndLB, POINT pt, BOOL bAutoScroll) 00290 { 00291 RECT rcClient; 00292 INT nIndex; 00293 DWORD dwScrollTime; 00294 00295 TRACE("(%p %d x %d %s)\n", 00296 hwndLB, pt.x, pt.y, bAutoScroll ? "TRUE" : "FALSE"); 00297 00298 ScreenToClient (hwndLB, &pt); 00299 GetClientRect (hwndLB, &rcClient); 00300 nIndex = (INT)SendMessageW (hwndLB, LB_GETTOPINDEX, 0, 0); 00301 00302 if (PtInRect (&rcClient, pt)) 00303 { 00304 /* point is inside -- get the item index */ 00305 while (TRUE) 00306 { 00307 if (SendMessageW (hwndLB, LB_GETITEMRECT, nIndex, (LPARAM)&rcClient) == LB_ERR) 00308 return -1; 00309 00310 if (PtInRect (&rcClient, pt)) 00311 return nIndex; 00312 00313 nIndex++; 00314 } 00315 } 00316 else 00317 { 00318 /* point is outside */ 00319 if (!bAutoScroll) 00320 return -1; 00321 00322 if ((pt.x > rcClient.right) || (pt.x < rcClient.left)) 00323 return -1; 00324 00325 if (pt.y < 0) 00326 nIndex--; 00327 else 00328 nIndex++; 00329 00330 dwScrollTime = GetTickCount (); 00331 00332 if ((dwScrollTime - dwLastScrollTime) < DRAGLIST_SCROLLPERIOD) 00333 return -1; 00334 00335 dwLastScrollTime = dwScrollTime; 00336 00337 SendMessageW (hwndLB, LB_SETTOPINDEX, nIndex, 0); 00338 } 00339 00340 return -1; 00341 } Generated on Sun May 27 2012 04:22:59 for ReactOS by
1.7.6.1
|