- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
[wine] / dlls / comctl32 / listview.c
1 /*
2  * Listview control
3  *
4  * Copyright 1998 Eric Kohl
5  * Copyright 1999 Luc Tourangeau
6  *
7  * NOTES
8  * Listview control implementation. The behavior conforms to version 4.70 
9  * and earlier of the listview contol.
10  *
11  * TODO:
12  *   Most messages and notifications
13  *   Report, small icon and icon display modes 
14  */
15
16 #include <string.h>
17 #include "commctrl.h"
18 #include "listview.h"
19 #include "win.h"
20 #include "debug.h"
21 #include "winuser.h"
22
23 /* prototypes */
24 static INT32 LISTVIEW_GetItemCountPerColumn(HWND32 hwnd);
25 static INT32 LISTVIEW_GetItemCountPerRow(HWND32 hwnd);
26 static INT32 LISTVIEW_GetFirstVisibleItem(HWND32 hwnd);
27 static VOID LISTVIEW_SetVisible(HWND32 hwnd, INT32 nItem);
28
29
30 /***
31  * DESCRIPTION:
32  * Scrolls the specified item into the visible area.
33  * 
34  * PARAMETER(S):
35  * [I] HWND32 : window handle
36  * [I] INT32 : item index
37  *
38  * RETURN:
39  * None
40  */
41 static VOID LISTVIEW_SetVisible(HWND32 hwnd, INT32 nItem)
42 {
43   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
44   INT32 nItemCountPerRow;
45   INT32 nItemCountPerColumn;
46   INT32 nLastItem;
47   INT32 nFirstItem;
48   INT32 nHScrollPos;
49   INT32 nVScrollPos;
50
51   /* retrieve the index of the first visible fully item */
52   nFirstItem = LISTVIEW_GetFirstVisibleItem(hwnd);
53
54   /* nunber of fully visible items per row */
55   nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd);
56
57   /* nunber of fully visible items per column */
58   nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd);
59
60   if ((nItemCountPerRow > 0) && (nItemCountPerColumn > 0))
61   {
62     if (lStyle & LVS_LIST)
63     {
64       if (lStyle & WS_HSCROLL)
65       {
66         /* last visible item index */
67         nLastItem = nItemCountPerColumn * nItemCountPerRow + nFirstItem - 1;
68         if (nItem > nLastItem)
69         {
70           /* calculate new scroll position based on item index */
71           if (((nItem - nLastItem) % nItemCountPerColumn) == 0)
72             nHScrollPos = (nItem - nLastItem) / nItemCountPerColumn;
73           else
74             nHScrollPos = (nItem - nLastItem) / nItemCountPerColumn + 1;
75           SendMessage32A(hwnd, LVM_SCROLL, (WPARAM32)nHScrollPos, (LPARAM)0);
76         }
77         else if (nItem < nFirstItem)
78         {
79           /* calculate new scroll position based on item index */
80           if (((nItem - nFirstItem) % nItemCountPerColumn) == 0)
81             nHScrollPos = (nItem - nFirstItem) / nItemCountPerColumn;
82           else
83             nHScrollPos = (nItem - nFirstItem) / nItemCountPerColumn - 1;
84           SendMessage32A(hwnd, LVM_SCROLL, (WPARAM32)nHScrollPos, (LPARAM)0);
85         }
86       }
87     }
88     else if (lStyle & LVS_REPORT)
89     {
90       if (lStyle & WS_VSCROLL)
91       {
92         if (nFirstItem > 0)
93         {
94           nLastItem = nItemCountPerColumn + nFirstItem;
95         }
96         else
97 {
98           nLastItem = nItemCountPerColumn + nFirstItem - 1;
99         }
100
101         if (nItem > nLastItem)
102         {
103           /* calculate new scroll position based on item index */
104           nVScrollPos = nItem - nLastItem;
105           SendMessage32A(hwnd, LVM_SCROLL, (WPARAM32)0, (LPARAM)nVScrollPos);
106         }
107         else if (nItem < nFirstItem)
108         {
109           /* calculate new scroll position based on item index */
110           nVScrollPos = nItem - nFirstItem;
111           SendMessage32A(hwnd, LVM_SCROLL, (WPARAM32)0, (LPARAM)nVScrollPos);
112         }
113       }
114     }
115     else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON))
116     {
117       if (lStyle & WS_VSCROLL)
118       {
119         /* last visible item index */
120         nLastItem = nItemCountPerColumn * nItemCountPerRow + nFirstItem - 1;
121         if (nItem > nLastItem)
122         {
123           /* calculate new scroll position based on item index */
124           nVScrollPos = (nItem - nLastItem) / nItemCountPerRow + 1;
125           SendMessage32A(hwnd, LVM_SCROLL, (WPARAM32)0, (LPARAM)nVScrollPos);
126         }
127         else if (nItem < nFirstItem)
128         {
129           /* calculate new scroll position based on item index */
130           nHScrollPos = (nItem - nFirstItem) / nItemCountPerRow - 1;
131           SendMessage32A(hwnd, LVM_SCROLL, (WPARAM32)0, (LPARAM)nHScrollPos);
132         }
133       }
134     }
135
136     /* refresh display */
137     InvalidateRect32(hwnd, NULL, FALSE);
138     UpdateWindow32(hwnd);
139
140 }
141 }
142
143 /***
144  * DESCRIPTION:
145  * Retrieves the index of the item at coordinate (0, 0) of the client area.
146  * 
147  * PARAMETER(S):
148  * [I] HWND32 : window handle
149  *
150  * RETURN:
151  * item index
152  */
153 static INT32 LISTVIEW_GetFirstVisibleItem(HWND32 hwnd)
154 {
155   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
156   INT32 nItemCountPerRow;
157   INT32 nItemCountPerColumn;
158   INT32 nMinRange;
159   INT32 nMaxRange;
160   INT32 nHScrollPos;
161 /*  INT32 nVScrollPos; */
162   INT32 nItem = 0;
163
164   /* get number of items per column */
165   nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd);
166
167   /* get number of fully visble items per row */ 
168   nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd);
169
170   if ((nItemCountPerRow > 0) && (nItemCountPerColumn > 0))
171   {
172     if (lStyle & LVS_LIST)
173     {
174       if (lStyle & WS_HSCROLL)
175       {
176         GetScrollRange32(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
177         nHScrollPos = GetScrollPos32(hwnd, SB_HORZ);
178         if (nMinRange < nHScrollPos)
179         {
180           nItem = ((nHScrollPos - nMinRange) * nItemCountPerColumn * 
181                    nItemCountPerRow);
182         }
183       }
184     }
185     else if (lStyle & LVS_REPORT)
186     {
187       /* TO DO */
188     }
189     else if (lStyle & LVS_SMALLICON)
190     {
191       /* TO DO */
192     }
193     else if (lStyle & LVS_ICON)
194     {
195       /* TO DO */
196     }
197   }
198
199   return nItem;
200 }
201
202 /***
203  * DESCRIPTION:
204  * Retrieves the number of items per row. In other words, the number 
205  * visible display columns.
206  * 
207  * PARAMETER(S):
208  * [I] HWND32 : window handle
209  *
210  * RETURN:
211  * Number of items per row.
212  */
213 static INT32 LISTVIEW_GetItemCountPerRow(HWND32 hwnd)
214 {
215   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
216   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
217   INT32 nItemCountPerRow = 0;
218
219   if (infoPtr->nWidth > 0)
220   {
221     if (lStyle & LVS_LIST)
222     {
223       if (infoPtr->nColumnWidth > 0)
224       {
225         nItemCountPerRow = infoPtr->nWidth / infoPtr->nColumnWidth;
226         if (nItemCountPerRow == 0)
227           nItemCountPerRow = 1;
228       }
229     }
230     else if (lStyle & LVS_REPORT)
231     {
232       /* TO DO */
233     }
234     else if (lStyle & LVS_SMALLICON)
235     {
236       /* TO DO */
237     }
238     else if (lStyle & LVS_ICON)
239     {
240       /* TO DO */
241     }
242   }
243
244   return nItemCountPerRow; 
245 }
246
247 /***
248  * DESCRIPTION:
249  * Retrieves the number of items that can be displayed vertically in   
250  * the listview.
251  * 
252  * PARAMETER(S):
253  * [I] HWND32 : window handle
254  *
255  * RETURN:
256  * Number of items per column.
257  */
258 static INT32 LISTVIEW_GetItemCountPerColumn(HWND32 hwnd)
259 {
260   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
261   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
262   INT32 nItemCountPerColumn = 0;
263   
264   if (infoPtr->nHeight > 0)
265   {
266     if (lStyle & LVS_LIST)
267     {
268       if (infoPtr->nItemHeight > 0)
269         nItemCountPerColumn = infoPtr->nHeight / infoPtr->nItemHeight;
270     }
271     else if (lStyle & LVS_REPORT)
272     {
273       /* TO DO */
274     }
275     else if (lStyle & LVS_SMALLICON)
276     {
277       /* TO DO */
278     }
279     else if (lStyle & LVS_ICON)
280     {
281       /* TO DO */
282     }
283   }
284
285   return nItemCountPerColumn;
286 }
287
288 /***
289  * DESCRIPTION:
290  * Retrieves the number of columns needed to display  
291  * all the items in listview.
292  * 
293  * PARAMETER(S):
294  * [I] HWND32 : window handle
295  *
296  * RETURN:
297  * Number of columns.
298  */
299 static INT32 LISTVIEW_GetColumnCount(HWND32 hwnd)
300 {
301   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
302   LONG lStyle  = GetWindowLong32A(hwnd, GWL_STYLE);
303   INT32 nColumnCount = 0;
304   INT32 nItemCountPerColumn;
305
306   nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd);
307
308  if ((infoPtr->nItemCount > 0) && (nItemCountPerColumn > 0))
309  {
310    if (lStyle & LVS_LIST)
311    {
312      if ((infoPtr->nItemCount % nItemCountPerColumn) == 0)
313      {
314        nColumnCount = infoPtr->nItemCount / nItemCountPerColumn ;
315      }
316      else
317      {
318        nColumnCount = infoPtr->nItemCount / nItemCountPerColumn + 1;
319      }
320    }
321    else if (lStyle & LVS_REPORT)
322    {
323      /* TO DO */
324    }
325    else if (lStyle & LVS_SMALLICON)
326    {
327      /* TO DO */
328    }
329    else if (lStyle & LVS_ICON)
330    {
331      /* TO DO */
332    }
333  }
334
335   return nColumnCount;
336 }
337
338 /***
339  * DESCRIPTION:
340  * Sets the scrolling parameters.
341  * 
342  * PARAMETER(S):
343  * [I] HWND32 : window handle
344  *
345  * RETURN:
346  * None
347  */
348 static VOID LISTVIEW_SetScroll(HWND32 hwnd)
349 {
350   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
351   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
352   INT32 nColumnCount;
353   INT32 nItemCountPerRow;
354   INT32 nItemCountPerColumn;
355   INT32 nMinRange, nMaxRange;
356   INT32 nHScrollPos;
357 /*   INT32 nVScrollPos; */
358
359   nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd);
360   nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd);
361
362   if ((nItemCountPerColumn > 0) && (nItemCountPerRow > 0))
363   {
364     if (lStyle & LVS_LIST)
365     {
366       /* get number of columns needed to display all the listview items */
367       nColumnCount = LISTVIEW_GetColumnCount(hwnd);      
368       if (nColumnCount > 0) 
369       {
370         if (nColumnCount > nItemCountPerRow)
371         {
372           /* add scrollbar if not already present */
373           if (!(lStyle & WS_HSCROLL))
374           {
375             /* display scrollbar */
376             ShowScrollBar32(hwnd, SB_HORZ, TRUE);
377         
378             /* set scrollbar range and position */
379             nMaxRange = nColumnCount - nItemCountPerRow;
380             SetScrollRange32(hwnd, SB_HORZ, 0, nMaxRange, FALSE);
381             SetScrollPos32(hwnd, SB_HORZ, 0, TRUE);
382           }
383           else
384           {
385             nHScrollPos = GetScrollPos32(hwnd, SB_HORZ);
386             GetScrollRange32(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
387             if (nMaxRange != nColumnCount - nItemCountPerRow)
388             {
389               nMaxRange = nColumnCount - nItemCountPerRow;
390               SetScrollRange32(hwnd, SB_HORZ, nMinRange, nMaxRange, FALSE);
391
392               if (nHScrollPos > nMaxRange)
393                 nHScrollPos = nMaxRange;
394         
395               SetScrollPos32(hwnd, SB_HORZ, nHScrollPos, TRUE);
396             }
397           }
398           
399           /* refresh the client area */
400           InvalidateRect32(hwnd,NULL, TRUE);
401           UpdateWindow32(hwnd);
402         }
403         else
404         {
405           /* remove scrollbar if present */
406           if (lStyle & WS_HSCROLL)
407           {
408             /* hide scrollbar */
409             ShowScrollBar32(hwnd, SB_HORZ, FALSE);
410
411             /* refresh the client area */
412             InvalidateRect32(hwnd,NULL, TRUE);
413             UpdateWindow32(hwnd);
414           }
415         }
416       }
417     }
418     else if (lStyle & LVS_REPORT) 
419     {
420       HDLAYOUT hl;
421       WINDOWPOS32 wp;
422       RECT32 rc;
423         
424       rc.top = 0;
425       rc.left = 0;
426       rc.right = infoPtr->nWidth;
427       rc.bottom = infoPtr->nHeight;
428
429       hl.prc = &rc;
430       hl.pwpos = &wp;
431       SendMessage32A(infoPtr->hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hl);
432       
433       SetWindowPos32(infoPtr->hwndHeader, hwnd,
434                      wp.x, wp.y, wp.cx, wp.cy, wp.flags);
435       
436 /*       infoPtr->rcList.top += wp.cy; */
437     }
438     else if (lStyle & LVS_SMALLICON) 
439     {
440       /* TO DO */
441     }
442     else if (lStyle & LVS_ICON) 
443     {
444       /* TO DO */
445     }
446   }
447 }
448
449 /***
450  * DESCRIPTION:
451  * Modifies the state (selected and focused) of the listview items.
452  * 
453  * PARAMETER(S):
454  * [I] HWND32 : window handle
455  * [I] INT32 : focused item index
456  * [I] BOOL32 : flag for determining weither the control keys are used or not
457  * [I] BOOL32 : flag for determining the input type (mouse or keyboard)
458  *
459  * RETURN:
460  * None
461  */
462 static VOID LISTVIEW_SetItemStates(HWND32 hwnd, INT32 nFocusedItem, 
463                                    BOOL32 bVirtualKeys, BOOL32 bMouseInput)
464 {
465   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
466   WORD wShift = HIWORD(GetKeyState32(VK_SHIFT));
467   WORD wCtrl = HIWORD(GetKeyState32(VK_CONTROL));
468   INT32 i;
469   LVITEM32A lvItem;
470
471   /* initialize memory */
472   ZeroMemory(&lvItem, sizeof(LVITEM32A));
473     
474   if (wShift && (bVirtualKeys == TRUE))
475   {
476     /* reset the selected and focused states of all the items */
477     lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
478     lvItem.state = 0;
479     SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)-1, (LPARAM)&lvItem);
480
481     if (infoPtr->nSelectionMark > nFocusedItem)
482     {
483       for (i = infoPtr->nSelectionMark; i > nFocusedItem; i--)
484       {
485         /* select items */
486         lvItem.stateMask = LVIS_SELECTED;
487         lvItem.state = LVIS_SELECTED;
488         SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)i, (LPARAM)&lvItem);
489       }
490     }
491     else
492     {
493       for (i = infoPtr->nSelectionMark; i < nFocusedItem; i++)
494       {
495         /* select items */
496         lvItem.stateMask = LVIS_SELECTED;
497         lvItem.state = LVIS_SELECTED;
498         SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)i, (LPARAM)&lvItem);
499       }
500     }
501
502     /* select anf focus item */
503     lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
504     lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
505     SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)i, (LPARAM)&lvItem);
506   }
507   else
508   {
509     if (wCtrl && (bVirtualKeys == TRUE))
510     {
511       /* make sure the focus is lost */
512       lvItem.stateMask = LVIS_FOCUSED;
513       lvItem.state = 0;
514       SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)-1, (LPARAM)&lvItem);
515
516       if (bMouseInput == TRUE)
517       {
518         if (SendMessage32A(hwnd, LVM_GETITEMSTATE, (WPARAM32)nFocusedItem, 
519                            (LPARAM)LVIS_SELECTED) & LVIS_SELECTED)
520         {
521           /* focus and unselect (toggle selection) */
522           lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
523           lvItem.state = LVIS_FOCUSED;
524           SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)nFocusedItem, 
525                          (LPARAM)&lvItem);
526         }
527         else
528         {
529           /* select and focus */
530           lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
531           lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
532           SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)nFocusedItem, 
533                          (LPARAM)&lvItem);
534         }
535         
536         /* set the group selection start position */
537         infoPtr->nSelectionMark = nFocusedItem;
538       }
539       else
540       {
541         /* focus */
542         lvItem.stateMask = LVIS_FOCUSED;
543         lvItem.state = LVIS_FOCUSED;
544         SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)nFocusedItem, 
545                        (LPARAM)&lvItem);
546       }
547     }
548     else
549     {
550       /* clear selection and focus for all the items */
551       lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
552       lvItem.state = 0;
553       SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)-1, (LPARAM)&lvItem);
554
555       /* set select and focus for this particular item */
556       lvItem.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
557       lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
558       SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)nFocusedItem, 
559                      (LPARAM)&lvItem);
560
561       /* set the new group selection start position */
562       infoPtr->nSelectionMark = nFocusedItem;
563     }
564   }
565 }
566
567 /***
568  * DESCRIPTION:
569  * Draws listview items when in list display maode.
570  * 
571  * PARAMETER(S):
572  * [I] HWND32 : window handle
573  * [I] HDC32 : device context handle 
574  *
575  * RETURN:
576  * None
577  */
578 static VOID LISTVIEW_RefreshList(HWND32 hwnd, HDC32 hdc)
579 {
580   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
581     LISTVIEW_ITEM *lpItem;
582   HFONT32 hOldFont;
583   HPEN32 hPen, hOldPen;
584   INT32 nItemCountPerColumn;
585   INT32 nItemCountPerRow;
586   INT32 nSmallIconWidth;
587   SIZE32 labelSize;
588   INT32 nDrawPosX = 0;
589   INT32 nDrawPosY = 0;
590   BOOL32 bSelected;
591   RECT32 rcBoundingBox;
592   COLORREF clrHighlight;
593   COLORREF clrHighlightText;
594   INT32 i;
595   INT32 nColumn = 0;
596   INT32 nRow;
597   INT32 j;
598
599   /* get number of items per column */
600   nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd);
601
602   /* get number of items per row */
603   nItemCountPerRow = LISTVIEW_GetItemCountPerColumn(hwnd);
604   
605   if ((nItemCountPerColumn > 0) && (nItemCountPerRow > 0))
606   {
607      /* select font */
608     hOldFont = SelectObject32(hdc, infoPtr->hFont);
609
610     /* inititialize system dependent information */
611     clrHighlight = GetSysColor32(COLOR_HIGHLIGHT);
612     clrHighlightText = GetSysColor32(COLOR_HIGHLIGHTTEXT);
613     nSmallIconWidth = GetSystemMetrics32(SM_CXSMICON);  
614
615     /* select transparent brush (for drawing the focus box) */
616     SelectObject32(hdc, GetStockObject32(NULL_BRUSH)); 
617
618     /* select the doted pen (for drawing the focus box) */
619     hPen = CreatePen32(PS_DOT, 1, 0);
620     hOldPen = SelectObject32(hdc, hPen);
621
622     /* get starting index */
623     i = LISTVIEW_GetFirstVisibleItem(hwnd);
624     
625     /* DRAW ITEMS */
626     for (j = 0; i < infoPtr->nItemCount; i++, j++)
627     {
628       /* set draw position for current item */
629       nRow = j % nItemCountPerColumn;
630       nColumn = j / nItemCountPerColumn;
631       if (nRow == 0)
632         nDrawPosY = 0;
633       else
634         nDrawPosY += infoPtr->nItemHeight;
635
636       nDrawPosX = nColumn * infoPtr->nColumnWidth;
637     
638       /* get item */
639       lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, i);
640       if (lpItem != NULL)
641       {
642         if (lpItem->state & LVIS_SELECTED)
643         {
644           bSelected = TRUE;
645         
646           /* set item colors */ 
647           SetBkColor32(hdc, clrHighlight);
648           SetTextColor32(hdc, clrHighlightText);
649
650           /* set raster mode */
651           SetROP232(hdc, R2_XORPEN);
652         }
653         else
654         {
655           bSelected = FALSE;
656           
657           /* set item colors */
658           SetBkColor32(hdc, infoPtr->clrTextBk);
659           SetTextColor32(hdc, infoPtr->clrText);
660           
661           /* set raster mode */
662           SetROP232(hdc, R2_COPYPEN);
663         }
664
665         /* state images */
666         if (infoPtr->himlState != NULL)
667         {
668           /* right shift 12 bits to obtain index in image list */
669           if (bSelected == TRUE)
670             ImageList_Draw(infoPtr->himlState, lpItem->state >> 12, hdc, 
671                            nDrawPosX, nDrawPosY, ILD_SELECTED);
672           else
673             ImageList_Draw(infoPtr->himlState, lpItem->state >> 12, hdc, 
674                            nDrawPosX, nDrawPosY, ILD_NORMAL);
675         
676           nDrawPosX += nSmallIconWidth; 
677         }
678
679         /* small icons */
680         if (infoPtr->himlSmall != NULL)
681         {
682           if (bSelected == TRUE)
683             ImageList_Draw(infoPtr->himlSmall, lpItem->iImage, hdc, nDrawPosX, 
684                            nDrawPosY, ILD_SELECTED);
685           else
686             ImageList_Draw(infoPtr->himlSmall, lpItem->iImage, hdc, nDrawPosX, 
687                            nDrawPosY, ILD_NORMAL);
688         
689           nDrawPosX += nSmallIconWidth; 
690         }
691
692         /* get string size (in pixels) */
693         GetTextExtentPoint32A(hdc, lpItem->pszText, 
694                               lstrlen32A(lpItem->pszText), &labelSize);
695
696         /* define a bounding box */
697         rcBoundingBox.left = nDrawPosX;
698         rcBoundingBox.top = nDrawPosY;
699
700         /* 2 pixels for padding purposes */
701         rcBoundingBox.right = nDrawPosX + labelSize.cx + 2;
702
703         /* padding already included in infoPtr->nItemHeight */
704         rcBoundingBox.bottom = nDrawPosY + infoPtr->nItemHeight;
705       
706         /* draw text */  
707         ExtTextOut32A(hdc, nDrawPosX + 1, nDrawPosY+ 1, 
708                       ETO_OPAQUE|ETO_CLIPPED, &rcBoundingBox, 
709                       lpItem->pszText, lstrlen32A(lpItem->pszText), NULL);
710       
711         if (lpItem->state & LVIS_FOCUSED)
712           Rectangle32(hdc, rcBoundingBox.left, rcBoundingBox.top, 
713                       rcBoundingBox.right, rcBoundingBox.bottom); 
714       }
715     }
716
717     /* unselect objects */
718     SelectObject32(hdc, hOldFont);
719     SelectObject32(hdc, hOldPen);
720
721     /* delete pen */
722     DeleteObject32(hPen);
723   }
724 }
725
726 /***
727  * DESCRIPTION:
728  * Draws listview items when in report display mode.
729  * 
730  * PARAMETER(S):
731  * [I] HWND32 : window handle
732  * [I] HDC32 : device context handle 
733  *
734  * RETURN:
735  * None
736  */
737 static VOID LISTVIEW_RefreshReport(HWND32 hwnd, HDC32 hdc)
738 {
739   /* TO DO */
740 }
741
742 /***
743  * DESCRIPTION:
744  * Draws listview items when in small icon display mode.
745  * 
746  * PARAMETER(S):
747  * [I] HWND32 : window handle
748  * [I] HDC32 : device context handle 
749  *
750  * RETURN:
751  * None
752  */
753 static VOID LISTVIEW_RefreshSmallIcon(HWND32 hwnd, HDC32 hdc)
754 {
755   /* TO DO */
756 }
757
758 /***
759  * DESCRIPTION:
760  * Draws listview items when in icon display mode.
761  * 
762  * PARAMETER(S):
763  * [I] HWND32 : window handle
764  * [I] HDC32 : device context handle 
765  *
766  * RETURN:
767  * None
768  */
769 static VOID LISTVIEW_RefreshIcon(HWND32 hwnd, HDC32 hdc)
770 {
771   /* TO DO */
772 }
773
774 /***
775  * DESCRIPTION:
776  * Draws listview items.
777  * 
778  * PARAMETER(S):
779  * [I] HWND32 : window handle
780  * [I] HDC32 : device context handle 
781  *
782  * RETURN:
783  * None
784  */
785 static VOID LISTVIEW_Refresh(HWND32 hwnd, HDC32 hdc)
786 {
787   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
788   
789   if (lStyle & LVS_LIST)
790   {
791     LISTVIEW_RefreshList(hwnd, hdc);
792   }
793   else if (lStyle & LVS_REPORT)
794   {
795     LISTVIEW_RefreshReport(hwnd, hdc);
796   }
797   else if (lStyle & LVS_SMALLICON)
798   {
799     LISTVIEW_RefreshSmallIcon(hwnd, hdc);
800   }
801   else if (lStyle & LVS_ICON)
802   {
803     LISTVIEW_RefreshIcon(hwnd, hdc);
804   }
805 }
806
807
808 /***
809  * DESCRIPTION:
810  * Calculates the approximate width and height of a given number of items.
811  * 
812  * PARAMETER(S):
813  * [I] HWND32 : window handle
814  * [I] INT32 : number of items
815  * [I] INT32 : width
816  * [I] INT32 : height
817  *
818  * RETURN:
819  * Returns a DWORD. The width in the low word and the height in high word.
820  */
821 static LRESULT LISTVIEW_ApproximateViewRect(HWND32 hwnd, INT32 nItemCount, 
822                                             WORD wWidth, WORD wHeight)
823 {
824   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
825   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
826   INT32 nItemCountPerColumn = 1;
827   INT32 nColumnCount = 0;
828   DWORD dwViewRect = 0;
829
830   if (nItemCount == -1)
831     nItemCount = infoPtr->nItemCount;
832
833   if (lStyle & LVS_LIST)
834   {
835     if (wHeight == 0xFFFF)
836     {
837       /* use current height */
838       wHeight = infoPtr->nHeight;
839     }
840
841     if (wHeight < infoPtr->nItemHeight)
842     {
843       wHeight = infoPtr->nItemHeight;
844     }
845
846     if (nItemCount > 0)
847     {
848       if (infoPtr->nItemHeight > 0)
849       {
850         nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
851         if (nItemCountPerColumn == 0)
852           nItemCountPerColumn = 1;
853
854         if (nItemCount % nItemCountPerColumn != 0)
855           nColumnCount = nItemCount / nItemCountPerColumn;
856         else
857           nColumnCount = nItemCount / nItemCountPerColumn + 1;
858       }
859     }
860
861     wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
862     wWidth = nColumnCount * infoPtr->nColumnWidth + 2;
863
864     dwViewRect = MAKELONG(wWidth, wHeight);
865   }
866   else if (lStyle & LVS_REPORT)
867   {
868     /* TO DO */
869     }
870   else if (lStyle & LVS_SMALLICON)
871   {
872     /* TO DO */
873   }
874   else if (lStyle & LVS_ICON)
875   {
876     /* TO DO */
877   }
878  
879   return dwViewRect;
880 }
881
882 /***
883  * DESCRIPTION:
884  * Arranges listview items in icon display mode.
885  * 
886  * PARAMETER(S):
887  * [I] HWND32 : window handle
888  * [I] INT32 : alignment code
889  *
890  * RETURN:
891  *   SUCCESS : TRUE
892  *   FAILURE : FALSE
893  */
894 static LRESULT LISTVIEW_Arrange(HWND32 hwnd, INT32 nAlignCode)
895 {
896   /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */
897   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
898   BOOL32 bResult = FALSE;
899
900   if (lStyle & LVS_ICON)
901   {
902     switch (nAlignCode)
903     {
904     case LVA_ALIGNLEFT:
905       /* TO DO */
906       break;
907     case LVA_ALIGNTOP:
908       /* TO DO */
909       break;
910     case LVA_DEFAULT:
911       /* TO DO */
912       break;
913     case LVA_SNAPTOGRID:
914       /* TO DO */
915     }
916   }
917
918   return bResult;
919 }
920
921 /* << LISTVIEW_CreateDragImage >> */
922
923 /***
924  * DESCRIPTION:
925  * Removes all listview items.
926  * 
927  * PARAMETER(S):
928  * [I] HWND32 : window handle
929  *
930  * RETURN:
931  *   SUCCESS : TRUE
932  *   FAILURE : FALSE
933  */
934 static LRESULT LISTVIEW_DeleteAllItems(HWND32 hwnd)
935 {
936   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
937   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
938   LISTVIEW_ITEM *lpItem;
939   NMLISTVIEW nmlv;
940   BOOL32 bNotify;
941   INT32 i;
942   BOOL32 bResult = TRUE;
943
944   if (infoPtr->nItemCount > 0)
945   {
946     /* send LVN_DELETEALLITEMS notification */
947     ZeroMemory (&nmlv, sizeof (NMLISTVIEW));
948     nmlv.hdr.hwndFrom = hwnd;
949     nmlv.hdr.idFrom = lCtrlId;
950     nmlv.hdr.code     = LVN_DELETEALLITEMS;
951     nmlv.iItem        = -1;
952     bNotify = !(BOOL32)SendMessage32A(GetParent32(hwnd), WM_NOTIFY, 
953                                       (WPARAM32)lCtrlId, (LPARAM)&nmlv);
954
955     nmlv.hdr.code     = LVN_DELETEITEM;
956
957     for (i = 0; i < infoPtr->nItemCount; i++) 
958     {
959       if (bNotify == TRUE)
960       {
961         /* send LVN_DELETEITEM notification */
962         nmlv.iItem = i;
963         SendMessage32A(GetParent32(hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
964                        (LPARAM)&nmlv);
965         }
966
967       /* get item */
968       lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, i);
969       if (lpItem != NULL) 
970       {
971         /* free item string */
972         if ((lpItem->pszText != NULL) && 
973             (lpItem->pszText != LPSTR_TEXTCALLBACK32A))
974                 COMCTL32_Free (lpItem->pszText);
975
976         /* free item */
977             COMCTL32_Free (lpItem);
978         }
979     }
980
981     /* ???? needs follow up */ 
982     DPA_DeleteAllPtrs (infoPtr->hdpaItems);
983  
984     /* reset item counter */
985     infoPtr->nItemCount = 0;
986
987     /* reset scrollbar */
988     LISTVIEW_SetScroll(hwnd);
989 }
990
991   return bResult;
992 }
993
994 /***
995  * DESCRIPTION:
996  * Removes a column from the listview control.
997  * 
998  * PARAMETER(S):
999  * [I] HWND32 : window handle
1000  * [I] INT32 : column index
1001  *
1002  * RETURN:
1003  *   SUCCESS : TRUE
1004  *   FAILURE : FALSE
1005  */
1006 static LRESULT LISTVIEW_DeleteColumn(HWND32 hwnd, INT32 nColumn)
1007 {
1008 /*   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */
1009
1010     /* FIXME ??? */
1011 /* if (infoPtr->nItemCount > 0) */
1012 /* return FALSE; */
1013 /* if (!SendMessage32A(infoPtr->hwndHeader, HDM_DELETEITEM, wParam, 0)) */
1014 /* return FALSE; */
1015 /* infoPtr->nColumnCount--; */
1016 /* FIXME (listview, "semi stub!\n"); */
1017
1018     return TRUE;
1019 }
1020
1021 /***
1022  * DESCRIPTION:
1023  * Removes an item from the listview control.
1024  * 
1025  * PARAMETER(S):
1026  * [I] HWND32 : window handle
1027  * [I] INT32 : item index  
1028  *
1029  * RETURN:
1030  *   SUCCESS : TRUE
1031  *   FAILURE : FALSE
1032  */
1033 static LRESULT LISTVIEW_DeleteItem(HWND32 hwnd, INT32 nItem)
1034 {
1035   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1036   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
1037     LISTVIEW_ITEM *lpItem;
1038     NMLISTVIEW nmlv;
1039   BOOL32 bResult = FALSE;
1040
1041   if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
1042   {
1043     /* send LVN_DELETEITEM notification */
1044     ZeroMemory (&nmlv, sizeof (NMLISTVIEW));
1045     nmlv.hdr.hwndFrom = hwnd;
1046     nmlv.hdr.idFrom = lCtrlId;
1047     nmlv.hdr.code     = LVN_DELETEITEM;
1048     nmlv.iItem        = nItem;
1049     SendMessage32A(GetParent32(hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
1050                    (LPARAM)&nmlv);
1051
1052     /* remove item */
1053     lpItem = (LISTVIEW_ITEM*)DPA_DeletePtr (infoPtr->hdpaItems, nItem);
1054     if (lpItem != NULL)
1055     {
1056       /* free item string */
1057       if ((lpItem->pszText != NULL) && 
1058           (lpItem->pszText != LPSTR_TEXTCALLBACK32A))
1059         COMCTL32_Free (lpItem->pszText);
1060
1061       /* free item */
1062     COMCTL32_Free (lpItem);
1063     }
1064
1065     /* decrement item counter */
1066     infoPtr->nItemCount--;
1067
1068     /* reset some of the draw data */
1069     LISTVIEW_SetScroll(hwnd);
1070    
1071     bResult = TRUE;
1072 }
1073
1074   return bResult;
1075 }
1076
1077 /* << LISTVIEW_EditLabel >> */
1078 /* << LISTVIEW_EnsureVisible >> */
1079
1080 /***
1081  * DESCRIPTION:
1082  * Searches for an item with specific characteristics.
1083  * 
1084  * PARAMETER(S):
1085  * [I] HWND32 : window handle
1086  * [I] INT32 : base item index
1087  * [I] LPLVFINDINFO : item information to look for
1088  * 
1089  * RETURN:
1090  *   SUCCESS : index of item
1091  *   FAILURE : -1
1092  */
1093 static LRESULT LISTVIEW_FindItem(HWND32 hwnd, INT32 nStart, 
1094                                  LPLVFINDINFO lpFindInfo)
1095 {
1096 /*   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */
1097 /*   LISTVIEW_ITEM *lpItem; */
1098 /*   INT32 nItem; */
1099 /*   INT32 nEnd = infoPtr->nItemCount; */
1100 /*   BOOL32 bWrap = FALSE; */
1101 /*   if (nStart == -1) */
1102 /*     nStart = 0; */
1103 /*   else */
1104 /*     nStart++ ; */
1105 /*   if (lpFindInfo->flags & LVFI_PARAM) */
1106 /*   { */
1107 /*     for (nItem = nStart; nItem < nEnd; nItem++) */
1108 /*     { */
1109        /* get item pointer */ 
1110 /*       lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
1111 /*       if (lpItem != NULL)  */
1112 /*       { */
1113 /*         if (lpFindInfo->lParam == lpItem->lParam) */
1114 /*           return nItem; */
1115 /*       } */
1116 /*     } */
1117 /*   } */
1118 /*   else */
1119 /*   { */
1120 /*     if (lpFindInfo->flags & LVFI_PARTIAL) */
1121 /*     { */
1122 /*       for (nItem = nStart; nItem < nEnd; nItem++) */
1123 /*       { */
1124          /* get item pointer */
1125 /*         lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
1126 /*         if (lpItem)  */
1127 /*         { */
1128 /*           if (strncmp(lpItem->pszText, lpFindInfo->psz, strlen(lpFindInfo->psz))  */
1129 /*               == 0) */
1130 /*             return nItem; */
1131 /*         } */
1132 /*       } */
1133 /*     } */
1134
1135 /*     if (lpFindInfo->flags & LVFI_STRING) */
1136 /*     { */
1137 /*       for (nItem = nStart; nItem < nEnd; nItem++) */
1138 /*       { */
1139          /* get item pointer */
1140 /*         lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
1141 /*         if (lpItem != NULL)  */
1142 /*         { */
1143 /*           if (strcmp(lpItem->pszText, lpFindInfo->psz) == 0) */
1144 /*             return nItem; */
1145 /*         } */
1146 /*       } */
1147 /*     } */
1148     
1149 /*     if ((lpFindInfo->flags & LVFI_WRAP) && nStart)  */
1150 /*     { */
1151 /*       nEnd = nStart; */
1152 /*       nStart = 0; */
1153 /*       bWrap = TRUE; */
1154 /*     } */
1155 /*     else */
1156 /*       bWrap = FALSE; */
1157
1158    return -1; 
1159 }
1160
1161 /***
1162  * DESCRIPTION:
1163  * Retrieves the background color of the listview control.
1164  * 
1165  * PARAMETER(S):
1166  * [I] HWND32 : window handle
1167  *
1168  * RETURN:
1169  * COLORREF associated with the background.
1170  */
1171 static LRESULT LISTVIEW_GetBkColor(HWND32 hwnd)
1172 {
1173   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1174
1175     return infoPtr->clrBk;
1176 }
1177
1178 /***
1179  * DESCRIPTION:
1180  * Retrieves the background image of the listview control.
1181  * 
1182  * PARAMETER(S):
1183  * [I] HWND32 : window handle
1184  * [O] LPLVMKBIMAGE : background image information
1185  *
1186  * RETURN:
1187  *   SUCCESS : TRUE
1188  *   FAILURE : FALSE
1189  */
1190 /* static LRESULT LISTVIEW_GetBkImage(HWND32 hwnd, LPLVBKIMAGE lpBkImage) */
1191 /* { */
1192 /*   return FALSE; */
1193 /* } */
1194
1195 /* << LISTVIEW_GetCallbackMask >> */
1196
1197 /***
1198  * DESCRIPTION:
1199  * Retrieves column attributes.
1200  * 
1201  * PARAMETER(S):
1202  * [I] HWND32 : window handle
1203  * [I] INT32 :  column index
1204  * [IO] LPLVCOLUMN32A : column information
1205  *
1206  * RETURN:
1207  *   SUCCESS : TRUE
1208  *   FAILURE : FALSE
1209  */
1210 static LRESULT LISTVIEW_GetColumn32A(HWND32 hwnd, INT32 nIndex, 
1211                                      LPLVCOLUMN32A lpColumn)
1212 {
1213   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1214     HDITEM32A hdi;
1215
1216   if (lpColumn == NULL)
1217         return FALSE;
1218
1219     ZeroMemory (&hdi, sizeof(HDITEM32A));
1220
1221   if (lpColumn->mask & LVCF_FMT)
1222         hdi.mask |= HDI_FORMAT;
1223
1224   if (lpColumn->mask & LVCF_WIDTH)
1225         hdi.mask |= HDI_WIDTH;
1226
1227   if (lpColumn->mask & LVCF_TEXT)
1228         hdi.mask |= (HDI_TEXT | HDI_FORMAT);
1229
1230   if (lpColumn->mask & LVCF_IMAGE)
1231         hdi.mask |= HDI_IMAGE;
1232
1233   if (lpColumn->mask & LVCF_ORDER)
1234         hdi.mask |= HDI_ORDER;
1235
1236     if (!SendMessage32A (infoPtr->hwndHeader, HDM_GETITEM32A,
1237                        (WPARAM32)nIndex, (LPARAM)&hdi))
1238         return FALSE;
1239
1240   if (lpColumn->mask & LVCF_FMT) 
1241   {
1242     lpColumn->fmt = 0;
1243
1244         if (hdi.fmt & HDF_LEFT)
1245       lpColumn->fmt |= LVCFMT_LEFT;
1246         else if (hdi.fmt & HDF_RIGHT)
1247       lpColumn->fmt |= LVCFMT_RIGHT;
1248         else if (hdi.fmt & HDF_CENTER)
1249       lpColumn->fmt |= LVCFMT_CENTER;
1250
1251         if (hdi.fmt & HDF_IMAGE)
1252       lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
1253     }
1254
1255   if (lpColumn->mask & LVCF_WIDTH)
1256     lpColumn->cx = hdi.cxy;
1257
1258   if ((lpColumn->mask & LVCF_TEXT) && (lpColumn->pszText) && (hdi.pszText))
1259     lstrcpyn32A (lpColumn->pszText, hdi.pszText, lpColumn->cchTextMax);
1260
1261   if (lpColumn->mask & LVCF_IMAGE)
1262     lpColumn->iImage = hdi.iImage;
1263
1264   if (lpColumn->mask & LVCF_ORDER)
1265     lpColumn->iOrder = hdi.iOrder;
1266
1267     return TRUE;
1268 }
1269
1270 /* << LISTVIEW_GetColumn32W >> */
1271 /* << LISTVIEW_GetColumnOrderArray >> */
1272
1273 /***
1274  * DESCRIPTION:
1275  * Retrieves the column width when list or report display mode.
1276  * 
1277  * PARAMETER(S):
1278  * [I] HWND32 : window handle
1279  * [I] int32 : column index
1280  *
1281  * RETURN:
1282  *   SUCCESS : column width
1283  *   FAILURE : zero 
1284  */
1285 static LRESULT LISTVIEW_GetColumnWidth(HWND32 hwnd, INT32 nColumn)
1286 {
1287   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1288   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
1289     HDITEM32A hdi;
1290   INT32 nColumnWidth = 0;
1291
1292   if ((lStyle & LVS_LIST) || (lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON))
1293   {
1294     nColumnWidth = infoPtr->nColumnWidth;
1295   }
1296   else if (lStyle & LVS_REPORT)
1297   {
1298     /* verify validity of index */
1299     if ((nColumn >= 0) && (nColumn < infoPtr->nColumnCount))
1300     {
1301       /* get column width from header */
1302     hdi.mask = HDI_WIDTH;
1303     if (SendMessage32A (infoPtr->hwndHeader, HDM_GETITEM32A,
1304                          (WPARAM32)nColumn, (LPARAM)&hdi))
1305         nColumnWidth = hdi.cxy;
1306     }
1307   }
1308
1309   return nColumnWidth;
1310 }
1311
1312 /***
1313  * DESCRIPTION:
1314  * In list or report display mode, retrieves the number of items that can fit 
1315  * vertically in the visible area. In icon or small icon display mode, 
1316  * retrieves the total number of visible items.
1317  * 
1318  * PARAMETER(S):
1319  * [I] HWND32 : window handle
1320  *
1321  * RETURN:
1322  * Number of fully visible items.
1323  */
1324 static LRESULT LISTVIEW_GetCountPerPage(HWND32 hwnd)
1325 {
1326   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1327   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
1328   INT32 nItemCount = 0;
1329   INT32 nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd);
1330   INT32 nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd);
1331
1332   if (lStyle & LVS_LIST)
1333   {
1334     if ((nItemCountPerRow > 0) && (nItemCountPerColumn > 0))
1335     {
1336       nItemCount = nItemCountPerRow * nItemCountPerColumn;
1337     }
1338   }
1339   else if (lStyle & LVS_REPORT)
1340   {
1341     nItemCount = nItemCountPerColumn;
1342   }
1343   else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON))
1344   {
1345     nItemCount = infoPtr->nItemCount;
1346   }
1347
1348   return nItemCount;
1349 }
1350
1351 /* << LISTVIEW_GetEditControl >> */
1352 /* << LISTVIEW_GetExtendedListViewStyle >> */
1353
1354 /***
1355  * DESCRIPTION:
1356  * Retrieves a header handle.
1357  * 
1358  * PARAMETER(S):
1359  * [I] HWND32 : window handle
1360  *
1361  * RETURN:
1362  * Header handle.
1363  */
1364 static LRESULT LISTVIEW_GetHeader(HWND32 hwnd)
1365 {
1366   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1367
1368     return infoPtr->hwndHeader;
1369 }
1370
1371 /* << LISTVIEW_GetHotCursor >> */
1372 /* << LISTVIEW_GetHotItem >> */
1373 /* << LISTVIEW_GetHoverTime >> */
1374
1375 /***
1376  * DESCRIPTION:
1377  * Retrieves an image list handle.
1378  * 
1379  * PARAMETER(S):
1380  * [I] HWND32 : window handle
1381  * [I] INT32 : image list identifier 
1382  * 
1383  * RETURN:
1384  *   SUCCESS : image list handle
1385  *   FAILURE : NULL
1386  */
1387 static LRESULT LISTVIEW_GetImageList(HWND32 hwnd, INT32 nImageList)
1388 {
1389   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1390   HIMAGELIST himl = NULL;
1391
1392   switch (nImageList) 
1393   {
1394         case LVSIL_NORMAL:
1395     himl = infoPtr->himlNormal;
1396         case LVSIL_SMALL:
1397     himl = infoPtr->himlSmall;
1398         case LVSIL_STATE:
1399     himl = infoPtr->himlState;
1400     }
1401
1402   return (LRESULT)himl;
1403 }
1404
1405
1406 /* << LISTVIEW_GetISearchString >> */
1407
1408 /***
1409  * DESCRIPTION:
1410  * Retrieves item attributes.
1411  * 
1412  * PARAMETER(S):
1413  * [I] HWND32 : window handle
1414  * [IO] LPLVITEM32A : item info
1415  * 
1416  * RETURN:
1417  *   SUCCESS : TRUE 
1418  *   FAILURE : FALSE
1419  */
1420 static LRESULT LISTVIEW_GetItem32A(HWND32 hwnd, LPLVITEM32A lpItem)
1421 {
1422   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1423   LISTVIEW_ITEM *lpListItem;
1424   BOOL32 bResult = FALSE;
1425
1426   if (lpItem != NULL)
1427   {
1428     if ((lpItem->iItem >= 0) && (lpItem->iItem < infoPtr->nItemCount))
1429     {
1430       /* get item */
1431       lpListItem = DPA_GetPtr(infoPtr->hdpaItems, lpItem->iItem);
1432       if (lpListItem != NULL)
1433       {
1434         /* not tested for subitem > 0 */
1435         lpListItem += lpItem->iSubItem;
1436         if (lpListItem != NULL) 
1437         {
1438           /* retrieve valid data */
1439     if (lpItem->mask & LVIF_STATE)
1440             lpItem->state = lpListItem->state & lpItem->stateMask;
1441
1442           if (lpItem->mask & LVIF_TEXT) 
1443           {
1444             if (lpListItem->pszText == LPSTR_TEXTCALLBACK32A)
1445             lpItem->pszText = LPSTR_TEXTCALLBACK32A;
1446         else
1447               Str_GetPtr32A(lpListItem->pszText, lpItem->pszText, 
1448                            lpItem->cchTextMax);
1449     }
1450
1451     if (lpItem->mask & LVIF_IMAGE)
1452             lpItem->iImage = lpListItem->iImage;
1453
1454     if (lpItem->mask & LVIF_PARAM)
1455             lpItem->lParam = lpListItem->lParam;
1456
1457     if (lpItem->mask & LVIF_INDENT)
1458             lpItem->iIndent = lpListItem->iIndent;
1459
1460           bResult = TRUE;
1461 }
1462       }
1463     }
1464   }
1465
1466   return bResult;
1467 }
1468
1469 /* << LISTVIEW_GetItem32W >> */
1470 /* << LISTVIEW_GetHotCursor >> */
1471 /* << LISTVIEW_GetHotItem >> */
1472 /* << LISTVIEW_GetHoverTime >> */
1473
1474 /***
1475  * DESCRIPTION:
1476  * Retrieves the number of items in the listview control.
1477  * 
1478  * PARAMETER(S):
1479  * [I] HWND32 : window handle
1480  * 
1481  * RETURN:
1482  * Number of items.
1483  */
1484 static LRESULT LISTVIEW_GetItemCount(HWND32 hwnd)
1485 {
1486   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLong32A(hwnd, 0);
1487
1488     return infoPtr->nItemCount;
1489 }
1490
1491 /***
1492  * DESCRIPTION:
1493  * Retrieves the position (upper-left) of the listview control item.
1494  * 
1495  * PARAMETER(S):
1496  * [I] HWND32 : window handle
1497  * [I] INT32 : item index
1498  * [O] LPPOINT32 : coordinate information
1499  *
1500  * RETURN:
1501  *   SUCCESS : TRUE
1502  *   FAILURE : FALSE
1503  */
1504 static LRESULT LISTVIEW_GetItemPosition(HWND32 hwnd, INT32 nItem, 
1505                                         LPPOINT32 lpPt)
1506 {
1507   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1508   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
1509   INT32 nColumn;
1510   INT32 nRow;
1511   BOOL32 bResult = FALSE;
1512   INT32 nItemCountPerColumn;
1513   INT32 nItemCountPerRow;
1514   INT32 nFirstItem;
1515   INT32 nLastItem;
1516
1517   if ((nItem >= 0) && (nItem < infoPtr->nItemCount) && (lpPt != NULL))
1518   {
1519     if (lStyle & LVS_LIST)
1520 {
1521       nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd);
1522       nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd);
1523
1524       if ((nItemCountPerColumn > 0) && (nItemCountPerRow > 0))
1525       {
1526         nFirstItem = LISTVIEW_GetFirstVisibleItem(hwnd); 
1527         nLastItem = nFirstItem + nItemCountPerRow * nItemCountPerRow - 1;
1528
1529         if ((nItem >= nFirstItem) || (nItem <= nLastItem))
1530         {
1531           nItem -= nFirstItem; 
1532
1533           /* get column */
1534           nColumn = nItem / nItemCountPerColumn;
1535
1536           /* get row */
1537           nRow = nItem % nItemCountPerColumn;
1538
1539           /* X coordinate of the column */
1540           lpPt->x = nColumn * infoPtr->nColumnWidth;
1541
1542           /* Y coordinate of the item */
1543           lpPt->y = nRow * infoPtr->nItemHeight;
1544
1545           bResult = TRUE;
1546         }
1547       }
1548       else if (lStyle & LVS_REPORT)
1549       {
1550         /* TO DO */
1551       }
1552       else if (lStyle & LVS_SMALLICON)
1553       {
1554         /* TO DO */
1555       }
1556       else if (lStyle & LVS_ICON)
1557 {
1558         /* TO DO */
1559       }
1560     }
1561   }
1562
1563   return bResult;
1564 }
1565
1566 /***
1567  * DESCRIPTION:
1568  * Retrieves the bounding rectangle for a listview control item.
1569  * 
1570  * PARAMETER(S):
1571  * [I] HWND32 : window handle
1572  * [I] INT32 : item index
1573  * [IO] LPRECT32 : bounding rectangle coordinates
1574  * 
1575  * RETURN:
1576  *   SUCCESS : TRUE
1577  *   FAILURE : FALSE
1578  */
1579 static LRESULT LISTVIEW_GetItemRect(HWND32 hwnd, INT32 nItem, LPRECT32 lpRect)
1580 {
1581   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1582   LISTVIEW_ITEM *lpItem;
1583   POINT32 pt;
1584   INT32 nLabelWidth;
1585   BOOL32 bResult = FALSE;
1586   INT32 nSmallIconWidth;
1587
1588   nSmallIconWidth = GetSystemMetrics32(SM_CXSMICON);
1589
1590   if ((nItem < 0) || (nItem >= infoPtr->nItemCount) || (lpRect == NULL))
1591     return FALSE;
1592
1593   /* get item */
1594   lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem);
1595   if (lpItem == NULL) 
1596     return FALSE;
1597
1598   if (!SendMessage32A(hwnd, LVM_GETITEMPOSITION, (WPARAM32)nItem, (LPARAM)&pt))
1599     return FALSE;
1600
1601   nLabelWidth = SendMessage32A(hwnd, LVM_GETSTRINGWIDTH32A, (WPARAM32)0, 
1602                                (LPARAM)lpItem->pszText);
1603   switch(lpRect->left) 
1604   { 
1605   case LVIR_BOUNDS: 
1606     lpRect->left = pt.x;
1607     lpRect->top = pt.y;
1608     lpRect->right = lpRect->left + nSmallIconWidth + nLabelWidth;
1609     lpRect->bottom = lpRect->top + infoPtr->nItemHeight;
1610     bResult = TRUE;
1611     break;
1612   case LVIR_ICON:
1613     lpRect->left = pt.x;
1614     lpRect->top = pt.y;
1615     lpRect->right = lpRect->left + nSmallIconWidth;
1616     lpRect->bottom = lpRect->top + infoPtr->nItemHeight;
1617     bResult = TRUE;
1618     break;
1619   case LVIR_LABEL: 
1620     lpRect->left = pt.x + nSmallIconWidth;
1621     lpRect->top = pt.y;
1622     lpRect->right = lpRect->left + nLabelWidth;
1623     lpRect->bottom = infoPtr->nItemHeight;
1624     bResult = TRUE;
1625     break;
1626   case LVIR_SELECTBOUNDS:
1627     /* TO DO */
1628     break;
1629   }
1630         
1631   return bResult;
1632 }
1633
1634 /***
1635  * DESCRIPTION:
1636  * Retrieves the spacing between listview control items.
1637  * 
1638  * PARAMETER(S):
1639  * [I] HWND32 : window handle
1640  * [I] BOOL32 : small icon (TRUE) or large icon (FALSE)
1641  *
1642  * RETURN:
1643  * Horizontal + vertical spacing
1644  */
1645 static LRESULT LISTVIEW_GetItemSpacing(HWND32 hwnd, BOOL32 bSmall)
1646 {
1647   INT32 nSmallIconHSpacing;
1648   INT32 nSmallIconVSpacing;
1649   INT32 nIconHSpacing;
1650   INT32 nIconVSpacing;
1651   LONG lResult = 0;
1652
1653   if (bSmall == TRUE)
1654   {
1655     /* ??? */
1656     nSmallIconHSpacing = 0;
1657     nSmallIconVSpacing = 0;
1658     lResult = MAKELONG(nSmallIconHSpacing, nSmallIconVSpacing);
1659     }
1660     else
1661   {
1662     nIconHSpacing = GetSystemMetrics32(SM_CXICONSPACING);
1663     nIconVSpacing = GetSystemMetrics32(SM_CYICONSPACING);
1664     lResult = MAKELONG(nIconHSpacing, nIconVSpacing);
1665   }
1666   
1667   return lResult;
1668 }
1669
1670 /***
1671  * DESCRIPTION:
1672  * Retrieves the state of a listview control item.
1673  * 
1674  * PARAMETER(S):
1675  * [I] HWND32 : window handle
1676  * [I] INT32 : item index
1677  * [I] UINT32 : state mask
1678  * 
1679  * RETURN:
1680  * State specified by the mask.
1681  */
1682 static LRESULT LISTVIEW_GetItemState(HWND32 hwnd, INT32 nItem, UINT32 uMask)
1683 {
1684   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1685   LISTVIEW_ITEM *lpItem;
1686   INT32 nState = 0;
1687
1688   if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
1689   {
1690     lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem);
1691     if (lpItem != NULL) 
1692       nState =   lpItem->state & uMask;
1693   }
1694
1695   return nState;
1696 }
1697
1698 /***
1699  * DESCRIPTION:
1700  * Retrieves the text of a listview control item or subitem. 
1701  * 
1702  * PARAMETER(S):
1703  * [I] HWND32 : window handle
1704  * [I] INT32 : item index
1705  * [IO] LPLVITEM32A : item information
1706  * 
1707  * RETURN:
1708  * None
1709  */
1710 static VOID LISTVIEW_GetItemText32A(HWND32 hwnd, INT32 nItem, 
1711                                     LPLVITEM32A lpItem)
1712 {
1713   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1714   LISTVIEW_ITEM *lpListItem;
1715
1716   if ((nItem < 0) || (nItem >= infoPtr->nItemCount) || (lpItem == NULL))
1717     return;
1718
1719   lpListItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem);
1720   if (lpListItem == NULL)
1721     return;
1722
1723   lpListItem += lpItem->iSubItem;
1724   if (lpListItem == NULL)
1725     return;
1726
1727   if (lpListItem->pszText == LPSTR_TEXTCALLBACK32A) 
1728     lpItem->pszText = LPSTR_TEXTCALLBACK32A;
1729     else
1730     Str_GetPtr32A(lpListItem->pszText, lpItem->pszText, lpItem->cchTextMax);
1731 }
1732
1733 /***
1734  * DESCRIPTION:
1735  * Searches for an item based on properties + relationships.
1736  * 
1737  * PARAMETER(S):
1738  * [I] HWND32 : window handle
1739  * [I] INT32 : item index
1740  * [I] UINT32 : relationship flag
1741  * 
1742  * RETURN:
1743  *   SUCCESS : item index
1744  *   FAILURE : -1
1745  */
1746 static LRESULT LISTVIEW_GetNextItem (HWND32 hwnd, INT32 nItem, UINT32 uFlags)
1747 {
1748   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1749   INT32 nResult = -1;
1750
1751   /* start at begin */
1752   if (nItem == -1)
1753     nItem = 0;
1754
1755   if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
1756   {
1757     /* TO DO */
1758 }
1759
1760   return nResult;
1761 }
1762
1763 /* << LISTVIEW_GetNumberOfWorkAreas >> */
1764
1765 /***
1766  * DESCRIPTION:
1767  * Retrieves the current origin when in icon or small icon display mode.
1768  * 
1769  * PARAMETER(S):
1770  * [I] HWND32 : window handle
1771  * [O] LPPOINT32 : coordinate information
1772  * 
1773  * RETURN:
1774  *   SUCCESS : TRUE
1775  *   FAILURE : FALSE
1776  */
1777 static LRESULT LISTVIEW_GetOrigin(HWND32 hwnd, LPPOINT32 lpOrigin)
1778 {
1779   LONG lStyle = GetWindowLong32A(hwnd, GWL_ID);
1780   BOOL32 bResult = FALSE;
1781
1782   if (lStyle & LVS_SMALLICON) 
1783   {
1784     /* TO DO */
1785   }
1786   else if (lStyle & LVS_ICON)
1787   {
1788     /* TO DO */
1789   }
1790
1791   return bResult;
1792 }
1793
1794 /***
1795  * DESCRIPTION:
1796  * Retrieves the number of items that are marked as selected.
1797  * 
1798  * PARAMETER(S):
1799  * [I] HWND32 : window handle
1800  * 
1801  * RETURN:
1802  * Number of items selected.
1803  */
1804 static LRESULT LISTVIEW_GetSelectedCount(HWND32 hwnd)
1805 {
1806   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1807   LISTVIEW_ITEM *lpItem;
1808   INT32 nSelectedCount = 0;
1809   INT32 i;
1810
1811   for (i = 0; i < infoPtr->nItemCount; i++)
1812   {
1813     lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, i);
1814     if (lpItem != NULL)
1815     {
1816       if (lpItem->state & LVIS_SELECTED)
1817         nSelectedCount++;
1818     }
1819   }
1820
1821   return nSelectedCount;
1822 }
1823
1824 /***
1825  * DESCRIPTION:
1826  * Retrieves item index that marks the start of a multiple selection.
1827  * 
1828  * PARAMETER(S):
1829  * [I] HWND32 : window handle
1830  * 
1831  * RETURN:
1832  * Index number or -1 if there is no selection mark.
1833  */
1834 static LRESULT LISTVIEW_GetSelectionMark(HWND32 hwnd)
1835 {
1836   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1837   INT32 nResult = -1;
1838
1839   if (SendMessage32A(hwnd, LVM_GETSELECTEDCOUNT, (WPARAM32)0, (LPARAM)0) != 0)
1840     nResult = infoPtr->nSelectionMark;
1841
1842   return nResult;
1843 }
1844
1845 /***
1846  * DESCRIPTION:
1847  * Retrieves the width of a string.
1848  * 
1849  * PARAMETER(S):
1850  * [I] HWND32 : window handle
1851  * 
1852  * RETURN:
1853  *   SUCCESS : string width (in pixels)
1854  *   FAILURE : zero
1855  */
1856 static LRESULT LISTVIEW_GetStringWidth32A(HWND32 hwnd, LPCSTR lpsz)
1857 {
1858   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1859     HFONT32 hFont, hOldFont;
1860     HDC32 hdc;
1861   SIZE32 textSize;
1862   INT32 nResult = 0;
1863
1864   if (lpsz != NULL)
1865   {
1866     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (SYSTEM_FONT);
1867     hdc = GetDC32(hwnd);
1868     hOldFont = SelectObject32 (hdc, hFont);
1869     GetTextExtentPoint32A(hdc, lpsz, lstrlen32A(lpsz), &textSize);
1870     SelectObject32 (hdc, hOldFont);
1871     ReleaseDC32(hwnd, hdc);
1872     nResult = textSize.cx;
1873   }
1874
1875   return nResult;
1876 }
1877
1878 /***
1879  * DESCRIPTION:
1880  * Retrieves the text backgound color.
1881  * 
1882  * PARAMETER(S):
1883  * [I] HWND32 : window handle
1884  * 
1885  * RETURN:
1886  * COLORREF associated with the the background.
1887  */
1888 static LRESULT LISTVIEW_GetTextBkColor(HWND32 hwnd)
1889 {
1890   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLong32A(hwnd, 0);
1891
1892   return infoPtr->clrTextBk;
1893 }
1894
1895 /***
1896  * DESCRIPTION:
1897  * Retrieves the text color.
1898  * 
1899  * PARAMETER(S):
1900  * [I] HWND32 : window handle
1901  * 
1902  * RETURN:
1903  * COLORREF associated with the text.
1904  */
1905 static LRESULT LISTVIEW_GetTextColor(HWND32 hwnd)
1906 {
1907   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLong32A(hwnd, 0);
1908
1909   return infoPtr->clrText;
1910 }
1911
1912 /***
1913  * DESCRIPTION:
1914  * Retrieves the bounding rectangle of all the items.
1915  * 
1916  * PARAMETER(S):
1917  * [I] HWND32 : window handle
1918  * [O] LPRECT32 : bounding rectangle
1919  *
1920  * RETURN:
1921  *   SUCCESS : TRUE
1922  *   FAILURE : FALSE
1923  */
1924 static LRESULT LISTVIEW_GetViewRect(HWND32 hwnd, LPRECT32 lpBoundingRect)
1925 {
1926   /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */
1927   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
1928   BOOL32 bResult = FALSE;
1929
1930   if (lpBoundingRect != NULL)
1931   {
1932     if ((lStyle & LVS_ICON) || (lStyle & LVS_SMALLICON))
1933     {
1934       /* TO DO */
1935     }
1936   }
1937
1938   return bResult;
1939 }
1940
1941 /***
1942  * DESCRIPTION:
1943  * Determines item index when in small icon view.
1944  * 
1945  * PARAMETER(S):
1946  * [I] HWND32 : window handle
1947  * [IO] LPLVHITTESTINFO : hit test information
1948  *
1949  * RETURN:
1950  *   SUCCESS : item index
1951  *   FAILURE : -1
1952  */
1953 static LRESULT HitTestSmallIconView(HWND32 hwnd, LPLVHITTESTINFO lpHitTestInfo)
1954 {
1955   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
1956   LISTVIEW_ITEM *lpItem;
1957   INT32 nColumn;
1958   INT32 nRow;
1959   INT32 nItem = 0;
1960   INT32 nLabelWidth;
1961   INT32 nOffset;
1962   INT32 nPosX = 0;
1963   INT32 nSmallIconWidth;
1964   INT32 nItemCountPerRow;
1965
1966   /* get column */
1967   nColumn = lpHitTestInfo->pt.x / infoPtr->nColumnWidth;
1968
1969   /* get row */
1970   nRow = lpHitTestInfo->pt.y / infoPtr->nItemHeight;
1971   
1972   /* calculate offset from start of column (in pixels) */
1973   nOffset = lpHitTestInfo->pt.x % infoPtr->nColumnWidth;
1974
1975   /* get recommended width of a small icon */
1976   nSmallIconWidth = GetSystemMetrics32(SM_CXSMICON);
1977
1978   /* calculate index */
1979   nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd);
1980   nItem = nRow * nItemCountPerRow + LISTVIEW_GetFirstVisibleItem(hwnd) + nColumn;
1981
1982   /* verify existance of item */
1983   if (nItem < infoPtr->nItemCount)
1984   {
1985     /* get item */
1986     lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem);
1987     if (lpItem != NULL)
1988     {
1989       if (infoPtr->himlState != NULL)
1990       {
1991         nPosX += nSmallIconWidth;
1992         if (nOffset <= nPosX)
1993         {
1994           lpHitTestInfo->flags = LVHT_ONITEMSTATEICON | LVHT_ONITEM;
1995           lpHitTestInfo->iItem = nItem;
1996           lpHitTestInfo->iSubItem = 0;
1997           return nItem;
1998         }
1999       }
2000
2001       if (infoPtr->himlSmall != NULL)
2002       {
2003         nPosX += nSmallIconWidth;
2004         if (nOffset <= nPosX)
2005         {
2006           lpHitTestInfo->flags = LVHT_ONITEMICON | LVHT_ONITEM;
2007           lpHitTestInfo->iItem = nItem;
2008           lpHitTestInfo->iSubItem = 0;
2009           return nItem;
2010 }
2011       }
2012
2013       /* get width of label in pixels */
2014       nLabelWidth = SendMessage32A(hwnd, LVM_GETSTRINGWIDTH32A, (WPARAM32)0, 
2015                                    (LPARAM)lpItem->pszText); 
2016       nLabelWidth += nPosX;
2017
2018       if (nOffset <= nLabelWidth)
2019 {
2020         lpHitTestInfo->flags = LVHT_ONITEMLABEL | LVHT_ONITEM;
2021         lpHitTestInfo->iItem = nItem;
2022         lpHitTestInfo->iSubItem = 0;
2023           return nItem;
2024       }
2025     }
2026   }
2027
2028   /* hit is not on an item */
2029   lpHitTestInfo->flags = LVHT_NOWHERE; 
2030      
2031   return -1;
2032 }
2033
2034 /***
2035  * DESCRIPTION:
2036  * Determines item index when in list display mode.
2037  * 
2038  * PARAMETER(S):
2039  * [I] HWND32 : window handle
2040  * [IO] LPLVHITTESTINFO : hit test information
2041  *
2042  * RETURN:
2043  *   SUCCESS : item index
2044  *   FAILURE : -1
2045  */
2046 static LRESULT HitTestListView(HWND32 hwnd, LPLVHITTESTINFO lpHitTestInfo)
2047 {
2048   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
2049   LISTVIEW_ITEM *lpItem;
2050   INT32 nColumn;
2051   INT32 nRow;
2052   INT32 nItem = 0;
2053   INT32 nLabelWidth;
2054   INT32 nOffset;
2055   INT32 nPosX = 0;
2056   INT32 nSmallIconWidth;
2057   INT32 nItemCountPerColumn;
2058
2059   /* get column */
2060   nColumn = lpHitTestInfo->pt.x / infoPtr->nColumnWidth;
2061
2062   /* get row */ 
2063   nRow = lpHitTestInfo->pt.y / infoPtr->nItemHeight;
2064   
2065   /* calculate offset from start of column (in pixels) */
2066   nOffset = lpHitTestInfo->pt.x % infoPtr->nColumnWidth;
2067
2068   /* get recommended width of a small icon */
2069   nSmallIconWidth = GetSystemMetrics32(SM_CXSMICON);
2070
2071   /* calculate index */
2072   nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd);
2073   nItem = (nColumn * nItemCountPerColumn + LISTVIEW_GetFirstVisibleItem(hwnd) 
2074            + nRow);
2075
2076   /* verify existance of item */
2077   if (nItem < infoPtr->nItemCount)
2078   {
2079     /* get item */
2080     lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem);
2081     if (lpItem != NULL)
2082     {
2083       if (infoPtr->himlState != NULL)
2084       {
2085         nPosX += nSmallIconWidth;
2086         if (nOffset <= nPosX)
2087         {
2088           lpHitTestInfo->flags = LVHT_ONITEMSTATEICON | LVHT_ONITEM;
2089           lpHitTestInfo->iItem = nItem;
2090           lpHitTestInfo->iSubItem = 0;
2091           return nItem;
2092         }
2093       }
2094
2095       if (infoPtr->himlSmall != NULL)
2096       {
2097         nPosX += nSmallIconWidth;
2098         if (nOffset <= nPosX)
2099 {
2100           lpHitTestInfo->flags = LVHT_ONITEMICON | LVHT_ONITEM;
2101           lpHitTestInfo->iItem = nItem;
2102           lpHitTestInfo->iSubItem = 0;
2103           return nItem;
2104         }
2105       }
2106
2107       /* get width of label in pixels */
2108       nLabelWidth = SendMessage32A(hwnd, LVM_GETSTRINGWIDTH32A, (WPARAM32)0, 
2109                                    (LPARAM)lpItem->pszText); 
2110       nLabelWidth += nPosX;
2111
2112       if (nOffset <= nLabelWidth)
2113       {
2114         lpHitTestInfo->flags = LVHT_ONITEMLABEL | LVHT_ONITEM;
2115         lpHitTestInfo->iItem = nItem;
2116         lpHitTestInfo->iSubItem = 0;
2117           return nItem;
2118       }
2119     }
2120   }
2121
2122   /* hit is not on an item */
2123   lpHitTestInfo->flags = LVHT_NOWHERE; 
2124      
2125     return -1;
2126 }
2127
2128 /***
2129  * DESCRIPTION:
2130  * Determines wich listview item is located at the specified position.
2131  * 
2132  * PARAMETER(S):
2133  * [I] HWND32 : window handle
2134  * [IO} LPLVHITTESTINFO : hit test information
2135  *
2136  * RETURN:
2137  *   SUCCESS : item index
2138  *   FAILURE : -1
2139  */
2140 static LRESULT LISTVIEW_HitTest(HWND32 hwnd, LPLVHITTESTINFO lpHitTestInfo)
2141 {
2142   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
2143
2144   if (lStyle & LVS_LIST)
2145     return HitTestListView(hwnd, lpHitTestInfo);
2146   else if (lStyle & LVS_REPORT)
2147   {
2148     /* TO DO */
2149   }
2150   else if (lStyle & LVS_SMALLICON)
2151   {
2152     return HitTestSmallIconView(hwnd, lpHitTestInfo);
2153   }
2154   else if (lStyle & LVS_ICON)
2155   {
2156     /* TO DO */
2157   }
2158
2159   return -1;
2160 }
2161
2162 /***
2163  * DESCRIPTION:
2164  * Inserts a new column.
2165  * 
2166  * PARAMETER(S):
2167  * [I] HWND32 : window handle
2168  * [I] INT32 : column index
2169  * [I] LPLVCOLUMN32A : column information
2170  *
2171  * RETURN:
2172  *   SUCCESS : new column index
2173  *   FAILURE : -1
2174  */
2175 static LRESULT LISTVIEW_InsertColumn32A(HWND32 hwnd, INT32 nIndex, 
2176                                         LPLVCOLUMN32A lpColumn)
2177 {
2178   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLong32A(hwnd, 0);
2179     HDITEM32A hdi;
2180     INT32 nResult;
2181
2182   if ((lpColumn == NULL) || (infoPtr->nItemCount > 0))
2183         return -1;
2184
2185   FIXME (listview, "(%d %p): semi stub!\n", nIndex, lpColumn);
2186
2187   /* initialize memory */
2188     ZeroMemory (&hdi, sizeof(HDITEM32A));
2189
2190   if (lpColumn->mask & LVCF_FMT) 
2191   {
2192         if (nIndex == 0)
2193             hdi.fmt |= HDF_LEFT;
2194     else if (lpColumn->fmt & LVCFMT_LEFT)
2195             hdi.fmt |= HDF_LEFT;
2196     else if (lpColumn->fmt & LVCFMT_RIGHT)
2197             hdi.fmt |= HDF_RIGHT;
2198     else if (lpColumn->fmt & LVCFMT_CENTER)
2199             hdi.fmt |= HDF_CENTER;
2200     if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
2201             hdi.fmt |= HDF_IMAGE;
2202             
2203         hdi.mask |= HDI_FORMAT;
2204     }
2205
2206   if (lpColumn->mask & LVCF_WIDTH) 
2207   {
2208         hdi.mask |= HDI_WIDTH;
2209     hdi.cxy = lpColumn->cx;
2210     }
2211     
2212   if (lpColumn->mask & LVCF_TEXT) 
2213   {
2214         hdi.mask |= (HDI_TEXT | HDI_FORMAT);
2215     hdi.pszText = lpColumn->pszText;
2216         hdi.fmt |= HDF_STRING;
2217     }
2218
2219   if (lpColumn->mask & LVCF_IMAGE) 
2220   {
2221         hdi.mask |= HDI_IMAGE;
2222     hdi.iImage = lpColumn->iImage;
2223     }
2224
2225   if (lpColumn->mask & LVCF_ORDER) 
2226   {
2227         hdi.mask |= HDI_ORDER;
2228     hdi.iOrder = lpColumn->iOrder;
2229     }
2230
2231     nResult = SendMessage32A (infoPtr->hwndHeader, HDM_INSERTITEM32A,
2232                            (WPARAM32)nIndex, (LPARAM)&hdi);
2233     if (nResult == -1)
2234         return -1;
2235
2236   /* increment column counter */
2237     infoPtr->nColumnCount++;
2238
2239     return nResult;
2240 }
2241
2242 /* << LISTVIEW_InsertColumn32W >> */
2243
2244 /***
2245  * DESCRIPTION:
2246  * Inserts a new item in the listview control.
2247  * 
2248  * PARAMETER(S):
2249  * [I] HWND32 : window handle
2250  * [I] LPLVITEM32A : item information
2251  *
2252  * RETURN:
2253  *   SUCCESS : new item index
2254  *   FAILURE : -1
2255  */
2256 static LRESULT LISTVIEW_InsertItem32A(HWND32 hwnd, LPLVITEM32A lpItem)
2257 {
2258   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
2259   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
2260   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
2261     LISTVIEW_ITEM *lpListItem;
2262   INT32 nItem;
2263     NMLISTVIEW nmlv;
2264   LVITEM32A lvItem;
2265   INT32 nColumnWidth = 0;
2266   INT32 nSmallIconWidth;
2267
2268   if (lpItem == NULL)
2269         return -1;
2270
2271   if (lpItem->iSubItem != 0)
2272         return -1;
2273
2274   /* allocate memory */
2275   lpListItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
2276   if (lpListItem == NULL)
2277         return -1;
2278
2279   nSmallIconWidth = GetSystemMetrics32(SM_CXSMICON);
2280
2281   /* initialize listview control item */
2282   ZeroMemory(lpListItem, sizeof(LISTVIEW_ITEM));
2283
2284   /* copy only valid data */
2285   if (lpItem->mask & LVIF_TEXT) 
2286   {
2287         if (lpItem->pszText == LPSTR_TEXTCALLBACK32A)
2288     {
2289       if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
2290         return -1;
2291
2292       lpListItem->pszText = LPSTR_TEXTCALLBACK32A;
2293     }
2294         else
2295     {
2296       nColumnWidth = SendMessage32A(hwnd, LVM_GETSTRINGWIDTH32A, 
2297                                     (WPARAM32)0, (LPARAM)lpItem->pszText);
2298
2299       /* add padding for separating columns */
2300       nColumnWidth += 10;
2301
2302       /* calculate column width; make sure it's at least 96 pixels */
2303       if (nColumnWidth < 96)
2304         nColumnWidth = 96;
2305         
2306       Str_SetPtr32A(&lpListItem->pszText, lpItem->pszText);
2307     }
2308   }
2309
2310   if (lpItem->mask & LVIF_STATE)
2311   {
2312     if (lpItem->stateMask & LVIS_FOCUSED)
2313     {
2314       /* clear LVIS_FOCUSED states */
2315       ZeroMemory(&lvItem, sizeof(LVITEM32A));
2316       lvItem.stateMask = LVIS_FOCUSED;
2317       lvItem.state = 0;
2318       SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)-1, (LPARAM)&lvItem);
2319
2320       /* set focused item index */
2321       infoPtr->nFocusedItem = lpItem->iItem;
2322     }
2323
2324     lpListItem->state = lpItem->state & lpItem->stateMask;
2325   }
2326
2327     if (lpItem->mask & LVIF_IMAGE)
2328     lpListItem->iImage = lpItem->iImage;
2329
2330     if (lpItem->mask & LVIF_PARAM)
2331     lpListItem->lParam = lpItem->lParam;
2332
2333     if (lpItem->mask & LVIF_INDENT)
2334     lpListItem->iIndent = lpItem->iIndent;
2335
2336   /* insert item in listview control data structure */
2337   nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpItem->iItem, lpListItem);
2338   if (nItem == -1)
2339     return -1;
2340
2341   /* increment item counter */
2342     infoPtr->nItemCount++;
2343
2344   /* calculate column width */
2345   if (infoPtr->himlSmall != NULL)
2346     nColumnWidth += nSmallIconWidth;
2347
2348   /* calculate column width */
2349   if (infoPtr->himlState != NULL)
2350     nColumnWidth += nSmallIconWidth;
2351
2352   /* set column width */
2353    if (nColumnWidth > infoPtr->nColumnWidth)
2354      infoPtr->nColumnWidth = nColumnWidth;
2355
2356   /* set drawing data */
2357   LISTVIEW_SetScroll(hwnd);
2358
2359   /* send LVN_INSERTITEM notification */
2360     ZeroMemory (&nmlv, sizeof (NMLISTVIEW));
2361   nmlv.hdr.hwndFrom = hwnd;
2362   nmlv.hdr.idFrom = lCtrlId;
2363     nmlv.hdr.code     = LVN_INSERTITEM;
2364   nmlv.iItem = nItem;
2365   SendMessage32A(GetParent32 (hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
2366                  (LPARAM)&nmlv);
2367
2368   InvalidateRect32(hwnd, NULL, FALSE);
2369   UpdateWindow32(hwnd);
2370
2371   return nItem;
2372 }
2373
2374 /* << LISTVIEW_InsertItem32W >> */
2375
2376 /***
2377  * DESCRIPTION:
2378  * Redraws a range of items.
2379  * 
2380  * PARAMETER(S):
2381  * [I] HWND32 : window handle
2382  * [I] INT32 : first item
2383  * [I] INT32 : last item
2384  *
2385  * RETURN:
2386  *   SUCCESS : TRUE
2387  *   FAILURE : FALSE
2388  */
2389 static LRESULT LISTVIEW_RedrawItems(HWND32 hwnd, INT32 nFirst, INT32 nLast)
2390 {
2391   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); 
2392
2393   if (nFirst > nLast)
2394     return FALSE;
2395
2396   if ((nFirst < 0) || (nFirst >= infoPtr->nItemCount))
2397     return FALSE;
2398
2399   if ((nLast < 0) || (nLast >= infoPtr->nItemCount))
2400     return FALSE;
2401
2402   /* TO DO */
2403
2404   return TRUE;
2405 }
2406
2407 /***
2408  * DESCRIPTION:
2409  * Scrolls the content of a listview.
2410  * 
2411  * PARAMETER(S):
2412  * [I] HWND32 : window handle
2413  * [I] INT32 : amount of horizontal scrolling
2414  * [I] INT32 : amount of vertical scrolling
2415  *
2416  * RETURN:
2417  *   SUCCESS : TRUE
2418  *   FAILURE : FALSE
2419  */
2420 static LRESULT LISTVIEW_Scroll(HWND32 hwnd, INT32 nHScroll, INT32 nVScroll)
2421 {
2422   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
2423   BOOL32 bResult = FALSE;
2424   INT32 nHScrollPos;
2425   INT32 nMinRange;
2426   INT32 nMaxRange;
2427
2428   if (lStyle & LVS_LIST)
2429   {
2430     nHScrollPos = GetScrollPos32(hwnd, SB_HORZ);
2431     GetScrollRange32(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
2432
2433     if ((nMinRange <= nHScrollPos + nHScroll) && 
2434         (nHScrollPos + nHScroll <= nMaxRange))
2435     {
2436       bResult = TRUE;
2437       nHScrollPos += nHScroll;
2438       SetScrollPos32(hwnd, SB_HORZ, nHScrollPos, TRUE);
2439
2440       /* refresh client area */
2441       InvalidateRect32(hwnd, NULL, TRUE);
2442       UpdateWindow32(hwnd);
2443     }
2444   }  
2445   else if (lStyle & LVS_REPORT)
2446   {
2447     /* TO DO */
2448 }
2449   else if (lStyle & LVS_SMALLICON)
2450   {
2451     /* TO DO */
2452   }
2453   else if (lStyle & LVS_ICON)
2454   {
2455     /* TO DO */
2456   }
2457
2458   return bResult; 
2459 }
2460
2461 /***
2462  * DESCRIPTION:
2463  * Sets the background color.
2464  * 
2465  * PARAMETER(S):
2466  * [I] HWND32 : window handle
2467  * [I] COLORREF : background color
2468  *
2469  * RETURN:
2470  *   SUCCESS : TRUE
2471  *   FAILURE : FALSE
2472 */
2473 static LRESULT LISTVIEW_SetBkColor(HWND32 hwnd, COLORREF clrBk)
2474 {
2475   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
2476
2477   infoPtr->clrBk = clrBk;
2478   InvalidateRect32(hwnd, NULL, TRUE);
2479
2480   return TRUE;
2481 }
2482
2483 /***
2484  * DESCRIPTION:
2485  * Sets column attributes.
2486  * 
2487  * PARAMETER(S):
2488  * [I] HWND32 : window handle
2489  * [I] INT32 : column index
2490  * [I] LPLVCOLUMN32A : column information
2491  *
2492  * RETURN:
2493  *   SUCCESS : TRUE
2494  *   FAILURE : FALSE
2495  */
2496 static LRESULT LISTVIEW_SetColumn32A(HWND32 hwnd, INT32 nIndex, 
2497                                      LPLVCOLUMN32A lpColumn)
2498 {
2499   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
2500     HDITEM32A hdi;
2501
2502   if (lpColumn == NULL)
2503         return -1;
2504
2505   /* initialize memory */
2506     ZeroMemory (&hdi, sizeof(HDITEM32A));
2507
2508   if (lpColumn->mask & LVCF_FMT) 
2509   {
2510         if (nIndex == 0)
2511             hdi.fmt |= HDF_LEFT;
2512     else if (lpColumn->fmt & LVCFMT_LEFT)
2513             hdi.fmt |= HDF_LEFT;
2514     else if (lpColumn->fmt & LVCFMT_RIGHT)
2515             hdi.fmt |= HDF_RIGHT;
2516     else if (lpColumn->fmt & LVCFMT_CENTER)
2517             hdi.fmt |= HDF_CENTER;
2518
2519     if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
2520             hdi.fmt |= HDF_IMAGE;
2521             
2522         hdi.mask |= HDI_FORMAT;
2523     }
2524
2525   if (lpColumn->mask & LVCF_WIDTH) 
2526   {
2527         hdi.mask |= HDI_WIDTH;
2528     hdi.cxy = lpColumn->cx;
2529     }
2530     
2531   if (lpColumn->mask & LVCF_TEXT) 
2532   {
2533         hdi.mask |= (HDI_TEXT | HDI_FORMAT);
2534     hdi.pszText = lpColumn->pszText;
2535         hdi.fmt |= HDF_STRING;
2536     }
2537
2538   if (lpColumn->mask & LVCF_IMAGE) 
2539   {
2540         hdi.mask |= HDI_IMAGE;
2541     hdi.iImage = lpColumn->iImage;
2542     }
2543
2544   if (lpColumn->mask & LVCF_ORDER) 
2545   {
2546         hdi.mask |= HDI_ORDER;
2547     hdi.iOrder = lpColumn->iOrder;
2548     }
2549
2550     return (LRESULT)SendMessage32A (infoPtr->hwndHeader, HDM_SETITEM32A,
2551                                   (WPARAM32)nIndex, (LPARAM)&hdi);
2552 }
2553
2554 /***
2555  * DESCRIPTION:
2556  * Sets image list.
2557  * 
2558  * PARAMETER(S):
2559  * [I] HWND32 : window handle
2560  * [I] INT32 : image list type  
2561  * [I] HIMAGELIST : image list handle
2562  *
2563  * RETURN:
2564  *   SUCCESS : old image list
2565  *   FAILURE : NULL
2566 */
2567 static LRESULT LISTVIEW_SetImageList(HWND32 hwnd, INT32 nType, HIMAGELIST himl)
2568 {
2569   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
2570     HIMAGELIST himlTemp = 0;
2571
2572   switch (nType) 
2573   {
2574         case LVSIL_NORMAL:
2575             himlTemp = infoPtr->himlNormal;
2576     infoPtr->himlNormal = himl;
2577             return (LRESULT)himlTemp;
2578         case LVSIL_SMALL:
2579             himlTemp = infoPtr->himlSmall;
2580     infoPtr->himlSmall = himl;
2581             return (LRESULT)himlTemp;
2582         case LVSIL_STATE:
2583             himlTemp = infoPtr->himlState;
2584     infoPtr->himlState = himl;
2585             return (LRESULT)himlTemp;
2586     }
2587
2588     return (LRESULT)NULL;
2589 }
2590
2591
2592 /***
2593  * DESCRIPTION:
2594  * Sets item attributes.
2595  * 
2596  * PARAMETER(S):
2597  * [I] HWND32 : window handle
2598  * [I] LPLVITEM32 : item information 
2599  *
2600  * RETURN:
2601  *   SUCCESS : TRUE
2602  *   FAILURE : FALSE
2603  */
2604 static LRESULT LISTVIEW_SetItem32A(HWND32 hwnd, LPLVITEM32A lpItem)
2605 {
2606   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
2607   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
2608   LISTVIEW_ITEM *lpListItem;
2609     NMLISTVIEW nmlv;
2610
2611   if (lpItem == NULL)
2612         return FALSE;
2613
2614     if ((lpItem->iItem < 0) || (lpItem->iItem >= infoPtr->nItemCount))
2615         return FALSE;
2616
2617     /* send LVN_ITEMCHANGING notification */
2618     ZeroMemory (&nmlv, sizeof (NMLISTVIEW));
2619   nmlv.hdr.hwndFrom = hwnd;
2620   nmlv.hdr.idFrom = lCtrlId;
2621     nmlv.hdr.code     = LVN_ITEMCHANGING;
2622     nmlv.iItem        = lpItem->iItem;
2623     nmlv.iSubItem     = lpItem->iSubItem;
2624     nmlv.uChanged     = lpItem->mask;
2625   if (SendMessage32A(GetParent32(hwnd), WM_NOTIFY,  (WPARAM32)lCtrlId, 
2626                      (LPARAM)&nmlv) == FALSE) 
2627         return FALSE;
2628
2629   /* get item */
2630   lpListItem = DPA_GetPtr(infoPtr->hdpaItems, lpItem->iItem);
2631   if (lpListItem == NULL)
2632     return FALSE;
2633
2634   /* copy valid data */
2635   if (lpItem->iSubItem > 0)
2636   {
2637     /* verify existance of sub-item */
2638     lpListItem += lpItem->iSubItem;
2639     if (lpListItem == NULL)
2640         return FALSE;
2641
2642     /* exit if indent attribute is valid */
2643     if (lpItem->mask & LVIF_INDENT)
2644         return FALSE;
2645
2646     if (lpItem->mask & LVIF_IMAGE)
2647     {
2648       /* set sub-item attribute */
2649     }
2650
2651         }
2652   else
2653   {
2654     if (lpItem->mask & LVIF_STATE)
2655     {
2656       lpListItem->state &= ~lpItem->stateMask;
2657       lpListItem->state |= (lpItem->state & lpItem->stateMask);
2658     }
2659
2660     if (lpItem->mask & LVIF_IMAGE)
2661       lpListItem->iImage = lpItem->iImage;
2662
2663     if (lpItem->mask & LVIF_PARAM)
2664       lpListItem->lParam = lpItem->lParam;
2665
2666     if (lpItem->mask & LVIF_INDENT)
2667       lpListItem->iIndent = lpItem->iIndent;
2668   }
2669   
2670   if (lpItem->mask & LVIF_TEXT) 
2671   {
2672     if (lpItem->pszText == LPSTR_TEXTCALLBACK32A) 
2673     {
2674       if ((lpListItem->pszText != NULL) &&
2675           (lpListItem->pszText != LPSTR_TEXTCALLBACK32A))
2676         COMCTL32_Free (lpListItem->pszText);
2677
2678       lpListItem->pszText = LPSTR_TEXTCALLBACK32A;
2679     }
2680     else 
2681     {
2682       if (lpListItem->pszText == LPSTR_TEXTCALLBACK32A)
2683         lpListItem->pszText = NULL;
2684       
2685       if (Str_SetPtr32A(&lpListItem->pszText, lpItem->pszText) == FALSE)
2686         return FALSE;
2687     }
2688   }
2689
2690     /* send LVN_ITEMCHANGED notification */
2691     nmlv.hdr.code = LVN_ITEMCHANGED;
2692   SendMessage32A(GetParent32(hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
2693                  (LPARAM)&nmlv);
2694
2695     return TRUE;
2696 }
2697
2698 /* << LISTVIEW_SetItem32W >> */
2699
2700 /* LISTVIEW_SetItemCount*/
2701
2702 /***
2703  * DESCRIPTION:
2704  * Sets item position.
2705  * 
2706  * PARAMETER(S):
2707  * [I] HWND32 : window handle
2708  * [I] INT32 : item index
2709  * [I] INT32 : x coordinate
2710  * [I] INT32 : y coordinate
2711  *
2712  * RETURN:
2713  *   SUCCESS : TRUE
2714  *   FAILURE : FALSE
2715  */
2716 static LRESULT LISTVIEW_SetItemPosition(HWND32 hwnd, INT32 nItem, 
2717                                         INT32 nPosX, INT32 nPosY)
2718 {
2719   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLong32A(hwnd, 0);
2720   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
2721
2722   if ((nItem < 0) || (nItem >= infoPtr->nItemCount))
2723         return FALSE;
2724
2725   if ((lStyle & LVS_ICON) && (lStyle & LVS_SMALLICON))
2726   {
2727     /* get item */
2728
2729     /* set position of item */
2730
2731     /* refresh */
2732     if (lStyle & LVS_AUTOARRANGE)
2733     {
2734       InvalidateRect32(hwnd, NULL, FALSE);
2735       UpdateWindow32(hwnd);
2736     }
2737
2738     return TRUE;
2739 }
2740
2741   return FALSE;
2742 }
2743
2744 /***
2745  * DESCRIPTION:
2746  * Sets the state of one or many items.
2747  * 
2748  * PARAMETER(S):
2749  * [I] HWND32 : window handle
2750  * [I]INT32 : item index
2751  * [I] LPLVITEM32 : item information 
2752  *
2753  * RETURN:
2754  *   SUCCESS : TRUE
2755  *   FAILURE : FALSE
2756 */
2757 static LRESULT LISTVIEW_SetItemState(HWND32 hwnd, INT32 nItem, 
2758                                      LPLVITEM32A lpItem)
2759 {
2760   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
2761   LISTVIEW_ITEM *lpListItem;
2762   INT32 i;
2763
2764   if (nItem == -1)
2765   {
2766     /* apply to all the items */
2767     for (i = 0; i< infoPtr->nItemCount; i++)
2768     {
2769       lpListItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, i);
2770       if (lpListItem == NULL)
2771         return FALSE;
2772
2773       lpListItem->state &= ~lpItem->stateMask;
2774       lpListItem->state |= (lpItem->state & lpItem->stateMask);
2775         }
2776         }
2777   else if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
2778   {
2779     lpListItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem);
2780     if (lpListItem == NULL)
2781       return FALSE;
2782
2783     /* set state */
2784     lpListItem->state &= ~lpItem->stateMask;
2785     lpListItem->state |= (lpItem->state & lpItem->stateMask);
2786     }
2787   else
2788     return FALSE;
2789
2790     return TRUE;
2791 }
2792
2793 /***
2794  * DESCRIPTION:
2795  * Sets the text background color.
2796  * 
2797  * PARAMETER(S):
2798  * [I] HWND32 : window handle
2799  * [I] COLORREF : text background color
2800  *
2801  * RETURN:
2802  *   SUCCESS : TRUE
2803  *   FAILURE : FALSE
2804 */
2805 static LRESULT LISTVIEW_SetTextBkColor(HWND32 hwnd, COLORREF clrTextBk)
2806 {
2807   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
2808
2809   infoPtr->clrTextBk = clrTextBk;
2810
2811     return TRUE;
2812 }
2813
2814 /***
2815  * DESCRIPTION:
2816  * Sets the text background color.
2817  * 
2818  * PARAMETER(S):
2819  * [I] HWND32 : window handle
2820  * [I] COLORREF : text color 
2821  *
2822  * RETURN:
2823  *   SUCCESS : TRUE
2824  *   FAILURE : FALSE
2825  */
2826 static LRESULT LISTVIEW_SetTextColor (HWND32 hwnd, COLORREF clrText)
2827 {
2828   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
2829
2830   infoPtr->clrText = clrText;
2831
2832     return TRUE;
2833 }
2834
2835 /***
2836  * DESCRIPTION:
2837  * ??
2838  * 
2839  * PARAMETER(S):
2840  * [I] HWND32 : window handle
2841  *
2842  * RETURN:
2843  *   SUCCESS : TRUE
2844  *   FAILURE : FALSE
2845 */
2846 static LRESULT LISTVIEW_SortItems(HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
2847 {
2848 /*  LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLong32A(hwnd, 0); */
2849
2850     FIXME (listview, "empty stub!\n");
2851
2852     return TRUE;
2853 }
2854
2855 /***
2856  * DESCRIPTION:
2857  * Updates an items.
2858  * 
2859  * PARAMETER(S):
2860  * [I] HWND32 : window handle
2861  * [I] INT32 : item index
2862  *
2863  * RETURN:
2864  *   SUCCESS : TRUE
2865  *   FAILURE : FALSE
2866 */
2867 static LRESULT LISTVIEW_Update(HWND32 hwnd, INT32 nItem)
2868 {
2869   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLong32A(hwnd, 0);
2870   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
2871   RECT32 rcItemRect;
2872   BOOL32 bResult = FALSE;
2873
2874   if ((nItem >= 0) || (nItem < infoPtr->nItemCount))
2875   {
2876     /* get item bounding rectangle */
2877     rcItemRect.left = LVIR_BOUNDS;
2878     SendMessage32A(hwnd, LVM_GETITEMRECT, (WPARAM32)nItem, 
2879                    (LPARAM)&rcItemRect);
2880
2881     InvalidateRect32(hwnd, &rcItemRect, FALSE);
2882
2883     /* rearrange with default alignment style */
2884     if ((lStyle & LVS_AUTOARRANGE) && 
2885         ((lStyle & LVS_ICON) || (lStyle & LVS_SMALLICON)))
2886       SendMessage32A(hwnd, LVM_ARRANGE, (WPARAM32)LVA_DEFAULT, (LPARAM)0);
2887   }
2888
2889   return bResult;
2890 }
2891
2892 /***
2893  * DESCRIPTION:
2894  * Creates a listview control.
2895  * 
2896  * PARAMETER(S):
2897  * [I] HWND32 : window handle
2898  *
2899  * RETURN:
2900  * Zero
2901  */
2902 static LRESULT LISTVIEW_Create(HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
2903 {
2904   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
2905   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE); 
2906   LOGFONT32A logFont;
2907   HFONT32 hOldFont;
2908   HDC32 hdc;
2909   TEXTMETRIC32A tm;
2910   INT32 nSmallIconHeight;
2911
2912   /* initialize color information  */
2913   infoPtr->clrBk = GetSysColor32(COLOR_WINDOW);
2914   infoPtr->clrText = GetSysColor32(COLOR_WINDOWTEXT);
2915   infoPtr->clrTextBk = GetSysColor32(COLOR_WINDOW); 
2916
2917     /* get default font (icon title) */
2918     SystemParametersInfo32A (SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
2919     infoPtr->hDefaultFont = CreateFontIndirect32A (&logFont);
2920     infoPtr->hFont = infoPtr->hDefaultFont;
2921
2922   /* initialize column width */
2923   infoPtr->nColumnWidth = 96;
2924
2925   /* get text height */
2926   hdc = GetDC32(hwnd);
2927   hOldFont = SelectObject32(hdc, infoPtr->hFont);
2928   GetTextMetrics32A(hdc, &tm);
2929
2930   /* initialize item height with padding */
2931   if (!(lStyle & LVS_ICON)) 
2932   {
2933     nSmallIconHeight = GetSystemMetrics32(SM_CYSMICON);
2934     infoPtr->nItemHeight = max(tm.tmHeight, nSmallIconHeight) + 2;
2935   }
2936
2937   SelectObject32(hdc, hOldFont);
2938   ReleaseDC32(hwnd, hdc);
2939
2940  /* create header */
2941   infoPtr->hwndHeader = CreateWindow32A(WC_HEADER32A, "", lStyle, 0, 0, 0, 0, 
2942                                         hwnd, (HMENU32)0, 
2943                                         GetWindowLong32A(hwnd, GWL_HINSTANCE),
2944                                         NULL);
2945     /* set header font */
2946   SendMessage32A(infoPtr->hwndHeader, WM_SETFONT, (WPARAM32)infoPtr->hFont, 
2947                  (LPARAM)TRUE);
2948
2949   /* allocate memory */
2950     infoPtr->hdpaItems = DPA_Create (10);
2951
2952     return 0;
2953 }
2954
2955
2956 static LRESULT
2957 LISTVIEW_Destroy (HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
2958 {
2959     LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLong32A(hwnd, 0);
2960
2961     /* delete all items */
2962     LISTVIEW_DeleteAllItems(hwnd);
2963
2964     /* destroy dpa */
2965     DPA_Destroy (infoPtr->hdpaItems);
2966
2967     /* destroy header */
2968     if (infoPtr->hwndHeader)
2969         DestroyWindow32 (infoPtr->hwndHeader);
2970
2971     /* destroy font */
2972     infoPtr->hFont = (HFONT32)0;
2973     if (infoPtr->hDefaultFont)
2974         DeleteObject32 (infoPtr->hDefaultFont);
2975
2976     infoPtr->nColumnWidth = 96;
2977
2978     return 0;
2979 }
2980
2981 /***
2982  * DESCRIPTION:
2983  * Erases the background of the listview control
2984  * 
2985  * PARAMETER(S):
2986  * [I] HWND32 : window handle
2987  *
2988  * RETURN:
2989  *   SUCCESS : TRUE
2990  *   FAILURE : FALSE
2991  */
2992 static LRESULT LISTVIEW_EraseBackground(HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
2993 {
2994   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
2995   BOOL32 bResult;
2996
2997   if (infoPtr->clrBk == CLR_NONE) 
2998     bResult = SendMessage32A(GetParent32(hwnd), WM_ERASEBKGND, wParam, lParam);
2999   else 
3000   {
3001     HBRUSH32 hBrush = CreateSolidBrush32(infoPtr->clrBk);
3002     RECT32   clientRect;
3003
3004     GetClientRect32(hwnd, &clientRect);
3005     FillRect32((HDC32)wParam, &clientRect, hBrush);
3006     DeleteObject32(hBrush);
3007     bResult = TRUE;
3008   }
3009
3010   return bResult;
3011 }
3012
3013 /***
3014  * DESCRIPTION:
3015  * Gets the listview control font.
3016  * 
3017  * PARAMETER(S):
3018  * [I] HWND32 : window handle
3019  *
3020  * RETURN:
3021  * Font handle.
3022  */
3023 static LRESULT LISTVIEW_GetFont(HWND32 hwnd)
3024 {
3025   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
3026
3027   return infoPtr->hFont;
3028 }
3029
3030 /***
3031  * DESCRIPTION:
3032  * Performs horizontal scrolling.
3033  * 
3034  * PARAMETER(S):
3035  * [I] HWND32 : window handle
3036  * [I] INT32 : scroll code
3037  * [I] INT32 : scroll position
3038  * [I] HWND32 : scrollbar control window handle
3039  *
3040  * RETURN:
3041  * Zero
3042  */
3043 static LRESULT LISTVIEW_HScroll(HWND32 hwnd, INT32 nScrollCode, 
3044                                 INT32 nScrollPos, HWND32 hScrollWnd)
3045 {
3046   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
3047   INT32 nHScrollPos;
3048   INT32 nMinRange;
3049   INT32 nMaxRange;
3050
3051   GetScrollRange32(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
3052   nHScrollPos = GetScrollPos32(hwnd, SB_HORZ);
3053
3054   if (lStyle & LVS_LIST)
3055   {
3056     switch (nScrollCode)
3057     {
3058     case SB_LINELEFT:
3059       if (nHScrollPos > nMinRange)
3060         nHScrollPos--;
3061       break;
3062     case SB_LINERIGHT:
3063       if (nHScrollPos < nMaxRange)
3064         nHScrollPos++;
3065       break;
3066     case SB_PAGELEFT:
3067       if (nHScrollPos > nMinRange)
3068         nHScrollPos--;
3069       break;
3070     case SB_PAGERIGHT:
3071       if (nHScrollPos < nMaxRange)
3072         nHScrollPos++;
3073       break;
3074     case SB_THUMBPOSITION:
3075       nHScrollPos = nScrollPos;
3076     break;
3077     }
3078
3079     SetScrollPos32(hwnd, SB_HORZ, nHScrollPos, TRUE);
3080
3081     /* refresh client area */
3082     InvalidateRect32(hwnd, NULL, TRUE);
3083     UpdateWindow32(hwnd);
3084   }
3085
3086   return 0;
3087 }
3088
3089 /***
3090  * DESCRIPTION:
3091  * ?????
3092  * 
3093  * PARAMETER(S):
3094  * [I] HWND32 : window handle
3095  * [I] INT32 : virtual key 
3096  * [I] LONG : key data
3097  *
3098  * RETURN:
3099  * Zero
3100  */
3101 static LRESULT LISTVIEW_KeyDown(HWND32 hwnd, INT32 nVirtualKey, LONG lKeyData)
3102 {
3103   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
3104   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
3105   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
3106   HWND32 hwndParent = GetParent32(hwnd);
3107   INT32 nItemCountPerColumn;
3108   INT32 nItemCountPerRow;
3109   NMHDR nmh;
3110   INT32 nColumn;
3111 /*   NMLVKEYDOWN nmKeyDown; */
3112
3113   /* send LVN_KEYDOWN notification */
3114 /*   nmh.hwndFrom = hwnd; */
3115 /*   nmh.idFrom = lCtrlId; */
3116 /*   nmh.code = LVN_KEYDOWN; */
3117 /*   nmKeyDown.hdr = nmh; */
3118 /*   nmKeyDown..wVKey = nVirtualKey; */
3119 /*   nmKeyCode.flags = 0; */
3120 /*   SendMessage32A(hwndParent, WM_NOTIFY, (WPARAM32)lCtrlId, (LPARAM)&nmKeyDown); */
3121
3122   switch (nVirtualKey)
3123   {
3124   case VK_RETURN:
3125     if ((infoPtr->nItemCount > 0) && (infoPtr->nFocusedItem != -1))
3126     {
3127       /* send NM_RETURN notification */
3128       nmh.code = NM_RETURN;
3129       SendMessage32A(hwndParent, WM_NOTIFY, (WPARAM32)lCtrlId, (LPARAM)&nmh);
3130
3131       /* send LVN_ITEMACTIVATE notification */
3132       nmh.code = LVN_ITEMACTIVATE;
3133       SendMessage32A(hwndParent, WM_NOTIFY, (WPARAM32)lCtrlId, (LPARAM)&nmh);
3134     }
3135     break;
3136
3137   case VK_HOME:
3138     if (infoPtr->nItemCount > 0)
3139     {
3140       /* set item state(s) */
3141       infoPtr->nFocusedItem = 0;
3142       LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE);
3143
3144       /* make item visible */
3145       LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem);
3146     }
3147     break;
3148
3149   case VK_END:
3150     if (infoPtr->nItemCount > 0)
3151 {
3152       /* set item state(s) */
3153       infoPtr->nFocusedItem = infoPtr->nItemCount - 1;
3154       LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE);
3155
3156       /* make item visible */
3157       LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem);
3158     }
3159
3160     break;
3161
3162   case VK_LEFT:
3163     if (lStyle & LVS_LIST)
3164     {
3165       nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd);
3166       if (infoPtr->nFocusedItem >= nItemCountPerColumn) 
3167       {
3168          /* set item state(s) */
3169         infoPtr->nFocusedItem -= nItemCountPerColumn;
3170         LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE);
3171
3172         /* make item visible */
3173         LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem);
3174       }
3175     }
3176     else if (lStyle & LVS_REPORT)
3177     {
3178       /* TO DO ; does not affect the focused item, it only scrolls */
3179     }
3180     else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON))
3181     {
3182       nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd);
3183       nColumn = infoPtr->nFocusedItem % nItemCountPerRow;
3184       if (nColumn != 0)
3185       {
3186         infoPtr->nFocusedItem -= 1; 
3187         LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE);
3188
3189         /* refresh display */
3190         InvalidateRect32(hwnd, NULL, FALSE);
3191         UpdateWindow32(hwnd);
3192       }
3193     }
3194     break;
3195     
3196   case VK_UP:
3197     if ((lStyle & LVS_LIST) || (lStyle & LVS_REPORT))
3198     {
3199       if (infoPtr->nFocusedItem > 0)
3200       {
3201         infoPtr->nFocusedItem -= 1;
3202         LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE);
3203
3204         LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem);
3205 }
3206     }
3207     else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON))
3208     {
3209       nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd);
3210       if (infoPtr->nFocusedItem >= nItemCountPerRow)
3211       {
3212         infoPtr->nFocusedItem -= nItemCountPerRow;
3213         LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE);
3214
3215         LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem);
3216       }
3217     }
3218     break;
3219
3220   case VK_RIGHT:
3221     if (lStyle & LVS_LIST)
3222 {
3223       nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd);
3224       if (infoPtr->nFocusedItem < infoPtr->nItemCount - nItemCountPerColumn)
3225       {
3226         infoPtr->nFocusedItem += nItemCountPerColumn;
3227         LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE);
3228
3229         LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem);
3230     }
3231     }
3232     else if (lStyle & LVS_REPORT)
3233     {
3234     }
3235     else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON))
3236     {
3237       nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd);
3238       nColumn = infoPtr->nFocusedItem % nItemCountPerRow;
3239       if (nColumn != nItemCountPerRow - 1)
3240       {
3241         infoPtr->nFocusedItem += 1; 
3242         LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE);
3243
3244         /* refresh display */
3245         InvalidateRect32(hwnd, NULL, FALSE);
3246         UpdateWindow32(hwnd);
3247 }
3248
3249     }
3250     break;
3251
3252   case VK_DOWN:
3253     if ((lStyle & LVS_LIST) || (lStyle & LVS_REPORT))
3254 {
3255       if (infoPtr->nFocusedItem < infoPtr->nItemCount - 1)
3256       {
3257         infoPtr->nFocusedItem += 1;
3258         LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE);
3259
3260         LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem);
3261 }
3262     }
3263     else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON))
3264     {
3265       nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd);
3266       if (infoPtr->nFocusedItem < infoPtr->nItemCount - nItemCountPerRow)
3267       {
3268         infoPtr->nFocusedItem += nItemCountPerRow;
3269         LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE);
3270
3271         LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem);
3272       }
3273     }
3274     break;
3275
3276   case VK_PRIOR:
3277     break;
3278
3279   case VK_NEXT:
3280     break;
3281   }
3282
3283   return 0;
3284 }
3285
3286 /***
3287  * DESCRIPTION:
3288  * Kills the focus.
3289  * 
3290  * PARAMETER(S):
3291  * [I] HWND32 : window handle
3292  *
3293  * RETURN:
3294  * Zero
3295  */
3296 static LRESULT LISTVIEW_KillFocus(HWND32 hwnd)
3297 {
3298   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLong32A(hwnd, 0);
3299   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
3300     NMHDR nmh;
3301
3302   nmh.hwndFrom = hwnd;
3303   nmh.idFrom = lCtrlId;
3304     nmh.code = NM_KILLFOCUS;
3305   SendMessage32A(GetParent32(hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
3306                  (LPARAM)&nmh);
3307
3308   /* set window focus flag */
3309     infoPtr->bFocus = FALSE;
3310
3311     return 0;
3312 }
3313
3314 /***
3315  * DESCRIPTION:
3316  * Left mouse button double click.
3317  * 
3318  * PARAMETER(S):
3319  * [I] HWND32 : window handle
3320  * [I] WORD : key flag
3321  * [I] WORD : x coordinate
3322  * [I] WORD : y coordinate
3323  *
3324  * RETURN:
3325  * Zero
3326  */
3327 static LRESULT LISTVIEW_LButtonDblClk(HWND32 hwnd, WORD wKey, WORD wPosX, 
3328                                       WORD wPosY)
3329 {
3330   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
3331   NMHDR nmh;
3332
3333   /* send NM_DBLCLK notification */
3334   nmh.hwndFrom = hwnd;
3335   nmh.idFrom = lCtrlId;
3336   nmh.code = NM_DBLCLK;
3337   SendMessage32A(GetParent32 (hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
3338                  (LPARAM)&nmh);
3339
3340   /* send LVN_ITEMACTIVATE notification */
3341   nmh.code = LVN_ITEMACTIVATE;
3342   SendMessage32A(GetParent32 (hwnd), WM_NOTIFY, (WPARAM32)lCtrlId,
3343                  (LPARAM)&nmh);
3344
3345   return 0;
3346 }
3347
3348 /***
3349  * DESCRIPTION:
3350  * Left mouse button down.
3351  * 
3352  * PARAMETER(S):
3353  * [I] HWND32 : window handle
3354  * [I] WORD : key flag
3355  * [I] WORD : x coordinate
3356  * [I] WORD : y coordinate
3357  *
3358  * RETURN:
3359  * Zero
3360  */
3361 static LRESULT LISTVIEW_LButtonDown(HWND32 hwnd, WORD wKey, WORD wPosX, 
3362                                     WORD wPosY)
3363 {
3364   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
3365   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
3366   LVHITTESTINFO hitTestInfo;
3367   LVITEM32A lvItem;
3368   NMHDR nmh;
3369   INT32 nItem;
3370
3371   /* send NM_RELEASEDCAPTURE notification */ 
3372   nmh.hwndFrom = hwnd;
3373   nmh.idFrom = lCtrlId;
3374   nmh.code = NM_RELEASEDCAPTURE;
3375   SendMessage32A(GetParent32(hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
3376                  (LPARAM)&nmh);
3377
3378   if (infoPtr->bFocus == FALSE)
3379     SetFocus32(hwnd);
3380
3381   /* set left button down flag */
3382   infoPtr->bLButtonDown = TRUE;
3383
3384   /* set left button hit coordinates */
3385   hitTestInfo.pt.x = wPosX;
3386   hitTestInfo.pt.y = wPosY;
3387   
3388   /* perform hit test */
3389   nItem = SendMessage32A(hwnd, LVM_HITTEST, (WPARAM32)0, (LPARAM)&hitTestInfo);
3390     if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
3391   {
3392     /* perform state changes (selection and focus) */
3393     infoPtr->nFocusedItem = nItem;
3394     LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, TRUE);
3395
3396     /* scroll intem into view if doing a multiple selection */
3397
3398     if ((wKey & MK_CONTROL) || (wKey & MK_SHIFT))
3399 {
3400       LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem);
3401     }
3402     else
3403     {
3404       /* refresh display */
3405       InvalidateRect32(hwnd, NULL, FALSE);
3406       UpdateWindow32(hwnd);
3407     }
3408   }
3409   else
3410   {
3411     /* clear selection(s) */
3412     ZeroMemory(&lvItem, sizeof(LVITEM32A));
3413     lvItem.stateMask = LVIS_SELECTED;
3414     lvItem.state = 0;
3415     SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)-1, (LPARAM)&lvItem);
3416
3417     /* repaint everything */
3418     InvalidateRect32(hwnd, NULL, FALSE);
3419     UpdateWindow32(hwnd);
3420   }
3421
3422   return 0;
3423 }
3424
3425 /***
3426  * DESCRIPTION:
3427  * Left mouse button up.
3428  * 
3429  * PARAMETER(S):
3430  * [I] HWND32 : window handle
3431  * [I] WORD : key flag
3432  * [I] WORD : x coordinate
3433  * [I] WORD : y coordinate
3434  *
3435  * RETURN:
3436  * Zero
3437  */
3438 static LRESULT LISTVIEW_LButtonUp(HWND32 hwnd, WORD wKey, WORD wPosX, 
3439                                   WORD wPosY)
3440 {
3441   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
3442   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
3443   NMHDR nmh;
3444
3445   if (infoPtr->bLButtonDown == TRUE) 
3446   {
3447     /* send NM_CLICK notification */
3448     nmh.hwndFrom = hwnd;
3449     nmh.idFrom = lCtrlId;
3450     nmh.code = NM_CLICK;
3451     SendMessage32A(GetParent32 (hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
3452                      (LPARAM)&nmh);
3453   }
3454
3455   /* set left button flag */
3456   infoPtr->bLButtonDown = FALSE;
3457
3458     return 0;
3459 }
3460
3461 /***
3462  * DESCRIPTION:
3463  * Creates the listview control (called before WM_CREATE).
3464  * 
3465  * PARAMETER(S):
3466  * [I] HWND32 : window handle
3467  * [I] WPARAM32 : unhandled 
3468  * [I] LPARAM : widow creation info
3469  * 
3470  * RETURN:
3471  * Zero
3472  */
3473 static LRESULT LISTVIEW_NCCreate(HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
3474 {
3475     LISTVIEW_INFO *infoPtr;
3476
3477     /* allocate memory for info structure */
3478     infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc (sizeof(LISTVIEW_INFO));
3479   SetWindowLong32A(hwnd, 0, (LONG)infoPtr);
3480   if (infoPtr == NULL) 
3481   {
3482         ERR (listview, "could not allocate info memory!\n");
3483         return 0;
3484     }
3485
3486   if ((LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0) != infoPtr) 
3487   {
3488         ERR (listview, "pointer assignment error!\n");
3489         return 0;
3490     }
3491
3492   return DefWindowProc32A(hwnd, WM_NCCREATE, wParam, lParam);
3493 }
3494
3495 /***
3496  * DESCRIPTION:
3497  * Destroys the listview control (called after WM_DESTROY).
3498  * 
3499  * PARAMETER(S):
3500  * [I] HWND32 : window handle
3501  * 
3502  * RETURN:
3503  * Zero
3504  */
3505 static LRESULT LISTVIEW_NCDestroy(HWND32 hwnd)
3506 {
3507   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
3508
3509     /* free list view info data */
3510     COMCTL32_Free (infoPtr);
3511
3512     return 0;
3513 }
3514
3515 /***
3516  * DESCRIPTION:
3517  * Handles notification from children.
3518  * 
3519  * PARAMETER(S):
3520  * [I] HWND32 : window handle
3521  * [I] INT32 : control identifier
3522  * [I] LPNMHDR : notification information
3523  * 
3524  * RETURN:
3525  * Zero
3526  */
3527 static LRESULT LISTVIEW_Notify(HWND32 hwnd, INT32 nCtrlId, LPNMHDR lpnmh)
3528 {
3529   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
3530
3531   if (lpnmh->hwndFrom == infoPtr->hwndHeader) 
3532   {
3533     /* handle notification from header control */
3534         FIXME (listview, "WM_NOTIFY from header!\n");
3535     }
3536   else 
3537   {
3538     /* handle notification from unknown source */
3539         FIXME (listview, "WM_NOTIFY from unknown source!\n");
3540     }
3541
3542     return 0;
3543 }
3544
3545 /***
3546  * DESCRIPTION:
3547  * Draws the listview control.
3548  * 
3549  * PARAMETER(S):
3550  * [I] HWND32 : window handle
3551  * [I] HDC32 : device context handle
3552  *
3553  * RETURN:
3554  * Zero
3555  */
3556 static LRESULT LISTVIEW_Paint(HWND32 hwnd, HDC32 hdc)
3557 {
3558     PAINTSTRUCT32 ps;
3559
3560   if (hdc == 0)
3561   {
3562     hdc = BeginPaint32(hwnd, &ps);
3563     LISTVIEW_Refresh(hwnd, hdc);
3564     EndPaint32(hwnd, &ps);
3565 }
3566   else
3567     LISTVIEW_Refresh(hwnd, hdc);
3568
3569   return 0;
3570 }
3571
3572 /***
3573  * DESCRIPTION:
3574  * Right mouse button double clisk.
3575  * 
3576  * PARAMETER(S):
3577  * [I] HWND32 : window handle
3578  * [I] WORD : key flag
3579  * [I] WORD : x coordinate
3580  * [I] WORD : y coordinate
3581  *
3582  * RETURN:
3583  * Zero
3584  */
3585 static LRESULT LISTVIEW_RButtonDblClk(HWND32 hwnd, WORD wKey, WORD wPosX, 
3586                                       WORD wPosY)
3587 {
3588   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
3589   NMHDR nmh;
3590
3591   /* send NM_RELEASEDCAPTURE notification */ 
3592   nmh.hwndFrom = hwnd;
3593   nmh.idFrom = lCtrlId;
3594   nmh.code = NM_RELEASEDCAPTURE;
3595   SendMessage32A(GetParent32(hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
3596                  (LPARAM)&nmh);
3597
3598   /* send NM_RDBLCLK notification */
3599   nmh.code = NM_RDBLCLK;
3600   SendMessage32A(GetParent32(hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
3601                  (LPARAM)&nmh);
3602
3603     return 0;
3604 }
3605
3606 /***
3607  * DESCRIPTION:
3608  * Right mouse button input.
3609  * 
3610  * PARAMETER(S):
3611  * [I] HWND32 : window handle
3612  * [I] WORD : key flag
3613  * [I] WORD : x coordinate
3614  * [I] WORD : y coordinate
3615  *
3616  * RETURN:
3617  * Zero
3618  */
3619 static LRESULT LISTVIEW_RButtonDown(HWND32 hwnd, WORD wKey, WORD wPosX, 
3620                                     WORD wPosY)
3621 {
3622   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
3623   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
3624   LVHITTESTINFO hitTestInfo;
3625   NMHDR nmh;
3626   LVITEM32A lvItem;
3627   INT32 nItem;
3628
3629   /* The syslistview32 control sends a NM_RELEASEDCAPTURE notification.
3630      I do not know why, but I decided to send it as well for compatibility 
3631      purposes. */
3632   ZeroMemory(&nmh, sizeof(NMHDR));
3633   nmh.hwndFrom = hwnd;
3634   nmh.idFrom = lCtrlId;
3635   nmh.code = NM_RELEASEDCAPTURE;
3636   SendMessage32A(GetParent32(hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
3637                  (LPARAM)&nmh);
3638  
3639   /* make sure listview control has focus */
3640   if (infoPtr->bFocus == FALSE)
3641     SetFocus32(hwnd);
3642
3643   /* set left button down flag */
3644   infoPtr->bRButtonDown = TRUE;
3645
3646   /* set hit coordinates */
3647   hitTestInfo.pt.x = wPosX;
3648   hitTestInfo.pt.y = wPosY;
3649
3650   /* perform hit test */
3651   nItem = SendMessage32A(hwnd, LVM_HITTEST, (WPARAM32)0, (LPARAM)&hitTestInfo);
3652   if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
3653   {
3654     /* perform state changes (selection and focus) */
3655     infoPtr->nFocusedItem = nItem;
3656     LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, FALSE, TRUE);
3657   }
3658   else
3659   {
3660     /* clear selection(s) */
3661     ZeroMemory(&lvItem, sizeof(LVITEM32A));
3662     lvItem.stateMask = LVIS_SELECTED;
3663     lvItem.state = 0;
3664     SendMessage32A(hwnd, LVM_SETITEMSTATE, (WPARAM32)-1, (LPARAM)&lvItem);
3665   }
3666
3667   /* repaint everything */
3668   InvalidateRect32(hwnd, NULL, FALSE);
3669   UpdateWindow32(hwnd);
3670
3671     return 0;
3672 }
3673
3674 /***
3675  * DESCRIPTION:
3676  * Right mouse button up.
3677  * 
3678  * PARAMETER(S):
3679  * [I] HWND32 : window handle
3680  * [I] WORD : key flag
3681  * [I] WORD : x coordinate
3682  * [I] WORD : y coordinate
3683  *
3684  * RETURN:
3685  * Zero
3686  */
3687 static LRESULT LISTVIEW_RButtonUp(HWND32 hwnd, WORD wKey, WORD wPosX, 
3688                                   WORD wPosY)
3689 {
3690   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
3691   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
3692     NMHDR nmh;
3693
3694   if (infoPtr->bRButtonDown == TRUE) 
3695   {
3696     /* initialize notification information */
3697     ZeroMemory(&nmh, sizeof(NMHDR));
3698     nmh.hwndFrom = hwnd;
3699     nmh.idFrom = lCtrlId;
3700     nmh.code = NM_RCLICK;
3701     SendMessage32A(GetParent32 (hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
3702                    (LPARAM)&nmh);
3703   }
3704
3705   /* set button flag */
3706   infoPtr->bRButtonDown = FALSE;
3707
3708     return 0;
3709 }
3710
3711 /***
3712  * DESCRIPTION:
3713  * Sets the focus.  
3714  * 
3715  * PARAMETER(S):
3716  * [I] HWND32 : window handle
3717  * [I] HWND32 : window handle of previously focused window
3718  *
3719  * RETURN:
3720  * Zero
3721  */
3722 static LRESULT LISTVIEW_SetFocus(HWND32 hwnd, HWND32 hwndLoseFocus)
3723 {
3724   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
3725   LONG lCtrlId = GetWindowLong32A(hwnd, GWL_ID);
3726   NMHDR nmh;
3727     
3728   /* send NM_SETFOCUS notification */
3729   nmh.hwndFrom = hwnd;
3730   nmh.idFrom = lCtrlId;
3731   nmh.code = NM_SETFOCUS;
3732   SendMessage32A(GetParent32(hwnd), WM_NOTIFY, (WPARAM32)lCtrlId, 
3733                  (LPARAM)&nmh);
3734
3735   /* set window focus flag */
3736   infoPtr->bFocus = TRUE;
3737
3738   return 0;
3739 }
3740
3741 /***
3742  * DESCRIPTION:
3743  * Sets the font.  
3744  * 
3745  * PARAMETER(S):
3746  * [I] HWND32 : window handle
3747  * [I] HFONT32 : font handle
3748  * [I] WORD : redraw flag
3749  *
3750  * RETURN:
3751  * Zero
3752  */
3753 static LRESULT LISTVIEW_SetFont(HWND32 hwnd, HFONT32 hFont, WORD fRedraw)
3754 {
3755   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
3756   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
3757
3758   if (hFont == 0)
3759   {
3760     infoPtr->hFont = infoPtr->hDefaultFont;
3761   }
3762   else
3763   {
3764     infoPtr->hFont = hFont;
3765     }
3766
3767   if (lStyle & LVS_REPORT)
3768   {
3769     /* set font of header */
3770     SendMessage32A(infoPtr->hwndHeader, WM_SETFONT, (WPARAM32)hFont, 
3771                    MAKELPARAM(fRedraw, 0));
3772 }
3773
3774   /* invalidate listview control client area */
3775   InvalidateRect32(hwnd, NULL, FALSE);
3776
3777   if (fRedraw == TRUE)
3778     UpdateWindow32(hwnd);
3779
3780   return 0;
3781 }
3782
3783 /***
3784  * DESCRIPTION:
3785  * Resizes the listview control.  
3786  * 
3787  * PARAMETER(S):
3788  * [I] HWND32 : window handle
3789  * [I] WORD : new width
3790  * [I] WORD : new height
3791  *
3792  * RETURN:
3793  * Zero
3794  */
3795 static LRESULT LISTVIEW_Size(HWND32 hwnd, WORD wWidth, WORD wHeight)
3796 {
3797   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0);
3798   LONG lStyle = GetWindowLong32A(hwnd, GWL_STYLE);
3799   INT32 nHScrollHeight;
3800
3801   if (lStyle & LVS_LIST)
3802   {
3803     if (!(lStyle & WS_HSCROLL))
3804     {
3805       nHScrollHeight = GetSystemMetrics32(SM_CYHSCROLL);
3806       if (wHeight > nHScrollHeight)
3807         wHeight -= nHScrollHeight;
3808     }
3809
3810     infoPtr->nHeight = (INT32)wHeight;
3811     infoPtr->nWidth = (INT32)wWidth;
3812   }
3813
3814   /* set scrollbar(s) if needed */
3815   LISTVIEW_SetScroll(hwnd);
3816
3817   /* refresh client area */
3818   InvalidateRect32(hwnd, NULL, TRUE);
3819   UpdateWindow32(hwnd);
3820
3821     return 0;
3822 }
3823
3824 /***
3825  * DESCRIPTION:
3826  * Window procedure of the listview control.
3827  * 
3828  * PARAMETER(S):
3829  * [I] HWND32 :
3830  * [I] UINT32 :
3831  * [I] WPARAM32 :
3832  * [I] LPARAM : 
3833  *
3834  * RETURN:
3835  * 
3836  */
3837 LRESULT WINAPI LISTVIEW_WindowProc(HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam,
3838                                    LPARAM lParam)
3839 {
3840     switch (uMsg)
3841     {
3842   case LVM_APPROXIMATEVIEWRECT: 
3843     return LISTVIEW_ApproximateViewRect(hwnd, (INT32)wParam, 
3844                                         LOWORD(lParam), HIWORD(lParam));
3845   case LVM_ARRANGE: 
3846     return LISTVIEW_Arrange(hwnd, (INT32)wParam);
3847
3848 /*      case LVM_CREATEDRAGIMAGE: */
3849
3850         case LVM_DELETEALLITEMS:
3851     return LISTVIEW_DeleteAllItems(hwnd);
3852
3853         case LVM_DELETECOLUMN:
3854     return LISTVIEW_DeleteColumn(hwnd, (INT32)wParam);
3855
3856         case LVM_DELETEITEM:
3857     return LISTVIEW_DeleteItem(hwnd, (INT32)wParam);
3858
3859 /*      case LVM_EDITLABEL: */
3860 /*      case LVM_ENSUREVISIBLE: */
3861
3862   case LVM_FINDITEM32A:
3863     return LISTVIEW_FindItem(hwnd, (INT32)wParam, (LPLVFINDINFO)lParam);
3864
3865         case LVM_GETBKCOLOR:
3866     return LISTVIEW_GetBkColor(hwnd);
3867
3868 /*      case LVM_GETBKIMAGE: */
3869 /*      case LVM_GETCALLBACKMASK: */
3870
3871         case LVM_GETCOLUMN32A:
3872     return LISTVIEW_GetColumn32A(hwnd, (INT32)wParam, (LPLVCOLUMN32A)lParam);
3873
3874 /*      case LVM_GETCOLUMN32W: */
3875 /*      case LVM_GETCOLUMNORDERARRAY: */
3876
3877         case LVM_GETCOLUMNWIDTH:
3878     return LISTVIEW_GetColumnWidth(hwnd, (INT32)wParam);
3879
3880   case LVM_GETCOUNTPERPAGE:
3881     return LISTVIEW_GetCountPerPage(hwnd);
3882
3883 /*      case LVM_GETEDITCONTROL: */
3884 /*      case LVM_GETEXTENDEDLISTVIEWSTYLE: */
3885
3886         case LVM_GETHEADER:
3887     return LISTVIEW_GetHeader(hwnd);
3888
3889 /*      case LVM_GETHOTCURSOR: */
3890 /*      case LVM_GETHOTITEM: */
3891 /*      case LVM_GETHOVERTIME: */
3892
3893         case LVM_GETIMAGELIST:
3894     return LISTVIEW_GetImageList(hwnd, (INT32)wParam);
3895
3896 /*      case LVM_GETISEARCHSTRING: */
3897
3898         case LVM_GETITEM32A:
3899     return LISTVIEW_GetItem32A(hwnd, (LPLVITEM32A)lParam);
3900
3901 /*      case LVM_GETITEM32W: */
3902
3903         case LVM_GETITEMCOUNT:
3904     return LISTVIEW_GetItemCount(hwnd);
3905
3906         case LVM_GETITEMPOSITION:
3907     return LISTVIEW_GetItemPosition(hwnd, (INT32)wParam, (LPPOINT32)lParam);
3908
3909   case LVM_GETITEMRECT: 
3910     return LISTVIEW_GetItemRect(hwnd, (INT32)wParam, (LPRECT32)lParam);
3911
3912   case LVM_GETITEMSPACING: 
3913     return LISTVIEW_GetItemSpacing(hwnd, (BOOL32)wParam);
3914
3915   case LVM_GETITEMSTATE: 
3916     return LISTVIEW_GetItemState(hwnd, (INT32)wParam, (UINT32)lParam);
3917     
3918         case LVM_GETITEMTEXT32A:
3919     LISTVIEW_GetItemText32A(hwnd, (INT32)wParam, (LPLVITEM32A)lParam);
3920     break;
3921
3922 /*      case LVM_GETITEMTEXT32W: */
3923
3924         case LVM_GETNEXTITEM:
3925     return LISTVIEW_GetNextItem(hwnd, (INT32)wParam, LOWORD(lParam));
3926
3927 /*      case LVM_GETNUMBEROFWORKAREAS: */
3928   case LVM_GETORIGIN:
3929     return LISTVIEW_GetOrigin(hwnd, (LPPOINT32)lParam);
3930
3931         case LVM_GETSELECTEDCOUNT:
3932     return LISTVIEW_GetSelectedCount(hwnd);
3933
3934   case LVM_GETSELECTIONMARK: 
3935     return LISTVIEW_GetSelectionMark(hwnd);
3936
3937         case LVM_GETSTRINGWIDTH32A:
3938     return LISTVIEW_GetStringWidth32A (hwnd, (LPCSTR)lParam);
3939
3940 /*      case LVM_GETSTRINGWIDTH32W: */
3941 /*      case LVM_GETSUBITEMRECT: */
3942
3943         case LVM_GETTEXTBKCOLOR:
3944     return LISTVIEW_GetTextBkColor(hwnd);
3945
3946         case LVM_GETTEXTCOLOR:
3947     return LISTVIEW_GetTextColor(hwnd);
3948
3949 /*      case LVM_GETTOOLTIPS: */
3950 /*      case LVM_GETTOPINDEX: */
3951 /*      case LVM_GETUNICODEFORMAT: */
3952
3953   case LVM_GETVIEWRECT:
3954     return LISTVIEW_GetViewRect(hwnd, (LPRECT32)lParam);
3955
3956 /*      case LVM_GETWORKAREAS: */
3957
3958         case LVM_HITTEST:
3959     return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
3960
3961         case LVM_INSERTCOLUMN32A:
3962     return LISTVIEW_InsertColumn32A(hwnd, (INT32)wParam, 
3963                                     (LPLVCOLUMN32A)lParam);
3964
3965 /*      case LVM_INSERTCOLUMN32W: */
3966
3967         case LVM_INSERTITEM32A:
3968     return LISTVIEW_InsertItem32A(hwnd, (LPLVITEM32A)lParam);
3969
3970 /*      case LVM_INSERTITEM32W: */
3971
3972         case LVM_REDRAWITEMS:
3973     return LISTVIEW_RedrawItems(hwnd, (INT32)wParam, (INT32)lParam);
3974
3975   case LVM_SCROLL: 
3976     return LISTVIEW_Scroll(hwnd, (INT32)wParam, (INT32)lParam);
3977
3978         case LVM_SETBKCOLOR:
3979     return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
3980
3981 /*      case LVM_SETBKIMAGE: */
3982 /*      case LVM_SETCALLBACKMASK: */
3983
3984         case LVM_SETCOLUMN32A:
3985     return LISTVIEW_SetColumn32A(hwnd, (INT32)wParam, (LPLVCOLUMN32A)lParam);
3986
3987 /*      case LVM_SETCOLUMN32W: */
3988 /*      case LVM_SETCOLUMNORDERARRAY: */
3989 /*      case LVM_SETCOLUMNWIDTH: */
3990 /*      case LVM_SETEXTENDEDLISTVIEWSTYLE: */
3991 /*      case LVM_SETHOTCURSOR: */
3992 /*      case LVM_SETHOTITEM: */
3993 /*      case LVM_SETHOVERTIME: */
3994 /*      case LVM_SETICONSPACING: */
3995         
3996         case LVM_SETIMAGELIST:
3997     return LISTVIEW_SetImageList(hwnd, (INT32)wParam, (HIMAGELIST)lParam);
3998
3999         case LVM_SETITEM32A:
4000     return LISTVIEW_SetItem32A(hwnd, (LPLVITEM32A)lParam);
4001
4002 /*      case LVM_SETITEM32W: */
4003 /*      case LVM_SETITEMCOUNT: */
4004
4005         case LVM_SETITEMPOSITION:
4006     return LISTVIEW_SetItemPosition(hwnd, (INT32)wParam, 
4007                                     (INT32)LOWORD(lParam), 
4008                                     (INT32) HIWORD(lParam));
4009
4010 /*      case LVM_SETITEMPOSITION32: */
4011
4012   case LVM_SETITEMSTATE: 
4013     return LISTVIEW_SetItemState(hwnd, (INT32)wParam, (LPLVITEM32A)lParam);
4014
4015 /*      case LVM_SETITEMTEXT: */
4016 /*      case LVM_SETSELECTIONMARK: */
4017
4018         case LVM_SETTEXTBKCOLOR:
4019     return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
4020
4021         case LVM_SETTEXTCOLOR:
4022     return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
4023
4024 /*      case LVM_SETTOOLTIPS: */
4025 /*      case LVM_SETUNICODEFORMAT: */
4026 /*      case LVM_SETWORKAREAS: */
4027
4028         case LVM_SORTITEMS:
4029     return LISTVIEW_SortItems(hwnd, wParam, lParam);
4030
4031 /*      case LVM_SUBITEMHITTEST: */
4032
4033   case LVM_UPDATE: 
4034     return LISTVIEW_Update(hwnd, (INT32)wParam);
4035
4036 /*      case WM_CHAR: */
4037 /*      case WM_COMMAND: */
4038
4039         case WM_CREATE:
4040     return LISTVIEW_Create(hwnd, wParam, lParam);
4041
4042         case WM_DESTROY:
4043     return LISTVIEW_Destroy(hwnd, wParam, lParam);
4044
4045         case WM_ERASEBKGND:
4046     return LISTVIEW_EraseBackground (hwnd, wParam, lParam);
4047
4048         case WM_GETDLGCODE:
4049             return DLGC_WANTTAB | DLGC_WANTARROWS;
4050
4051         case WM_GETFONT:
4052     return LISTVIEW_GetFont(hwnd);
4053
4054   case WM_HSCROLL:
4055     return LISTVIEW_HScroll(hwnd, (INT32)LOWORD(wParam), 
4056                             (INT32)HIWORD(wParam), (HWND32)lParam);
4057
4058   case WM_KEYDOWN:
4059     return LISTVIEW_KeyDown(hwnd, (INT32)wParam, (LONG)lParam);
4060
4061         case WM_KILLFOCUS:
4062     return LISTVIEW_KillFocus(hwnd);
4063
4064         case WM_LBUTTONDBLCLK:
4065     return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam), 
4066                                 HIWORD(lParam));
4067
4068         case WM_LBUTTONDOWN:
4069     return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam), 
4070                                 HIWORD(lParam));
4071   case WM_LBUTTONUP:
4072     return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam), 
4073                               HIWORD(lParam));
4074
4075 /*      case WM_MOUSEMOVE: */
4076 /*          return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
4077
4078         case WM_NCCREATE:
4079     return LISTVIEW_NCCreate(hwnd, wParam, lParam);
4080
4081         case WM_NCDESTROY:
4082     return LISTVIEW_NCDestroy(hwnd);
4083
4084         case WM_NOTIFY:
4085     return LISTVIEW_Notify(hwnd, (INT32)wParam, (LPNMHDR)lParam);
4086
4087         case WM_PAINT:
4088     return LISTVIEW_Paint(hwnd, (HDC32)wParam); 
4089
4090         case WM_RBUTTONDBLCLK:
4091     return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam), 
4092                                   HIWORD(lParam));
4093
4094         case WM_RBUTTONDOWN:
4095     return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam), 
4096                                 HIWORD(lParam));
4097
4098   case WM_RBUTTONUP:
4099     return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam), 
4100                               HIWORD(lParam));
4101
4102         case WM_SETFOCUS:
4103     return LISTVIEW_SetFocus(hwnd, (HWND32)wParam);
4104
4105         case WM_SETFONT:
4106     return LISTVIEW_SetFont(hwnd, (HFONT32)wParam, (WORD)lParam);
4107
4108 /*      case WM_SETREDRAW: */
4109
4110         case WM_SIZE:
4111     return LISTVIEW_Size(hwnd, LOWORD(lParam), HIWORD(lParam));
4112
4113 /*      case WM_TIMER: */
4114 /*      case WM_VSCROLL: */
4115 /*      case WM_WINDOWPOSCHANGED: */
4116 /*      case WM_WININICHANGE: */
4117
4118         default:
4119             if (uMsg >= WM_USER)
4120                 ERR (listview, "unknown msg %04x wp=%08x lp=%08lx\n",
4121                      uMsg, wParam, lParam);
4122
4123     /* call default window procedure */
4124             return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
4125     }
4126
4127     return 0;
4128 }
4129
4130 /***
4131  * DESCRIPTION:`
4132  * Registers the window class.
4133  * 
4134  * PARAMETER(S):
4135  * None
4136  *
4137  * RETURN:
4138  * None
4139  */
4140 VOID LISTVIEW_Register(VOID)
4141 {
4142     WNDCLASS32A wndClass;
4143
4144   if (!GlobalFindAtom32A(WC_LISTVIEW32A)) 
4145   {
4146     ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
4147     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
4148     wndClass.lpfnWndProc   = (WNDPROC32)LISTVIEW_WindowProc;
4149     wndClass.cbClsExtra    = 0;
4150     wndClass.cbWndExtra    = sizeof(LISTVIEW_INFO *);
4151     wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
4152     wndClass.hbrBackground = (HBRUSH32)(COLOR_WINDOW + 1);
4153     wndClass.lpszClassName = WC_LISTVIEW32A;
4154     RegisterClass32A (&wndClass);
4155 }
4156 }
4157
4158 /***
4159  * DESCRIPTION:
4160  * Unregisters the window class.
4161  * 
4162  * PARAMETER(S):
4163  * None
4164  *
4165  * RETURN:
4166  * None
4167  */
4168 VOID LISTVIEW_Unregister(VOID)
4169 {
4170     if (GlobalFindAtom32A (WC_LISTVIEW32A))
4171         UnregisterClass32A (WC_LISTVIEW32A, (HINSTANCE32)NULL);
4172 }
4173