ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

draglist.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.