Implemented:
[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. 
9  *
10  * TODO:
11  *   LISTVIEW_GetMaxItemWidth : large icon view
12  *   LISTVIEW_Notify : notification from children 
13  *   LISTVIEW_KeyDown : key press messages
14  *   LISTVIEW_HScroll : small icon and icon
15  *   LISTVIEW_VScroll : small icon and icon
16  *   LISTVIEW_SortItems : empty stub 
17  *   LISTVIEW_SetItemPosition : small icon and icon
18  *   LISTVIEW_SetItemCount : empty stub 
19  *   LISTVIEW_SetItem32W : no unicode yet!
20  *   LISTVIEW_SetColumn32A : DOUBLE CHECK 
21  *   LISTVIEW_Scroll : scrolling in pixels 
22  *   LISTVIEW_RedrawItems : define bounding rect 
23  *   LISTVIEW_InsertItem32W : no unicode yet!
24  *   LISTVIEW_InsertColumn32W : no unicode yet!
25  *   LISTVIEW_GetViewRect : small icon and icon 
26  *   LISTVIEW_GetOrigin : small icon and icon
27  *   LISTVIEW_GetNumberOfWorkAreas : small icon and icon
28  *   LISTVIEW_GetNextItem : all
29  *   LISTVIEW_SetScroll : scrolling in pixels 
30  *   LISTVIEW_GetItemRect : all 
31  *   LISTVIEW_GetHotCursor : all 
32  *   LISTVIEW_GetHotItem : all 
33  *   LISTVIEW_GetHoverTime : all
34  *   LISTVIEW_GetISearchString : all 
35  *   LISTVIEW_GetBkImage : all
36  *   LISTVIEW_FindItem : all 
37  *   LISTVIEW_EnsureVisible : some 
38  *   LISTVIEW_EditLabel : REPORT (need to implement a timer)
39  *   LISTVIEW_GetItemPosition : small icon and icon
40  *   LISTVIEW_GetItemRect : some
41  *   LISTVIEW_Arrange : small icon and icon
42  *   LISTVIEW_ApproximateViewRect : report, small icon and icon
43  *   LISTVIEW_RefreshIcon : large icon draw function
44  */
45
46 #include <string.h>
47 #include "winbase.h"
48 #include "commctrl.h"
49 #include "listview.h"
50 #include "debug.h"
51
52 /* constants */
53 #define DISP_TEXT_SIZE 128
54 #define WIDTH_PADDING 12
55 #define HEIGHT_PADDING 2
56 #define MIN_COLUMN_WIDTH 96
57
58 /* macro section */
59 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
60 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
61     (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
62 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
63     (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
64
65 /* forward declarations */
66 static VOID LISTVIEW_SetSize(HWND hwnd, LONG lStyle, LONG lWidth, 
67                              LONG lHeight);
68 static VOID LISTVIEW_SetViewInfo(HWND hwnd);
69 static VOID LISTVIEW_SetScroll(HWND hwnd);
70 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem);
71 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem);
72 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem);
73 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem);
74 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem);
75 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast);
76 static VOID LISTVIEW_SetItemFocus(HWND hwnd, INT nItem);
77 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem);
78 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nColumn);
79 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem, 
80                               LPLVITEMA lpLVItem);
81 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
82                                  LPLVITEMA lpLVItem);
83 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem);
84 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem);
85 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem);
86 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem);
87 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem);
88
89
90 /***
91  * DESCRIPTION:
92  * Prints a message for unsupported window styles.
93  * 
94  * PARAMETER(S):
95  * [I] LONG : window style
96  *
97  * RETURN:
98  * None
99  */
100 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
101 {
102   if ((LVS_TYPEMASK & lStyle) == LVS_ALIGNLEFT)
103   {
104     FIXME(listview, "  LVS_ALIGNLEFT\n");
105   } 
106      
107   if ((LVS_TYPEMASK & lStyle) ==  LVS_ALIGNTOP)
108   {
109     FIXME(listview, "  LVS_ALIGNTOP\n");
110   }
111
112   if ((LVS_TYPEMASK & lStyle) == LVS_AUTOARRANGE)
113   {
114     FIXME(listview, "  LVS_AUTOARRANGE\n");
115   }
116
117   if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
118   {
119     FIXME(listview, "  LVS_EDITLABELS\n");
120   }
121
122   if ((LVS_TYPEMASK & lStyle) == LVS_ICON)
123   {
124     FIXME(listview, "  LVS_ICON\n");
125   }
126
127   if ((LVS_TYPEMASK & lStyle) == LVS_NOCOLUMNHEADER)
128   {
129     FIXME(listview, "  LVS_SORTDESCENDING\n");
130   }
131
132   if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
133   {
134     FIXME(listview, "  LVS_NOLABELWRAP\n");
135   }
136
137   if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
138   {
139     FIXME(listview, "  LVS_NOSCROLL\n");
140   }
141
142   if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
143   {
144     FIXME(listview, "  LVS_NOSORTHEADER\n");
145   }
146
147   if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
148   {
149     FIXME(listview, "  LVS_OWNERDRAWFIXED\n");
150   }
151
152   if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
153   {
154     FIXME(listview, "  LVS_SHAREIMAGELISTS\n");
155   }
156
157   if ((LVS_TYPEMASK & lStyle) == LVS_SHOWSELALWAYS)
158   {
159     FIXME(listview, "  LVS_SHOWSELALWAYS\n");
160   }
161
162   if ((LVS_TYPEMASK & lStyle) == LVS_SINGLESEL)
163   {
164     FIXME(listview, "  LVS_SINGLESEL\n");
165   }
166
167   if ((LVS_TYPEMASK & lStyle) == LVS_SMALLICON)
168   {
169     FIXME(listview, "  LVS_SMALLICON\n");
170   }
171
172   if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
173   {
174     FIXME(listview, "  LVS_SORTDESCENDING\n");
175   }
176
177   if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
178   {
179     FIXME(listview, "  LVS_SORTDESCENDING\n");
180   }
181 }
182
183 /***
184  * DESCRIPTION:
185  * Retrieves display information.
186  * 
187  * PARAMETER(S):
188  * [I] HWND : window handle
189  * [I] LISTVIEW_ITEM* : listview control item
190  * [O] INT : image index
191  * [O] UINT : state value
192  * [O] CHAR** : string
193  * [I] INT : size of string
194  *
195  * RETURN:
196  * None
197  */
198 static VOID LISTVIEW_GetItemDispInfo(HWND hwnd, INT nItem, 
199                                      LISTVIEW_ITEM *lpItem, INT *pnDispImage, 
200                                      UINT *puState, CHAR **ppszDispText, 
201                                      INT nDispTextSize)
202 {
203   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
204   LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
205   NMLVDISPINFOA dispInfo;
206   ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
207  
208   if ((pnDispImage != NULL) && (lpItem->iImage == I_IMAGECALLBACK))
209   {
210     dispInfo.item.mask |= LVIF_IMAGE;
211   }
212
213   if ((ppszDispText != NULL) && (lpItem->pszText == LPSTR_TEXTCALLBACKA))
214   {
215     ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize);
216     dispInfo.item.mask |= LVIF_TEXT;
217     dispInfo.item.pszText = *ppszDispText;
218     dispInfo.item.cchTextMax = nDispTextSize;
219   }
220
221   if ((puState != NULL) && (infoPtr->uCallbackMask != 0))
222   {
223     dispInfo.item.mask |= LVIF_STATE;
224     dispInfo.item.stateMask = infoPtr->uCallbackMask; 
225   }
226
227   if (dispInfo.item.mask != 0)
228   {
229     dispInfo.hdr.hwndFrom = hwnd;
230     dispInfo.hdr.idFrom = lCtrlId;
231     dispInfo.hdr.code = LVN_GETDISPINFOA;
232     dispInfo.item.iItem = nItem;
233     dispInfo.item.iSubItem = 0;
234     dispInfo.item.lParam = lpItem->lParam;
235     ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
236   }
237
238   if (pnDispImage != NULL)
239   {
240     if (dispInfo.item.mask & LVIF_IMAGE)
241     {
242       *pnDispImage = dispInfo.item.iImage;
243     }
244     else
245     {
246       *pnDispImage = lpItem->iImage;
247     }
248   }
249
250   if (ppszDispText != NULL)
251   {
252     if (dispInfo.item.mask & LVIF_TEXT)
253     {
254       if (dispInfo.item.mask & LVIF_DI_SETITEM)
255       {
256         Str_SetPtrA(&lpItem->pszText, dispInfo.item.pszText);
257       }
258       *ppszDispText = dispInfo.item.pszText;
259     }
260     else
261     {
262       *ppszDispText = lpItem->pszText;
263     }
264   }
265
266   if (puState != NULL)
267   {
268     if (dispInfo.item.mask & LVIF_STATE)
269     {
270       *puState = lpItem->state;
271       *puState &= ~dispInfo.item.stateMask;
272       *puState |= (dispInfo.item.state & dispInfo.item.stateMask);
273     }
274     else
275     {
276       *puState = lpItem->state;
277     }
278   }
279 }
280
281 /***
282  * DESCRIPTION:
283  * Retrieves display information.
284  * 
285  * PARAMETER(S):
286  * [I] HWND : window handle
287  * [I] LISTVIEW_SUBITEM* : listview control subitem
288  * [O] INT : image index
289  * [O] UINT : state value
290  * [O] CHAR** : string
291  * [I] INT : size of string
292  *
293  * RETURN:
294  * None
295  */
296 static VOID LISTVIEW_GetSubItemDispInfo(HWND hwnd, INT nItem, LPARAM lParam,
297                                         LISTVIEW_SUBITEM *lpSubItem, 
298                                         INT nColumn, INT *pnDispImage, 
299                                         CHAR **ppszDispText, INT nDispTextSize)
300 {
301   LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
302   NMLVDISPINFOA dispInfo;
303   ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
304
305   if (lpSubItem == NULL)
306   {
307     ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize);
308     dispInfo.item.mask |= LVIF_TEXT;
309     dispInfo.item.pszText = *ppszDispText;
310     dispInfo.item.cchTextMax = nDispTextSize;
311     dispInfo.hdr.hwndFrom = hwnd;
312     dispInfo.hdr.idFrom = lCtrlId;
313     dispInfo.hdr.code = LVN_GETDISPINFOA;
314     dispInfo.item.iItem = nItem;
315     dispInfo.item.iSubItem = nColumn;
316     dispInfo.item.lParam = lParam;
317     ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
318     if (dispInfo.item.mask & LVIF_DI_SETITEM)
319     {
320       Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText);
321     }
322     *ppszDispText = dispInfo.item.pszText;
323   }
324   else
325   {
326     if ((pnDispImage != NULL) && (lpSubItem->iImage == I_IMAGECALLBACK))
327     {
328       dispInfo.item.mask |= LVIF_IMAGE;
329     }
330
331     if ((ppszDispText != NULL) && (lpSubItem->pszText == LPSTR_TEXTCALLBACKA))
332     {
333       ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize);
334       dispInfo.item.mask |= LVIF_TEXT;
335       dispInfo.item.pszText = *ppszDispText;
336       dispInfo.item.cchTextMax = nDispTextSize;
337     }
338
339     if (dispInfo.item.mask != 0)
340     {
341       dispInfo.hdr.hwndFrom = hwnd;
342       dispInfo.hdr.idFrom = lCtrlId;
343       dispInfo.hdr.code = LVN_GETDISPINFOA;
344       dispInfo.item.iItem = nItem;
345       dispInfo.item.iSubItem = lpSubItem->iSubItem;
346       dispInfo.item.lParam = lParam;
347       ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
348     }
349
350     if (pnDispImage != NULL)
351     {
352       if (dispInfo.item.mask & LVIF_IMAGE)
353       {
354         *pnDispImage = dispInfo.item.iImage;
355       }
356       else
357       {
358         *pnDispImage = lpSubItem->iImage;
359       }
360     }
361
362     if (ppszDispText != NULL)
363     {
364       if (dispInfo.item.mask & LVIF_TEXT)
365       {
366         if (dispInfo.item.mask & LVIF_DI_SETITEM)
367         {
368           Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText);
369         }
370         *ppszDispText = dispInfo.item.pszText;
371       }
372       else
373       {
374         *ppszDispText = lpSubItem->pszText;
375       }
376     }
377   }
378 }
379
380 /***
381  * DESCRIPTION:
382  * Calculates a new column width.
383  * 
384  * PARAMETER(S):
385  * [I] HWND : window handle
386  *
387  * RETURN:
388  * Returns item width.
389  */
390 static INT LISTVIEW_GetMaxItemWidth(HWND hwnd)
391 {
392   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
393   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
394   LISTVIEW_ITEM *lpItem;
395   HDPA hdpaSubItems;
396   INT nStringWidth;
397   INT nMaxItemWidth = 0;
398   INT i;
399   
400   if ((LVS_TYPEMASK & lStyle) == LVS_ICON)
401   {
402     /* TO DO */
403   }
404   else
405   {
406     for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
407     { 
408       hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
409       if (hdpaSubItems != NULL)
410       {
411         lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
412         if (lpItem != NULL)
413         {
414           CHAR szDispText[DISP_TEXT_SIZE];
415           LPSTR pszDispText;
416           pszDispText = szDispText;
417           LISTVIEW_GetItemDispInfo(hwnd, i, lpItem, NULL, NULL, &pszDispText, 
418                                    DISP_TEXT_SIZE);
419           nStringWidth = ListView_GetStringWidthA(hwnd, pszDispText);
420           nMaxItemWidth = max(nMaxItemWidth, nStringWidth);
421         }
422       }
423     }
424     
425     /* add arbitrary padding for separating columns */
426     nMaxItemWidth += WIDTH_PADDING;
427
428     if (infoPtr->himlSmall != NULL)
429     {
430       nMaxItemWidth += infoPtr->iconSize.cx;
431     }
432
433     if (infoPtr->himlState != NULL)
434     {
435       nMaxItemWidth += infoPtr->iconSize.cx;
436     }
437   }
438
439   nMaxItemWidth = max(MIN_COLUMN_WIDTH, nMaxItemWidth);
440
441   return nMaxItemWidth;
442 }
443
444 /***
445  * DESCRIPTION:
446  * Sets diplay information (needed for drawing and calculations).
447  * 
448  * PARAMETER(S):
449  * [I] HWND : window handle
450  * 
451  * RETURN:
452  * None
453  */
454 static VOID LISTVIEW_SetViewInfo(HWND hwnd)
455 {
456   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
457   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
458   INT nHeight;
459   INT nWidth;
460   HDC hdc;
461   HFONT hOldFont;
462   TEXTMETRICA tm; 
463
464   /* get text height */
465   hdc = GetDC(hwnd);
466   hOldFont = SelectObject(hdc, infoPtr->hFont);
467   GetTextMetricsA(hdc, &tm);
468
469   nHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
470   nWidth = infoPtr->rcList.right - infoPtr->rcList.left;
471
472   switch (LVS_TYPEMASK & lStyle)
473   {
474   case LVS_LIST:
475     infoPtr->nColumnWidth = LISTVIEW_GetMaxItemWidth(hwnd);
476     infoPtr->nItemHeight = (max(tm.tmHeight, infoPtr->iconSize.cy) + 
477                             HEIGHT_PADDING);
478     
479     infoPtr->nCountPerColumn = nHeight / infoPtr->nItemHeight;
480     if (infoPtr->nCountPerColumn == 0)
481     {
482       infoPtr->nCountPerColumn = 1;
483     }
484     
485     infoPtr->nCountPerRow = nWidth / infoPtr->nColumnWidth;
486     if (infoPtr->nCountPerRow == 0)
487     {
488       infoPtr->nCountPerRow = 1;
489     }
490     break;
491
492   case LVS_REPORT:
493     infoPtr->nItemHeight = (max(tm.tmHeight, infoPtr->iconSize.cy) + 
494                             HEIGHT_PADDING);
495     infoPtr->nCountPerRow = 1;
496     infoPtr->nCountPerColumn = nHeight / infoPtr->nItemHeight;
497     if (infoPtr->nCountPerColumn == 0)
498     {
499       infoPtr->nCountPerColumn = 1;
500     }
501     break;
502
503   }
504
505   SelectObject(hdc, hOldFont);
506   ReleaseDC(hwnd, hdc);
507 }
508
509 /***
510  * DESCRIPTION:
511  * Adds a block of selections.
512  * 
513  * PARAMETER(S):
514  * [I] HWND : window handle
515  * [I] INT : item index 
516  *
517  * RETURN:
518  * None
519  */
520 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
521 {
522   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
523   INT nFirst = min(infoPtr->nSelectionMark, nItem);
524   INT nLast = max(infoPtr->nSelectionMark, nItem);
525   LVITEMA lvItem;
526   INT i;
527
528   lvItem.state = LVIS_SELECTED;
529   lvItem.stateMask= LVIS_SELECTED;
530   
531   for (i = nFirst; i <= nLast; i++)
532   {
533     ListView_SetItemState(hwnd, i, &lvItem);
534   }
535   
536   LISTVIEW_SetItemFocus(hwnd, nItem);
537   infoPtr->nSelectionMark = nItem;
538 }
539
540 /***
541  * DESCRIPTION:
542  * Adds a single selection.
543  * 
544  * PARAMETER(S):
545  * [I] HWND : window handle
546  * [I] INT : item index 
547  *
548  * RETURN:
549  * None
550  */
551 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
552 {
553   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
554   LVITEMA lvItem;
555
556   lvItem.state = LVIS_SELECTED;
557   lvItem.stateMask= LVIS_SELECTED;
558
559   ListView_SetItemState(hwnd, nItem, &lvItem);
560
561   LISTVIEW_SetItemFocus(hwnd, nItem);
562   infoPtr->nSelectionMark = nItem;
563 }
564
565 /***
566  * DESCRIPTION:
567  * Selects or unselects an item.
568  * 
569  * PARAMETER(S):
570  * [I] HWND : window handle
571  * [I] INT : item index 
572  *
573  * RETURN:
574  *   SELECT: TRUE 
575  *   UNSELECT : FALSE
576  */
577 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
578 {
579   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
580   BOOL bResult;
581   LVITEMA lvItem;
582
583   lvItem.stateMask= LVIS_SELECTED;
584
585   if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
586   {
587     lvItem.state = 0;
588     ListView_SetItemState(hwnd, nItem, &lvItem);
589     bResult = FALSE;
590   }
591   else
592   {
593     lvItem.state = LVIS_SELECTED;
594     ListView_SetItemState(hwnd, nItem, &lvItem);
595     bResult = TRUE;
596   }
597
598   LISTVIEW_SetItemFocus(hwnd, nItem);
599   infoPtr->nSelectionMark = nItem;
600
601   return bResult;
602 }
603
604 /***
605  * DESCRIPTION:
606  * Reinitilizes the listview items.
607  * 
608  * PARAMETER(S):
609  * [I] HWND : window handle
610  * [I] INT : item index 
611  *
612  * RETURN:
613  * None 
614  */
615 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
616 {
617   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
618   INT nFirst = min(infoPtr->nSelectionMark, nItem);
619   INT nLast = max(infoPtr->nSelectionMark, nItem);
620   LVITEMA lvItem;
621   INT i;
622
623   if (nFirst > 0)
624   {
625     LISTVIEW_RemoveSelections(hwnd, 0, nFirst - 1);
626   }
627
628   if (nLast < GETITEMCOUNT(infoPtr))
629   {
630     LISTVIEW_RemoveSelections(hwnd, nLast + 1, GETITEMCOUNT(infoPtr));
631   }
632
633   lvItem.state = LVIS_SELECTED;
634   lvItem.stateMask = LVIS_SELECTED;
635
636   for (i = nFirst; i <= nLast; i++)
637   {
638     ListView_SetItemState(hwnd, i, &lvItem);
639   }
640
641   LISTVIEW_SetItemFocus(hwnd, nItem);
642 }
643
644 /***
645  * DESCRIPTION:
646  * Manages the item focus.
647  * 
648  * PARAMETER(S):
649  * [I] HWND : window handle
650  * [I] INT : item index 
651  *
652  * RETURN:
653  * None
654  */
655 static VOID LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
656 {
657   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
658   LVITEMA lvItem;
659
660   lvItem.state = 0;
661   lvItem.stateMask = LVIS_FOCUSED;
662   ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem); 
663   
664   lvItem.state =  LVIS_FOCUSED;
665   lvItem.stateMask = LVIS_FOCUSED;
666   ListView_SetItemState(hwnd, nItem, &lvItem);
667
668   infoPtr->nFocusedItem = nItem;
669
670   /* if multiple selection is allowed */
671   ListView_EnsureVisible(hwnd, nItem, FALSE);
672 }
673
674 /***
675  * DESCRIPTION:
676  * Reinitilizes the listview items.
677  * 
678  * PARAMETER(S):
679  * [I] HWND : window handle
680  * [I] INT : item index 
681  *
682  * RETURN:
683  * None
684  */
685 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
686 {
687   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
688   LVITEMA lvItem;
689
690   if (nItem > 0)
691   {
692     LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
693   }
694
695   if (nItem < GETITEMCOUNT(infoPtr))
696   {
697     LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
698   }
699
700   lvItem.state = 0;
701   lvItem.stateMask = LVIS_FOCUSED;
702   ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem); 
703   
704   lvItem.state =  LVIS_SELECTED | LVIS_FOCUSED;
705   lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
706   ListView_SetItemState(hwnd, nItem, &lvItem);
707
708   infoPtr->nFocusedItem = nItem;
709   infoPtr->nSelectionMark = nItem;
710 }
711
712 /***
713  * DESCRIPTION:
714  * Reinitilizes the listview items.
715  * 
716  * PARAMETER(S):
717  * [I] HWND : window handle
718  * [I] INT : item index 
719  *
720  * RETURN:
721  * None
722  */
723 static VOID LISTVIEW_KeySelection(HWND hwnd, INT nItem)
724 {
725   WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
726   WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
727
728   if (wShift)
729   {
730     LISTVIEW_SetGroupSelection(hwnd, nItem); 
731   }
732   else if (wCtrl)
733   {
734     LISTVIEW_SetItemFocus(hwnd, nItem);
735   }
736   else
737   {
738     LISTVIEW_SetSelection(hwnd, nItem); 
739
740     /* if multiple selection is allowed */
741     ListView_EnsureVisible(hwnd, nItem, FALSE);
742   }
743 }
744
745 /***
746  * DESCRIPTION:
747  * Removes all selection states.
748  * 
749  * PARAMETER(S):
750  * [I] HWND : window handle
751  * [I] INT : item index 
752  *
753  * RETURN:
754  *   SUCCCESS : TRUE
755  *   FAILURE : FALSE
756  */
757 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
758 {
759   LVITEMA lvItem;
760   INT i;
761
762   lvItem.state = 0;
763   lvItem.stateMask = LVIS_SELECTED;
764
765   for (i = nFirst; i <= nLast; i++)
766   {
767     ListView_SetItemState(hwnd, i, &lvItem);
768   }
769 }
770
771 /***
772  * DESCRIPTION:
773  * Removes a column.
774  * 
775  * PARAMETER(S):
776  * [IO] HDPA : dynamic pointer array handle
777  * [I] INT : column index (subitem index)
778  *
779  * RETURN:
780  *   SUCCCESS : TRUE
781  *   FAILURE : FALSE
782  */
783 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
784 {
785   BOOL bResult = TRUE;
786   HDPA hdpaSubItems;
787   INT i;
788
789   for (i = 0; i < hdpaItems->nItemCount; i++)
790   {
791     hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
792     if (hdpaSubItems != NULL)
793     {
794       if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
795       {
796         bResult = FALSE;
797       }
798     }
799   }
800     
801   return bResult;
802 }
803
804 /***
805  * DESCRIPTION:
806  * Removes a subitem at a given position.
807  * 
808  * PARAMETER(S):
809  * [IO] HDPA : dynamic pointer array handle
810  * [I] INT : subitem index
811  *
812  * RETURN:
813  *   SUCCCESS : TRUE
814  *   FAILURE : FALSE
815  */
816 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
817 {
818   LISTVIEW_SUBITEM *lpSubItem;
819   INT i;
820
821   for (i = 1; i < hdpaSubItems->nItemCount; i++)
822   {
823     lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
824     if (lpSubItem != NULL)
825     {
826       if (lpSubItem->iSubItem == nSubItem)
827       {
828         /* free string */
829         if ((lpSubItem->pszText != NULL) && 
830             (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
831         {
832           COMCTL32_Free(lpSubItem->pszText);
833         }
834       
835         /* free item */
836         COMCTL32_Free(lpSubItem);
837
838         /* free dpa memory */
839         if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
840         {
841           return FALSE;
842         }
843       }
844       else if (lpSubItem->iSubItem > nSubItem)
845       {
846         return TRUE;
847       }
848     }
849   }    
850   
851   return TRUE;
852 }
853
854 /***
855  * DESCRIPTION:
856  * Compares the item information.
857  * 
858  * PARAMETER(S):
859  * [I] LISTVIEW_ITEM *: destination item 
860  * [I] LPLVITEM : source item 
861  *
862  * RETURN:
863  *   SUCCCESS : TRUE (EQUAL)
864  *   FAILURE : FALSE (NOT EQUAL)
865  */
866 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
867 {
868   UINT uChanged = 0;
869
870   if ((lpItem != NULL) && (lpLVItem != NULL))
871   {
872     if (lpLVItem->mask & LVIF_STATE)
873     {
874       if ((lpItem->state & lpLVItem->stateMask) != 
875           (lpLVItem->state & lpLVItem->stateMask))
876       {
877         uChanged |= LVIF_STATE; 
878       }
879     }
880     
881     if (lpLVItem->mask & LVIF_IMAGE)
882     {
883       if (lpItem->iImage != lpLVItem->iImage)
884       {
885         uChanged |= LVIF_IMAGE; 
886       }
887     }
888   
889     if (lpLVItem->mask & LVIF_PARAM)
890     {
891       if (lpItem->lParam != lpLVItem->lParam)
892       {
893         uChanged |= LVIF_PARAM; 
894       }
895     }
896     
897     if (lpLVItem->mask & LVIF_INDENT)
898     {
899       if (lpItem->iIndent != lpLVItem->iIndent)
900       {
901         uChanged |= LVIF_INDENT; 
902       }
903     }
904
905     if (lpLVItem->mask & LVIF_TEXT) 
906     {
907       if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA) 
908       {
909         if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
910         {
911           uChanged |= LVIF_TEXT; 
912         }
913       }
914       else
915       {
916         if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
917         {
918           uChanged |= LVIF_TEXT; 
919         }
920       }
921     }
922   }
923
924   return uChanged;
925 }
926
927 /***
928  * DESCRIPTION:
929  * Initializes item attributes.
930  * 
931  * PARAMETER(S):
932  * [I] HWND : window handle
933  * [O] LISTVIEW_ITEM *: destination item 
934  * [I] LPLVITEM : source item 
935  *
936  * RETURN:
937  *   SUCCCESS : TRUE
938  *   FAILURE : FALSE
939  */
940 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem, 
941                                 LPLVITEMA lpLVItem)
942 {
943   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
944   BOOL bResult = FALSE;
945
946   if ((lpItem != NULL) && (lpLVItem != NULL))
947   {
948     bResult = TRUE;
949     
950     if (lpLVItem->mask & LVIF_STATE)
951     {
952       lpItem->state &= ~lpLVItem->stateMask;
953       lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
954     }
955     
956     if (lpLVItem->mask & LVIF_IMAGE)
957     {
958       lpItem->iImage = lpLVItem->iImage;
959     }
960   
961     if (lpLVItem->mask & LVIF_PARAM)
962     {
963       lpItem->lParam = lpLVItem->lParam;
964     }
965     
966     if (lpLVItem->mask & LVIF_INDENT)
967     {
968       lpItem->iIndent = lpLVItem->iIndent;
969     }
970
971     if (lpLVItem->mask & LVIF_TEXT) 
972     {
973       if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA) 
974       {
975         if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
976         {
977           return FALSE;
978         }
979
980         if ((lpItem->pszText != NULL) && 
981             (lpItem->pszText != LPSTR_TEXTCALLBACKA))
982         {
983           COMCTL32_Free(lpItem->pszText);
984         }
985     
986         lpItem->pszText = LPSTR_TEXTCALLBACKA;
987       }
988       else 
989       {
990         if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
991         {
992           lpItem->pszText = NULL;
993         }
994         
995         bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
996       }
997     }
998   }
999
1000   return bResult;
1001 }
1002
1003 /***
1004  * DESCRIPTION:
1005  * Initializes subitem attributes.
1006  *
1007  * NOTE: the documentation specifies that the operation fails if the user
1008  * tries to set the indent of a subitem.
1009  *
1010  * PARAMETER(S):
1011  * [I] HWND : window handle
1012  * [O] LISTVIEW_SUBITEM *: destination subitem
1013  * [I] LPLVITEM : source subitem
1014  *
1015  * RETURN:
1016  *   SUCCCESS : TRUE
1017  *   FAILURE : FALSE
1018  */
1019 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem, 
1020                                    LPLVITEMA lpLVItem)
1021 {
1022   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1023   BOOL bResult = FALSE;
1024   
1025   if ((lpSubItem != NULL) && (lpLVItem != NULL))
1026   {
1027     if (!(lpLVItem->mask & LVIF_INDENT))
1028     {
1029       bResult = TRUE;
1030       ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1031
1032       lpSubItem->iSubItem = lpLVItem->iSubItem;
1033
1034       if (lpLVItem->mask & LVIF_IMAGE)
1035       {
1036         lpSubItem->iImage = lpLVItem->iImage;
1037       }
1038       
1039       if (lpLVItem->mask & LVIF_TEXT) 
1040       {
1041         if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA) 
1042         {
1043           if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1044           {
1045             return FALSE;
1046           } 
1047
1048           if ((lpSubItem->pszText != NULL) && 
1049               (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1050           {
1051             COMCTL32_Free(lpSubItem->pszText);
1052           }
1053     
1054           lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1055         }
1056         else 
1057         {
1058           if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1059           {
1060             lpSubItem->pszText = NULL;
1061           }
1062         
1063           bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1064         }
1065       }
1066     }
1067   }
1068
1069   return bResult;
1070 }
1071
1072 /***
1073  * DESCRIPTION:
1074  * Adds a subitem at a given position (column index).
1075  * 
1076  * PARAMETER(S):
1077  * [I] HWND : window handle
1078  * [I] LPLVITEM : new subitem atttributes 
1079  *
1080  * RETURN:
1081  *   SUCCESS : TRUE
1082  *   FAILURE : FALSE
1083  */
1084 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1085 {
1086   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1087   BOOL bResult = FALSE;
1088   HDPA hdpaSubItems;
1089   LISTVIEW_SUBITEM *lpSubItem = NULL;
1090   INT nPosition, nItem;
1091
1092   if (lpLVItem != NULL)
1093   {
1094     hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1095     if (hdpaSubItems != NULL)
1096     {
1097       lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1098       if (lpSubItem != NULL)
1099       {
1100         if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) == TRUE)
1101         {
1102           nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems, 
1103                                                   lpSubItem->iSubItem);
1104           nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1105           if (nItem != -1)
1106           {
1107             bResult = TRUE;
1108           }            
1109         }
1110       }
1111     }
1112   }
1113   
1114   /* cleanup if unsuccessful */   
1115   if ((bResult == FALSE) && (lpSubItem != NULL))
1116   {
1117     COMCTL32_Free(lpSubItem);
1118   }
1119   
1120   return bResult;
1121 }
1122
1123 /***
1124  * DESCRIPTION:
1125  * Finds the dpa insert position (array index).
1126  * 
1127  * PARAMETER(S):
1128  * [I] HWND : window handle
1129  * [I] INT : subitem index
1130  *
1131  * RETURN:
1132  *   SUCCESS : TRUE
1133  *   FAILURE : FALSE
1134  */
1135 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1136 {
1137   LISTVIEW_SUBITEM *lpSubItem;
1138   INT i;
1139
1140   for (i = 1; i < hdpaSubItems->nItemCount; i++)
1141   {
1142     lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1143     if (lpSubItem != NULL)
1144     {
1145       if (lpSubItem->iSubItem > nSubItem)
1146       {
1147         return i;
1148       }
1149     } 
1150   }
1151
1152   return hdpaSubItems->nItemCount;
1153 }
1154
1155 /***
1156  * DESCRIPTION:
1157  * Retrieves a listview subitem at a given position (column index).
1158  * 
1159  * PARAMETER(S):
1160  * [I] HWND : window handle
1161  * [I] INT : subitem index
1162  *
1163  * RETURN:
1164  *   SUCCESS : TRUE
1165  *   FAILURE : FALSE
1166  */
1167 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1168 {
1169   LISTVIEW_SUBITEM *lpSubItem;
1170   INT i;
1171
1172   for (i = 1; i < hdpaSubItems->nItemCount; i++)
1173   {
1174     lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1175     if (lpSubItem != NULL)
1176     {
1177       if (lpSubItem->iSubItem == nSubItem)
1178       {
1179         return lpSubItem;
1180       }
1181       else if (lpSubItem->iSubItem > nSubItem)
1182       {
1183         return NULL;
1184       }  
1185     }
1186   }
1187   
1188   return NULL;
1189 }
1190
1191 /***
1192  * DESCRIPTION:
1193  * Sets item attributes.
1194  * 
1195  * PARAMETER(S):
1196  * [I] HWND : window handle
1197  * [I] LPLVITEM : new item atttributes 
1198  *
1199  * RETURN:
1200  *   SUCCESS : TRUE
1201  *   FAILURE : FALSE
1202  */
1203 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1204 {
1205   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1206   BOOL bResult = FALSE;
1207   HDPA hdpaSubItems;
1208   LISTVIEW_ITEM *lpItem;
1209   NMLISTVIEW nmlv;
1210   UINT uChanged;
1211   LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1212
1213   if (lpLVItem != NULL)
1214   {
1215     if (lpLVItem->iSubItem == 0)
1216     {
1217       hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1218       if (hdpaSubItems != NULL)
1219       {
1220         lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1221         if (lpItem != NULL)
1222         {
1223           ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1224           nmlv.hdr.hwndFrom = hwnd;
1225           nmlv.hdr.idFrom = lCtrlId;
1226           nmlv.hdr.code = LVN_ITEMCHANGING;
1227           nmlv.lParam = lpItem->lParam;
1228           uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1229           if (uChanged != 0)
1230           {
1231             if (uChanged & LVIF_STATE)
1232             {
1233               nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1234               nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1235             }
1236
1237             nmlv.uChanged = uChanged;
1238             nmlv.iItem = lpLVItem->iItem;
1239             nmlv.lParam = lpItem->lParam;
1240             /* send LVN_ITEMCHANGING notification */
1241             ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1242
1243             /* copy information */
1244             bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1245
1246             /* send LVN_ITEMCHANGED notification */
1247             nmlv.hdr.code = LVN_ITEMCHANGED;
1248             ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1249           }
1250           else
1251           {
1252             bResult = TRUE;
1253           }
1254
1255           InvalidateRect(hwnd, NULL, FALSE);
1256         }
1257       }
1258     }
1259   }
1260
1261   return bResult;
1262 }
1263
1264 /***
1265  * DESCRIPTION:
1266  * Sets subitem attributes.
1267  * 
1268  * PARAMETER(S):
1269  * [I] HWND : window handle
1270  * [I] LPLVITEM : new subitem atttributes 
1271  *
1272  * RETURN:
1273  *   SUCCESS : TRUE
1274  *   FAILURE : FALSE
1275  */
1276 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1277 {
1278   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1279   BOOL bResult = FALSE;
1280   HDPA hdpaSubItems;
1281   LISTVIEW_SUBITEM *lpSubItem;
1282
1283   if (lpLVItem != NULL)
1284   {
1285     if (lpLVItem->iSubItem > 0)
1286     {
1287       hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1288       if (hdpaSubItems != NULL)
1289       {
1290         /* set subitem only if column is present */
1291         if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1292         {
1293           lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1294           if (lpSubItem != NULL)
1295           {
1296             bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1297           }
1298           else
1299           {
1300             bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1301           }
1302           
1303           InvalidateRect(hwnd, NULL, FALSE);
1304         } 
1305       }
1306     }
1307   }
1308
1309   return bResult;
1310 }
1311
1312 /***
1313  * DESCRIPTION:
1314  * Retrieves the index of the item at coordinate (0, 0) of the client area.
1315  * 
1316  * PARAMETER(S):
1317  * [I] HWND : window handle
1318  *
1319  * RETURN:
1320  * item index
1321  */
1322 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1323 {
1324   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *) GetWindowLongA(hwnd, 0);
1325   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1326   INT nItem = 0;
1327
1328   switch (LVS_TYPEMASK & lStyle)
1329   {
1330   case LVS_LIST:
1331     if (lStyle & WS_HSCROLL)
1332     {
1333       nItem = GetScrollPos(hwnd, SB_HORZ) * infoPtr->nCountPerColumn;
1334     }
1335     break;
1336
1337   case LVS_REPORT:
1338     if (lStyle & WS_VSCROLL)
1339     {
1340       nItem = GetScrollPos(hwnd, SB_VERT);
1341     }
1342     break;
1343   }
1344
1345   return nItem;
1346 }
1347
1348 /***
1349  * DESCRIPTION:
1350  * Sets scrollbar(s). 
1351  * 
1352  * PARAMETER(S):
1353  * [I] HWND : window handle
1354  *
1355  * RETURN:
1356  *   TRUE if scrollbars were added, modified or removed.
1357  */
1358 static VOID LISTVIEW_SetVScroll(HWND hwnd)
1359 {
1360   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1361   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1362   INT nScrollPos;
1363   INT nMaxRange;
1364
1365   switch (LVS_TYPEMASK & lStyle)
1366   {
1367   case LVS_REPORT:
1368     nMaxRange = GETITEMCOUNT(infoPtr) - infoPtr->nCountPerColumn;
1369     SetScrollRange(hwnd, SB_VERT, 0, nMaxRange, FALSE);
1370     nScrollPos = ListView_GetTopIndex(hwnd);
1371     SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);
1372     break;
1373     
1374   default:
1375     /* TO DO */
1376   }
1377 }
1378
1379 static VOID LISTVIEW_SetHScroll(HWND hwnd)
1380 {
1381 /*   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
1382   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1383 /*   INT nScrollPos; */
1384 /*   INT nMaxRange; */
1385
1386   switch (LVS_TYPEMASK & lStyle)
1387   {
1388   case LVS_REPORT:
1389     /* TO DO */
1390     break;
1391
1392   default:
1393     /* TO DO */
1394   }
1395 }
1396
1397 static VOID LISTVIEW_SetScroll(HWND hwnd)
1398 {
1399   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1400   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1401   INT nHiddenItemCount;
1402   INT nScrollPos;
1403   INT nMaxRange;
1404   INT nCountPerPage;
1405   RECT rc;
1406   BOOL bHScroll = FALSE;
1407   BOOL bVScroll = FALSE;
1408   INT nHeaderWidth = 0;
1409   INT nItemCount;
1410   INT i;
1411
1412   switch (LVS_TYPEMASK & lStyle)
1413   {
1414   case LVS_LIST:
1415     nCountPerPage = infoPtr->nCountPerRow * infoPtr->nCountPerColumn;
1416     if (nCountPerPage < GETITEMCOUNT(infoPtr))
1417     {
1418       /* add scrollbar if not already present */
1419       if (!(lStyle & WS_HSCROLL))
1420       {
1421         ShowScrollBar(hwnd, SB_HORZ, TRUE);
1422       }
1423
1424       /* calculate new scrollbar range */
1425       nHiddenItemCount = GETITEMCOUNT(infoPtr) - nCountPerPage;
1426       if ((nHiddenItemCount % infoPtr->nCountPerColumn) == 0)
1427       {
1428         nMaxRange = nHiddenItemCount / infoPtr->nCountPerColumn;
1429       }
1430       else
1431       {
1432         nMaxRange = nHiddenItemCount / infoPtr->nCountPerColumn + 1;
1433       }
1434         
1435       SetScrollRange(hwnd, SB_HORZ, 0, nMaxRange, FALSE);
1436       nScrollPos = ListView_GetTopIndex(hwnd) / infoPtr->nCountPerColumn;
1437       SetScrollPos(hwnd, SB_HORZ, nScrollPos, TRUE);
1438     }
1439     else
1440     {
1441       /* remove scrollbar if present */
1442       if (lStyle & WS_HSCROLL)
1443       {
1444         /* hide scrollbar */
1445         ShowScrollBar(hwnd, SB_HORZ, FALSE);
1446       }
1447     }
1448     break;
1449     
1450   case LVS_REPORT:
1451     nItemCount = Header_GetItemCount(infoPtr->hwndHeader);
1452     for (i = 0; i < nItemCount; i++)
1453     {
1454       if (Header_GetItemRect(infoPtr->hwndHeader, i, &rc) != 0)
1455       {
1456         nHeaderWidth += (rc.right - rc.left);
1457       }
1458     }
1459
1460     if (nHeaderWidth > (infoPtr->rcList.right - infoPtr->rcList.left))
1461     {
1462       bHScroll = TRUE;
1463       
1464       /* add horizontal scrollbar if not present */
1465       if (!(lStyle & WS_HSCROLL))
1466       {
1467         /* display scrollbar */
1468         ShowScrollBar(hwnd, SB_HORZ, TRUE);
1469       }
1470     }
1471     else
1472     {
1473       /* remove scrollbar if present */
1474       if (lStyle & WS_HSCROLL)
1475       {
1476         /* hide scrollbar */
1477         ShowScrollBar(hwnd, SB_HORZ, FALSE);
1478       }
1479     }
1480   
1481     if (infoPtr->nCountPerColumn < GETITEMCOUNT(infoPtr))
1482     {
1483       bVScroll = TRUE;
1484
1485       /* add scrollbar if not already present */
1486       if (!(lStyle & WS_VSCROLL))
1487       {
1488         /* display scrollbar */
1489         ShowScrollBar(hwnd, SB_VERT, TRUE);
1490       }
1491     }
1492     else
1493     {
1494       /* remove scrollbar if present */
1495       if (lStyle & WS_VSCROLL)
1496       {
1497         /* hide scrollbar */
1498         ShowScrollBar(hwnd, SB_VERT, FALSE);
1499       }
1500     }
1501     break;
1502
1503   default:
1504     /* TO DO */
1505   }
1506
1507   /* set range and position */
1508   GetClientRect(hwnd, &rc);
1509   if ((bHScroll == TRUE) || (bVScroll == TRUE))
1510   {
1511     LISTVIEW_SetSize(hwnd, lStyle, rc.right, rc.bottom);
1512     LISTVIEW_SetViewInfo(hwnd);
1513     if (bHScroll == TRUE)
1514     {
1515       LISTVIEW_SetHScroll(hwnd);
1516     }
1517
1518     if (bVScroll == TRUE)
1519     {
1520       LISTVIEW_SetVScroll(hwnd);
1521     }
1522   }
1523 }
1524
1525 /***
1526  * DESCRIPTION:
1527  * Draws a subitem.
1528  * 
1529  * PARAMETER(S):
1530  * [I] HDC : device context handle
1531  * [I] LISTVIEW_INFO * : listview information
1532  * [I] LISTVIEW_SUBITEM * : subitem
1533  * [I] RECT * : clipping rectangle
1534  *
1535  * RETURN:
1536  * None
1537  */
1538 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, LPARAM lParam,
1539                                  LISTVIEW_SUBITEM *lpSubItem, INT nColumn, 
1540                                  RECT *lprc)
1541 {
1542   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1543   CHAR szDispText[DISP_TEXT_SIZE];
1544   LPSTR pszDispText = NULL;
1545
1546   /* set item colors */
1547   SetBkColor(hdc, infoPtr->clrTextBk);
1548   SetTextColor(hdc, infoPtr->clrText);
1549   
1550   pszDispText = szDispText;
1551   LISTVIEW_GetSubItemDispInfo(hwnd, nItem, lParam, lpSubItem, nColumn, NULL, 
1552                               &pszDispText, DISP_TEXT_SIZE);
1553
1554   /* draw text : using arbitrary offset of 10 pixels */  
1555   ExtTextOutA(hdc, lprc->left + 10, lprc->top, ETO_OPAQUE|ETO_CLIPPED, 
1556               lprc, pszDispText, lstrlenA(pszDispText), NULL);
1557 }
1558
1559 /***
1560  * DESCRIPTION:
1561  * Draws an item.
1562  * 
1563  * PARAMETER(S):
1564  * [I] HDC : device context handle
1565  * [I] LISTVIEW_INFO * : listview information
1566  * [I] LISTVIEW_ITEM * : item
1567  * [I] RECT * : clipping rectangle
1568  *
1569  * RETURN:
1570  * None
1571  */
1572 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, LISTVIEW_ITEM *lpItem, 
1573                               INT nItem, RECT *lprc)
1574 {
1575   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); 
1576   BOOL bSelected;
1577   INT nLabelWidth;
1578   INT nImage;
1579   CHAR szDispText[DISP_TEXT_SIZE];
1580   LPSTR pszDispText = NULL;
1581   UINT uState;
1582
1583   pszDispText = szDispText;
1584   LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, &nImage, &uState, &pszDispText,
1585                            DISP_TEXT_SIZE);
1586   if (uState & LVIS_SELECTED)
1587   {
1588     bSelected = TRUE;
1589
1590     /* set item colors */ 
1591     SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1592     SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1593     
1594     /* set raster mode */
1595     SetROP2(hdc, R2_XORPEN);
1596   }
1597   else
1598   {
1599     bSelected = FALSE;
1600
1601     /* set item colors */
1602     SetBkColor(hdc, infoPtr->clrTextBk);
1603     SetTextColor(hdc, infoPtr->clrText);
1604     
1605     /* set raster mode */
1606     SetROP2(hdc, R2_COPYPEN);
1607   }
1608
1609   /* state icons */
1610   if (infoPtr->himlState != NULL)
1611   {
1612     /* right shift 12 bits to obtain index in image list */
1613     if (bSelected == TRUE)
1614     {
1615       ImageList_Draw(infoPtr->himlState, uState >> 12, hdc, lprc->left, 
1616                      lprc->top, ILD_SELECTED);
1617     }
1618     else
1619     {
1620       ImageList_Draw(infoPtr->himlState, uState >> 12, hdc, lprc->left, 
1621                      lprc->top, ILD_NORMAL);
1622     }
1623     
1624     lprc->left += infoPtr->iconSize.cx; 
1625   }
1626   
1627   /* small icons */
1628   if (infoPtr->himlSmall != NULL)
1629   {
1630     if (bSelected == TRUE)
1631     {
1632       ImageList_Draw(infoPtr->himlSmall, nImage, hdc, lprc->left, 
1633                      lprc->top, ILD_SELECTED);
1634     }
1635     else
1636     {
1637       ImageList_Draw(infoPtr->himlSmall, nImage, hdc, lprc->left, 
1638                      lprc->top, ILD_NORMAL);
1639     }
1640     
1641     lprc->left += infoPtr->iconSize.cx; 
1642   }
1643
1644   nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText);
1645   if (lprc->left + nLabelWidth < lprc->right)
1646   {
1647     lprc->right = lprc->left + nLabelWidth;
1648   }
1649
1650   /* draw text */  
1651   ExtTextOutA(hdc, lprc->left + 1, lprc->top + 1, ETO_OPAQUE|ETO_CLIPPED, 
1652               lprc, pszDispText, lstrlenA(pszDispText), NULL);
1653         
1654   if (lpItem->state & LVIS_FOCUSED)
1655   {
1656     Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom); 
1657   }
1658 }
1659
1660 /***
1661  * DESCRIPTION:
1662  * Draws listview items when in report display mode.
1663  * 
1664  * PARAMETER(S):
1665  * [I] HWND : window handle
1666  * [I] HDC : device context handle 
1667  *
1668  * RETURN:
1669  * None
1670  */
1671 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
1672 {
1673   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
1674   INT nDrawPosY = infoPtr->rcList.top;
1675   LISTVIEW_ITEM *lpItem;
1676   LISTVIEW_SUBITEM *lpSubItem = NULL;
1677   INT nColumnCount;
1678   HDPA hdpaSubItems;
1679   RECT rc;
1680   INT  j, k;
1681   INT nItem;
1682   INT nLast;
1683   BOOL bNeedSubItem = TRUE;
1684
1685   nItem = ListView_GetTopIndex(hwnd);
1686   nLast = nItem + infoPtr->nCountPerColumn;
1687   while (nItem <= nLast)
1688   {
1689     hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
1690     if (hdpaSubItems != NULL)
1691     {
1692       lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
1693       if (lpItem != NULL)
1694       {
1695         Header_GetItemRect(infoPtr->hwndHeader, 0, &rc);
1696         rc.top = nDrawPosY;
1697         rc.bottom = rc.top + infoPtr->nItemHeight;
1698         
1699         /* draw state icon + icon + text */
1700         LISTVIEW_DrawItem(hwnd, hdc, lpItem, nItem, &rc);
1701       }
1702
1703       nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
1704       for (k = 1, j = 1; j < nColumnCount; j++)
1705       {
1706         Header_GetItemRect(infoPtr->hwndHeader, j, &rc);
1707         rc.top = nDrawPosY;
1708         rc.bottom = rc.top + infoPtr->nItemHeight;
1709
1710         if (k < hdpaSubItems->nItemCount)
1711         {
1712           if (bNeedSubItem == TRUE)
1713           {
1714             lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, k);
1715             k++;
1716           }
1717
1718           if (lpSubItem != NULL)
1719           {
1720             if (lpSubItem->iSubItem == j)
1721             {
1722               LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, lpSubItem,
1723                                    j, &rc);
1724               bNeedSubItem = TRUE;
1725             }
1726             else
1727             {
1728               LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j, 
1729                                    &rc);
1730               bNeedSubItem = FALSE;
1731             }
1732           }
1733           else
1734           {
1735             LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j, 
1736                                  &rc);
1737             bNeedSubItem = TRUE;
1738           }
1739         }
1740         else
1741         {
1742           LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j, &rc);
1743         }
1744       }
1745     }
1746
1747     nDrawPosY += infoPtr->nItemHeight;
1748     nItem++;
1749   }
1750 }
1751
1752 /***
1753  * DESCRIPTION:
1754  * Draws listview items when in list display mode.
1755  * 
1756  * PARAMETER(S):
1757  * [I] HWND : window handle
1758  * [I] HDC : device context handle 
1759  *
1760  * RETURN:
1761  * None
1762  */
1763 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
1764 {
1765   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1766   LISTVIEW_ITEM *lpItem;
1767   HDPA hdpaSubItems;
1768   RECT rc;
1769   INT i, j;
1770   INT nColumnCount;
1771   INT nItem = ListView_GetTopIndex(hwnd);
1772
1773   if (infoPtr->rcList.right > 0)
1774   {
1775     /* get number of display columns */
1776     if (infoPtr->rcList.right % infoPtr->nColumnWidth == 0)
1777     {
1778       nColumnCount = infoPtr->rcList.right / infoPtr->nColumnWidth;
1779     }
1780     else
1781     {
1782       nColumnCount = infoPtr->rcList.right / infoPtr->nColumnWidth + 1;
1783     }
1784
1785     for (i = 0; i < nColumnCount; i++)
1786     {
1787       j = 0;
1788       while ((nItem < GETITEMCOUNT(infoPtr)) && (j < infoPtr->nCountPerColumn))
1789       {
1790         hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
1791         if (hdpaSubItems != NULL)
1792         {
1793           lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
1794           if (lpItem != NULL)
1795           {
1796             rc.top = j * infoPtr->nItemHeight;
1797             rc.left = i * infoPtr->nColumnWidth;
1798             rc.bottom = rc.top + infoPtr->nItemHeight;
1799             rc.right = rc.left + infoPtr->nColumnWidth;
1800
1801             /* draw state icon + icon + text */
1802             LISTVIEW_DrawItem(hwnd, hdc,  lpItem, nItem, &rc);
1803           }
1804         }
1805  
1806         nItem++;
1807         j++;
1808       }
1809     }
1810   }
1811 }
1812
1813 /***
1814  * DESCRIPTION:
1815  * Draws listview items when in small icon display mode.
1816  * 
1817  * PARAMETER(S):
1818  * [I] HWND : window handle
1819  * [I] HDC : device context handle 
1820  *
1821  * RETURN:
1822  * None
1823  */
1824 static VOID LISTVIEW_RefreshSmallIcon(HWND hwnd, HDC hdc)
1825 {
1826   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1827   LISTVIEW_ITEM *lpItem;
1828   HDPA hdpaSubItems;
1829   RECT rc;
1830   INT i, j;
1831   INT nItem = ListView_GetTopIndex(hwnd);
1832
1833   for (i = 0; i < infoPtr->nCountPerColumn; i++)
1834   {
1835     j = 0;
1836     while ((nItem < GETITEMCOUNT(infoPtr)) && (j < infoPtr->nCountPerRow))
1837     {
1838       hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
1839       if (hdpaSubItems != NULL)
1840       {
1841         lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
1842         if (lpItem != NULL)
1843         {
1844           rc.top = i * infoPtr->nItemHeight;
1845           rc.left = j * infoPtr->nColumnWidth;
1846           rc.bottom = rc.top + infoPtr->nItemHeight;
1847           rc.right = rc.left + infoPtr->nColumnWidth;
1848
1849           /* draw state icon + icon + text */
1850           LISTVIEW_DrawItem(hwnd, hdc,  lpItem, nItem, &rc);
1851         }
1852       }
1853  
1854       nItem++;
1855       j++;
1856     }
1857   }
1858 }
1859
1860 /***
1861  * DESCRIPTION:
1862  * Draws listview items when in icon display mode.
1863  * 
1864  * PARAMETER(S):
1865  * [I] HWND : window handle
1866  * [I] HDC : device context handle 
1867  *
1868  * RETURN:
1869  * None
1870  */
1871 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc)
1872 {
1873   /* TO DO */
1874 }
1875
1876 /***
1877  * DESCRIPTION:
1878  * Draws listview items.
1879  * 
1880  * PARAMETER(S):
1881  * [I] HWND : window handle
1882  * [I] HDC : device context handle 
1883  *
1884  * RETURN:
1885  * NoneX
1886  */
1887 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
1888 {
1889   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1890   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1891   HFONT hOldFont;
1892   HPEN hPen, hOldPen;
1893
1894   /* select font */
1895   hOldFont = SelectObject(hdc, infoPtr->hFont);
1896
1897   /* select the doted pen (for drawing the focus box) */
1898   hPen = CreatePen(PS_DOT, 1, 0);
1899   hOldPen = SelectObject(hdc, hPen);
1900
1901   /* select transparent brush (for drawing the focus box) */
1902   SelectObject(hdc, GetStockObject(NULL_BRUSH)); 
1903
1904   switch (LVS_TYPEMASK & lStyle)
1905   {
1906   case LVS_LIST:
1907     LISTVIEW_RefreshList(hwnd, hdc); 
1908     break;
1909   case LVS_REPORT:
1910     LISTVIEW_RefreshReport(hwnd, hdc);
1911     break;
1912   case LVS_SMALLICON:
1913     LISTVIEW_RefreshSmallIcon(hwnd, hdc);
1914     break;
1915   case LVS_ICON:
1916     LISTVIEW_RefreshIcon(hwnd, hdc);
1917   }
1918
1919   /* unselect objects */
1920   SelectObject(hdc, hOldFont);
1921   SelectObject(hdc, hOldPen);
1922   
1923   /* delete pen */
1924   DeleteObject(hPen);
1925 }
1926
1927
1928 /***
1929  * DESCRIPTION:
1930  * Calculates the approximate width and height of a given number of items.
1931  * 
1932  * PARAMETER(S):
1933  * [I] HWND : window handle
1934  * [I] INT : number of items
1935  * [I] INT : width
1936  * [I] INT : height
1937  *
1938  * RETURN:
1939  * Returns a DWORD. The width in the low word and the height in high word.
1940  */
1941 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount, 
1942                                             WORD wWidth, WORD wHeight)
1943 {
1944   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1945   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1946   INT nItemCountPerColumn = 1;
1947   INT nColumnCount = 0;
1948   DWORD dwViewRect = 0;
1949
1950   if (nItemCount == -1)
1951     nItemCount = GETITEMCOUNT(infoPtr);
1952
1953   if (lStyle & LVS_LIST)
1954   {
1955     if (wHeight == 0xFFFF)
1956     {
1957       /* use current height */
1958       wHeight = infoPtr->rcList.bottom;
1959     }
1960
1961     if (wHeight < infoPtr->nItemHeight)
1962     {
1963       wHeight = infoPtr->nItemHeight;
1964     }
1965
1966     if (nItemCount > 0)
1967     {
1968       if (infoPtr->nItemHeight > 0)
1969       {
1970         nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
1971         if (nItemCountPerColumn == 0)
1972           nItemCountPerColumn = 1;
1973
1974         if (nItemCount % nItemCountPerColumn != 0)
1975           nColumnCount = nItemCount / nItemCountPerColumn;
1976         else
1977           nColumnCount = nItemCount / nItemCountPerColumn + 1;
1978       }
1979     }
1980
1981     /* Microsoft padding magic */
1982     wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
1983     wWidth = nColumnCount * infoPtr->nColumnWidth + 2;
1984
1985     dwViewRect = MAKELONG(wWidth, wHeight);
1986   }
1987   else if (lStyle & LVS_REPORT)
1988   {
1989     /* TO DO */
1990     }
1991   else if (lStyle & LVS_SMALLICON)
1992   {
1993     /* TO DO */
1994   }
1995   else if (lStyle & LVS_ICON)
1996   {
1997     /* TO DO */
1998   }
1999  
2000   return dwViewRect;
2001 }
2002
2003 /***
2004  * DESCRIPTION:
2005  * Arranges listview items in icon display mode.
2006  * 
2007  * PARAMETER(S):
2008  * [I] HWND : window handle
2009  * [I] INT : alignment code
2010  *
2011  * RETURN:
2012  *   SUCCESS : TRUE
2013  *   FAILURE : FALSE
2014  */
2015 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2016 {
2017   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2018   BOOL bResult = FALSE;
2019
2020   if (((LVS_TYPEMASK & lStyle) == LVS_ICON) || 
2021       ((LVS_TYPEMASK & lStyle) == LVS_SMALLICON))
2022   {
2023     switch (nAlignCode)
2024     {
2025     case LVA_ALIGNLEFT:
2026       /* TO DO */
2027       break;
2028     case LVA_ALIGNTOP:
2029       /* TO DO */
2030       break;
2031     case LVA_DEFAULT:
2032       /* TO DO */
2033       break;
2034     case LVA_SNAPTOGRID:
2035       /* TO DO */
2036     }
2037   }
2038
2039   return bResult;
2040 }
2041
2042 /* << LISTVIEW_CreateDragImage >> */
2043
2044 /***
2045  * DESCRIPTION:
2046  * Removes all listview items and subitems.
2047  * 
2048  * PARAMETER(S):
2049  * [I] HWND : window handle
2050  *
2051  * RETURN:
2052  *   SUCCESS : TRUE
2053  *   FAILURE : FALSE
2054  */
2055 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2056 {
2057   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2058   LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2059   LISTVIEW_ITEM *lpItem;
2060   LISTVIEW_SUBITEM *lpSubItem;
2061   NMLISTVIEW nmlv;
2062   BOOL bSuppress;
2063   BOOL bResult = FALSE;
2064   INT i;
2065   INT j;
2066   HDPA hdpaSubItems;
2067
2068   if (GETITEMCOUNT(infoPtr) > 0)
2069   {
2070     /* initialize memory */
2071     ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2072     
2073     /* send LVN_DELETEALLITEMS notification */
2074     nmlv.hdr.hwndFrom = hwnd;
2075     nmlv.hdr.idFrom = lCtrlId;
2076     nmlv.hdr.code = LVN_DELETEALLITEMS;
2077     nmlv.iItem = -1;
2078
2079     /* verify if subsequent LVN_DELETEITEM notifications should be 
2080        suppressed */
2081     bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2082
2083     for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2084     {
2085       hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2086       if (hdpaSubItems != NULL)
2087       {
2088         for (j = 1; j < hdpaSubItems->nItemCount; j++)
2089         {
2090           lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2091           if (lpSubItem != NULL)
2092           {
2093             /* free subitem string */
2094             if ((lpSubItem->pszText != NULL) && 
2095                 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2096             {
2097               COMCTL32_Free(lpSubItem->pszText);
2098             }
2099             
2100             /* free subitem */
2101             COMCTL32_Free(lpSubItem);
2102           }    
2103         }
2104     
2105         lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2106         if (lpItem != NULL)
2107         {
2108           if (bSuppress == FALSE)
2109           {
2110             /* send LVN_DELETEITEM notification */
2111             nmlv.hdr.code = LVN_DELETEITEM;
2112             nmlv.iItem = i;
2113             nmlv.lParam = lpItem->lParam;
2114             ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2115           }
2116
2117           /* free item string */
2118           if ((lpItem->pszText != NULL) && 
2119               (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2120           {
2121             COMCTL32_Free(lpItem->pszText);
2122           }
2123           
2124           /* free item */
2125           COMCTL32_Free(lpItem);
2126         }
2127         
2128         DPA_Destroy(hdpaSubItems);
2129       }
2130     }
2131
2132     /* reinitialize listview memory */
2133     bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2134     
2135     /* reset scroll parameters */
2136     LISTVIEW_SetScroll(hwnd);
2137
2138     /* invalidate client area (optimization needed) */
2139     InvalidateRect(hwnd, NULL, FALSE);
2140   }
2141   
2142   return bResult;
2143 }
2144
2145 /***
2146  * DESCRIPTION:
2147  * Removes a column from the listview control.
2148  * 
2149  * PARAMETER(S):
2150  * [I] HWND : window handle
2151  * [I] INT : column index
2152  *
2153  * RETURN:
2154  *   SUCCESS : TRUE
2155  *   FAILURE : FALSE
2156  */
2157 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2158 {
2159   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2160   BOOL bResult = FALSE;
2161   
2162   if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) == TRUE)
2163   {
2164     bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2165   }
2166
2167   /* reset scroll parameters */
2168   LISTVIEW_SetScroll(hwnd);
2169
2170   /* refresh client area */
2171   InvalidateRect(hwnd, NULL, FALSE);
2172
2173   return bResult;
2174 }
2175
2176 /***
2177  * DESCRIPTION:
2178  * Removes an item from the listview control.
2179  * 
2180  * PARAMETER(S):
2181  * [I] HWND : window handle
2182  * [I] INT : item index  
2183  *
2184  * RETURN:
2185  *   SUCCESS : TRUE
2186  *   FAILURE : FALSE
2187  */
2188 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2189 {
2190   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2191   LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2192   NMLISTVIEW nmlv;
2193   BOOL bResult = FALSE;
2194   HDPA hdpaSubItems;
2195   LISTVIEW_ITEM *lpItem;
2196   LISTVIEW_SUBITEM *lpSubItem;
2197   INT i;
2198
2199   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2200   {
2201     /* initialize memory */
2202     ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2203
2204     hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2205     if (hdpaSubItems != NULL)
2206     {
2207       for (i = 1; i < hdpaSubItems->nItemCount; i++)
2208       {
2209         lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2210         if (lpSubItem != NULL)
2211         {
2212           /* free item string */
2213           if ((lpSubItem->pszText != NULL) && 
2214               (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2215           {
2216             COMCTL32_Free(lpSubItem->pszText);
2217           }
2218           
2219           /* free item */
2220           COMCTL32_Free(lpSubItem);
2221         }    
2222       }
2223     
2224       lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2225       if (lpItem != NULL)
2226       {
2227         /* send LVN_DELETEITEM notification */
2228         nmlv.hdr.hwndFrom = hwnd;
2229         nmlv.hdr.idFrom = lCtrlId;
2230         nmlv.hdr.code = LVN_DELETEITEM;
2231         nmlv.iItem = nItem;
2232         nmlv.lParam = lpItem->lParam;
2233         SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, 
2234                      (LPARAM)&nmlv);
2235
2236         /* free item string */
2237         if ((lpItem->pszText != NULL) && 
2238             (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2239         {
2240           COMCTL32_Free(lpItem->pszText);
2241         }
2242         
2243         /* free item */
2244         COMCTL32_Free(lpItem);
2245       }
2246       
2247       bResult = DPA_Destroy(hdpaSubItems);
2248     }
2249
2250     /* refresh client area */
2251     InvalidateRect(hwnd, NULL, FALSE);
2252   }
2253   
2254   return bResult;
2255 }
2256
2257 /* << LISTVIEW_EditLabel >> */
2258
2259 /***
2260  * DESCRIPTION:
2261  * Ensures the specified item is visible, scrolling into view if necessary.
2262  * 
2263  * PARAMETER(S):
2264  * [I] HWND : window handle
2265  * [I] INT : item index
2266  * [I] BOOL : partially or entirely visible
2267  *
2268  * RETURN:
2269  *   SUCCESS : TRUE
2270  *   FAILURE : FALSE
2271  */
2272 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2273 {
2274   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2275   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2276   INT nLast;
2277   INT nFirst;
2278   INT nScrollPos;
2279   BOOL bResult = TRUE;
2280
2281   switch (LVS_TYPEMASK & lStyle)
2282   {
2283   case LVS_LIST:
2284     if (lStyle & WS_HSCROLL)
2285     {
2286       nFirst = ListView_GetTopIndex(hwnd);
2287
2288       /* calculate last fully visible item index */
2289       nLast = infoPtr->nCountPerColumn * infoPtr->nCountPerRow + nFirst - 1;
2290
2291       if (nItem > nLast)
2292       {
2293         /* calculate new scroll position based on item index */
2294         if (((nItem - nLast) % infoPtr->nCountPerColumn) == 0)
2295         {
2296           nScrollPos = (nItem - nLast) / infoPtr->nCountPerColumn;
2297         }
2298         else
2299         {
2300           nScrollPos = (nItem - nLast) / infoPtr->nCountPerColumn + 1;
2301         }
2302
2303         bResult = ListView_Scroll(hwnd, nScrollPos, 0);
2304       }
2305       else if (nItem < nFirst)
2306       {
2307         /* calculate new scroll position based on item index */
2308         if (((nItem - nFirst) % infoPtr->nCountPerColumn) == 0)
2309         {
2310           nScrollPos = (nItem - nFirst) / infoPtr->nCountPerColumn;
2311         }
2312         else
2313         {
2314           nScrollPos = (nItem - nFirst) / infoPtr->nCountPerColumn -1;
2315         }
2316
2317         bResult = ListView_Scroll(hwnd, nScrollPos, 0);
2318       }
2319     }
2320     break;
2321
2322   case LVS_REPORT:
2323     if (lStyle & WS_VSCROLL)
2324     {
2325       nFirst = ListView_GetTopIndex(hwnd);
2326
2327       /* calculate last fully visible item index */
2328       nLast = infoPtr->nCountPerColumn + nFirst - 1;
2329       if (nItem > nLast)
2330       {
2331         nScrollPos = nItem - nLast;
2332         bResult = ListView_Scroll(hwnd, 0, nScrollPos);
2333       }
2334       else if (nItem < nFirst)
2335       {
2336         nScrollPos = nItem - nFirst;
2337         bResult = ListView_Scroll(hwnd, 0, nScrollPos);
2338       }
2339     }
2340     break;
2341
2342   case LVS_SMALLICON:
2343     /* TO DO */
2344     break;
2345
2346   case LVS_ICON:
2347     /* TO DO */
2348     break;
2349   }
2350
2351   return bResult;
2352 }
2353 /***
2354  * DESCRIPTION:
2355  * Searches for an item with specific characteristics.
2356  * 
2357  * PARAMETER(S):
2358  * [I] HWND : window handle
2359  * [I] INT : base item index
2360  * [I] LPLVFINDINFO : item information to look for
2361  * 
2362  * RETURN:
2363  *   SUCCESS : index of item
2364  *   FAILURE : -1
2365  */
2366 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart, 
2367                                  LPLVFINDINFO lpFindInfo)
2368 {
2369 /*   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
2370 /*   LISTVIEW_ITEM *lpItem; */
2371 /*   INT nItem; */
2372 /*   INT nEnd = GETITEMCOUNT(infoPtr); */
2373 /*   BOOL bWrap = FALSE; */
2374 /*   if (nStart == -1) */
2375 /*     nStart = 0; */
2376 /*   else */
2377 /*     nStart++ ; */
2378 /*   if (lpFindInfo->flags & LVFI_PARAM) */
2379 /*   { */
2380 /*     for (nItem = nStart; nItem < nEnd; nItem++) */
2381 /*     { */
2382        /* get item pointer */ 
2383 /*       lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
2384 /*       if (lpItem != NULL)  */
2385 /*       { */
2386 /*         if (lpFindInfo->lParam == lpItem->lParam) */
2387 /*           return nItem; */
2388 /*       } */
2389 /*     } */
2390 /*   } */
2391 /*   else */
2392 /*   { */
2393 /*     if (lpFindInfo->flags & LVFI_PARTIAL) */
2394 /*     { */
2395 /*       for (nItem = nStart; nItem < nEnd; nItem++) */
2396 /*       { */
2397          /* get item pointer */
2398 /*         lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
2399 /*         if (lpItem)  */
2400 /*         { */
2401 /*           if (strncmp(lpItem->pszText, lpFindInfo->psz, strlen(lpFindInfo->psz))  */
2402 /*               == 0) */
2403 /*             return nItem; */
2404 /*         } */
2405 /*       } */
2406 /*     } */
2407
2408 /*     if (lpFindInfo->flags & LVFI_STRING) */
2409 /*     { */
2410 /*       for (nItem = nStart; nItem < nEnd; nItem++) */
2411 /*       { */
2412          /* get item pointer */
2413 /*         lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
2414 /*         if (lpItem != NULL)  */
2415 /*         { */
2416 /*           if (strcmp(lpItem->pszText, lpFindInfo->psz) == 0) */
2417 /*             return nItem; */
2418 /*         } */
2419 /*       } */
2420 /*     } */
2421     
2422 /*     if ((lpFindInfo->flags & LVFI_WRAP) && nStart)  */
2423 /*     { */
2424 /*       nEnd = nStart; */
2425 /*       nStart = 0; */
2426 /*       bWrap = TRUE; */
2427 /*     } */
2428 /*     else */
2429 /*       bWrap = FALSE; */
2430
2431    return -1; 
2432 }
2433
2434 /***
2435  * DESCRIPTION:
2436  * Retrieves the background color of the listview control.
2437  * 
2438  * PARAMETER(S):
2439  * [I] HWND : window handle
2440  *
2441  * RETURN:
2442  * COLORREF associated with the background.
2443  */
2444 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
2445 {
2446   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2447
2448   return infoPtr->clrBk;
2449 }
2450
2451 /***
2452  * DESCRIPTION:
2453  * Retrieves the background image of the listview control.
2454  * 
2455  * PARAMETER(S):
2456  * [I] HWND : window handle
2457  * [O] LPLVMKBIMAGE : background image attributes
2458  *
2459  * RETURN:
2460  *   SUCCESS : TRUE
2461  *   FAILURE : FALSE`
2462  */
2463 /*  static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage)  */
2464 /*  {  */
2465 /*    return FALSE;  */
2466 /*  }  */
2467
2468 /***
2469  * DESCRIPTION:
2470  * Retrieves the callback mask.
2471  * 
2472  * PARAMETER(S):
2473  * [I] HWND : window handle
2474  *
2475  * RETURN:
2476  *  Value of mask
2477  */
2478 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
2479 {
2480   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2481
2482   return infoPtr->uCallbackMask;
2483 }
2484
2485 /***
2486  * DESCRIPTION:
2487  * Retrieves column attributes.
2488  * 
2489  * PARAMETER(S):
2490  * [I] HWND : window handle
2491  * [I] INT :  column index
2492  * [IO] LPLVCOLUMNA : column information
2493  *
2494  * RETURN:
2495  *   SUCCESS : TRUE
2496  *   FAILURE : FALSE
2497  */
2498 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, 
2499                                      LPLVCOLUMNA lpColumn)
2500 {
2501   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2502   HDITEMA hdi;
2503   BOOL bResult = FALSE;
2504
2505   if (lpColumn != NULL)
2506   {
2507     /* initialize memory */
2508     ZeroMemory(&hdi, sizeof(HDITEMA));
2509     
2510     if (lpColumn->mask & LVCF_FMT)
2511     {
2512       hdi.mask |= HDI_FORMAT;
2513     }
2514
2515     if (lpColumn->mask & LVCF_WIDTH)
2516     {
2517       hdi.mask |= HDI_WIDTH;
2518     }
2519
2520     if (lpColumn->mask & LVCF_TEXT)
2521     {
2522       hdi.mask |= (HDI_TEXT | HDI_FORMAT);
2523     }
2524
2525     if (lpColumn->mask & LVCF_IMAGE)
2526     {
2527       hdi.mask |= HDI_IMAGE;
2528     }
2529
2530     if (lpColumn->mask & LVCF_ORDER)
2531     {
2532       hdi.mask |= HDI_ORDER;
2533     }
2534
2535     bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
2536     if (bResult == TRUE)
2537     {
2538       if (lpColumn->mask & LVCF_FMT) 
2539       {
2540         lpColumn->fmt = 0;
2541
2542         if (hdi.fmt & HDF_LEFT)
2543         {
2544           lpColumn->fmt |= LVCFMT_LEFT;
2545         }
2546         else if (hdi.fmt & HDF_RIGHT)
2547         {
2548           lpColumn->fmt |= LVCFMT_RIGHT;
2549         }
2550         else if (hdi.fmt & HDF_CENTER)
2551         {
2552           lpColumn->fmt |= LVCFMT_CENTER;
2553         }
2554
2555         if (hdi.fmt & HDF_IMAGE)
2556         {
2557           lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
2558         }
2559       }
2560
2561       if (lpColumn->mask & LVCF_WIDTH)
2562       {
2563         lpColumn->cx = hdi.cxy;
2564       }
2565       
2566       if ((lpColumn->mask & LVCF_TEXT) && (lpColumn->pszText) && (hdi.pszText))
2567       {
2568         lstrcpynA (lpColumn->pszText, hdi.pszText, lpColumn->cchTextMax);
2569       }
2570
2571       if (lpColumn->mask & LVCF_IMAGE)
2572       {
2573         lpColumn->iImage = hdi.iImage;
2574       }
2575
2576       if (lpColumn->mask & LVCF_ORDER)
2577       {
2578         lpColumn->iOrder = hdi.iOrder;
2579       }
2580     }
2581   }
2582
2583   return bResult;
2584 }
2585
2586 /* << LISTVIEW_GetColumnW >> */
2587 /* << LISTVIEW_GetColumnOrderArray >> */
2588
2589 /***
2590  * DESCRIPTION:
2591  * Retrieves the column width.
2592  * 
2593  * PARAMETER(S):
2594  * [I] HWND : window handle
2595  * [I] int : column index
2596  *
2597  * RETURN:
2598  *   SUCCESS : column width
2599  *   FAILURE : zero 
2600  */
2601 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
2602 {
2603   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2604   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2605   HDITEMA hdi;
2606   INT nColumnWidth = 0;
2607
2608   if ((LVS_TYPEMASK & lStyle) ==  LVS_LIST)
2609   {
2610     nColumnWidth = infoPtr->nColumnWidth;
2611   }
2612   else if ((LVS_TYPEMASK & lStyle) ==  LVS_REPORT)
2613   {
2614     /* get column width from header */
2615     ZeroMemory(&hdi, sizeof(HDITEMA));
2616     hdi.mask = HDI_WIDTH;
2617     if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) == TRUE)
2618     {
2619       nColumnWidth = hdi.cxy;
2620     }
2621   }
2622
2623   return nColumnWidth;
2624 }
2625
2626 /***
2627  * DESCRIPTION:
2628  * In list or report display mode, retrieves the number of items that can fit 
2629  * vertically in the visible area. In icon or small icon display mode, 
2630  * retrieves the total number of visible items.
2631  * 
2632  * PARAMETER(S):
2633  * [I] HWND : window handle
2634  *
2635  * RETURN:
2636  * Number of fully visible items.
2637  */
2638 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
2639 {
2640   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2641   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2642   INT nItemCount = 0;
2643
2644   switch (LVS_TYPEMASK & lStyle)
2645   {
2646   case LVS_LIST:
2647     if (infoPtr->rcList.right / infoPtr->nColumnWidth)
2648     {
2649       nItemCount = infoPtr->nCountPerRow * infoPtr->nCountPerColumn;
2650     }
2651     break;
2652   
2653   case LVS_REPORT:
2654     nItemCount = infoPtr->nCountPerColumn;
2655     break;
2656
2657   default:
2658     nItemCount = GETITEMCOUNT(infoPtr);
2659   }
2660
2661   return nItemCount;
2662 }
2663
2664 /* << LISTVIEW_GetEditControl >> */
2665 /* << LISTVIEW_GetExtendedListViewStyle >> */
2666
2667 /***
2668  * DESCRIPTION:
2669  * Retrieves a header handle.
2670  * 
2671  * PARAMETER(S):
2672  * [I] HWND : window handle
2673  *
2674  * RETURN:
2675  * Header handle.
2676  */
2677 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
2678 {
2679   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2680
2681   return infoPtr->hwndHeader;
2682 }
2683
2684 /* << LISTVIEW_GetHotCursor >> */
2685 /* << LISTVIEW_GetHotItem >> */
2686 /* << LISTVIEW_GetHoverTime >> */
2687
2688 /***
2689  * DESCRIPTION:
2690  * Retrieves an image list handle.
2691  * 
2692  * PARAMETER(S):
2693  * [I] HWND : window handle
2694  * [I] INT : image list identifier 
2695  * 
2696  * RETURN:
2697  *   SUCCESS : image list handle
2698  *   FAILURE : NULL
2699  */
2700 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
2701 {
2702   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2703   HIMAGELIST himl = NULL;
2704
2705   switch (nImageList) 
2706   {
2707   case LVSIL_NORMAL:
2708     himl = infoPtr->himlNormal;
2709     break;
2710   case LVSIL_SMALL:
2711     himl = infoPtr->himlSmall;
2712     break;
2713   case LVSIL_STATE:
2714     himl = infoPtr->himlState;
2715     break;
2716   }
2717
2718   return (LRESULT)himl;
2719 }
2720
2721 /* << LISTVIEW_GetISearchString >> */
2722
2723 /***
2724  * DESCRIPTION:
2725  * Retrieves item attributes.
2726  * 
2727  * PARAMETER(S):
2728  * [I] HWND : window handle
2729  * [IO] LPLVITEMA : item info
2730  * 
2731  * RETURN:
2732  *   SUCCESS : TRUE 
2733  *   FAILURE : FALSE
2734  */
2735 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem)
2736 {
2737   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2738   LISTVIEW_ITEM *lpItem;
2739   LISTVIEW_SUBITEM *lpSubItem;
2740   HDPA hdpaSubItems;
2741   BOOL bResult = FALSE;
2742
2743   if (lpLVItem != NULL)
2744   {
2745     if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
2746     {
2747       hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
2748       if (hdpaSubItems != NULL)
2749       {
2750         if (lpLVItem->iSubItem == 0)
2751         {
2752           lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2753           if (lpItem != NULL)
2754           {
2755             bResult = TRUE;
2756
2757             /* retrieve valid data */
2758             if (lpLVItem->mask & LVIF_STATE)
2759             {
2760               lpLVItem->state = lpItem->state & lpLVItem->stateMask;
2761             }
2762
2763             if (lpLVItem->mask & LVIF_TEXT) 
2764             {
2765               if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
2766               {
2767                 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
2768               }
2769               else
2770               {
2771                 bResult = Str_GetPtrA(lpItem->pszText, lpLVItem->pszText, 
2772                                         lpLVItem->cchTextMax);
2773               }
2774             }
2775
2776             if (lpLVItem->mask & LVIF_IMAGE)
2777             {
2778               lpLVItem->iImage = lpItem->iImage;
2779             }
2780           
2781             if (lpLVItem->mask & LVIF_PARAM)
2782             {
2783               lpLVItem->lParam = lpItem->lParam;
2784             }
2785       
2786             if (lpLVItem->mask & LVIF_INDENT)
2787             {
2788               lpLVItem->iIndent = lpItem->iIndent;
2789             }
2790           }
2791         }
2792         else
2793         {
2794           lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, 
2795                                                      lpLVItem->iSubItem);
2796           if (lpSubItem != NULL)
2797           {
2798             bResult = TRUE;
2799
2800             if (lpLVItem->mask & LVIF_TEXT) 
2801             {
2802               if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
2803               {
2804                 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
2805               }
2806               else
2807               {
2808                 bResult = Str_GetPtrA(lpSubItem->pszText, lpLVItem->pszText, 
2809                                         lpLVItem->cchTextMax);
2810               }
2811             }
2812
2813             if (lpLVItem->mask & LVIF_IMAGE)
2814             {
2815               lpLVItem->iImage = lpSubItem->iImage;
2816             }
2817           }
2818         }
2819       }
2820     }
2821   }
2822
2823   return bResult;
2824 }
2825
2826 /* << LISTVIEW_GetItemW >> */
2827 /* << LISTVIEW_GetHotCursor >> */
2828 /* << LISTVIEW_GetHotItem >> */
2829 /* << LISTVIEW_GetHoverTime >> */
2830
2831 /***
2832  * DESCRIPTION:
2833  * Retrieves the number of items in the listview control.
2834  * 
2835  * PARAMETER(S):
2836  * [I] HWND : window handle
2837  * 
2838  * RETURN:
2839  * Number of items.
2840  */
2841 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
2842 {
2843   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2844
2845   return GETITEMCOUNT(infoPtr);
2846 }
2847
2848 /***
2849  * DESCRIPTION:
2850  * Retrieves the position (upper-left) of the listview control item.
2851  * 
2852  * PARAMETER(S):
2853  * [I] HWND : window handle
2854  * [I] INT : item index
2855  * [O] LPPOINT : coordinate information
2856  *
2857  * RETURN:
2858  *   SUCCESS : TRUE
2859  *   FAILURE : FALSE
2860  */
2861 static LRESULT LISTVIEW_GetItemPosition(HWND hwnd, INT nItem, 
2862                                         LPPOINT lppt)
2863 {
2864   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2865   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2866   INT nColumn;
2867   INT nRow;
2868   BOOL bResult = FALSE;
2869   INT nFirst;
2870   INT nLast;
2871
2872   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lppt != NULL))
2873   {
2874     switch (LVS_TYPEMASK & lStyle)
2875     {
2876     case LVS_LIST:
2877       nFirst = ListView_GetTopIndex(hwnd);
2878       nLast = infoPtr->nCountPerColumn * infoPtr->nCountPerRow + nFirst - 1;
2879
2880       if ((nItem >= nFirst) || (nItem <= nLast))
2881       {
2882         nItem -= nFirst; 
2883        
2884         /* get column */
2885         nColumn = nItem / infoPtr->nCountPerColumn;
2886
2887         /* get row */
2888         nRow = nItem % infoPtr->nCountPerColumn;
2889           
2890         /* X coordinate of the column */
2891         lppt->x = nColumn * infoPtr->nColumnWidth + infoPtr->rcList.left;
2892
2893         /* Y coordinate of the item */
2894         lppt->y = nRow * infoPtr->nItemHeight + infoPtr->rcList.top;
2895           
2896         bResult = TRUE;
2897       }
2898       break;
2899
2900     case LVS_REPORT:
2901       nFirst = ListView_GetTopIndex(hwnd);
2902       nLast = infoPtr->nCountPerColumn * infoPtr->nCountPerRow + nFirst - 1;
2903
2904       /* get column */
2905       nColumn = nItem / infoPtr->nCountPerColumn;
2906       
2907       /* get row */
2908       nRow = nItem % infoPtr->nCountPerColumn;
2909
2910       if ((nItem >= nFirst) || (nItem <= nLast))
2911       {
2912         nItem -= nFirst; 
2913    
2914         /* get column */
2915         nColumn = nItem / infoPtr->nCountPerColumn;
2916
2917         /* get row */
2918         nRow = nItem % infoPtr->nCountPerColumn;
2919
2920         /* X coordinate of the column */
2921         lppt->x = infoPtr->rcList.left;
2922
2923         /* Y coordinate of the item */
2924         lppt->y = nRow * infoPtr->nItemHeight + infoPtr->rcList.top;
2925           
2926         bResult = TRUE;
2927       }        
2928
2929     default:
2930       /* TO DO */
2931     }
2932   }
2933     
2934   return bResult;
2935 }
2936
2937 /***
2938  * DESCRIPTION:
2939  * Retrieves the bounding rectangle for a listview control item.
2940  * 
2941  * PARAMETER(S):
2942  * [I] HWND : window handle
2943  * [I] INT : item index
2944  * [IO] LPRECT : bounding rectangle coordinates
2945  * 
2946  * RETURN:
2947  *   SUCCESS : TRUE
2948  *   FAILURE : FALSE
2949  */
2950 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
2951 {
2952   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2953   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2954   LISTVIEW_ITEM *lpItem;
2955   HDPA hdpaSubItems;
2956   INT nLabelWidth = 0;
2957   INT nStateWidth = 0;
2958   INT nIconWidth = 0;
2959   BOOL bResult = FALSE;
2960   CHAR szDispText[DISP_TEXT_SIZE];
2961   LPSTR pszDispText;
2962   POINT pt;
2963
2964   /*init pointer */
2965   pszDispText = szDispText;
2966
2967   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
2968   {
2969     hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
2970     if (hdpaSubItems != NULL)
2971     {
2972       lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2973       if (lpItem != NULL)
2974       {
2975         if ((LVS_TYPEMASK & lStyle) == LVS_ICON)
2976         {
2977
2978         }
2979         else
2980         {
2981           if (ListView_GetItemPosition(hwnd, nItem, &pt) == TRUE)
2982           {
2983             /* get width of label in pixels */
2984             LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, NULL, NULL, 
2985                                      &pszDispText, DISP_TEXT_SIZE);
2986             nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText); 
2987           }
2988
2989           if (infoPtr->himlState != NULL)
2990           {
2991             nStateWidth = infoPtr->iconSize.cx;
2992           }
2993
2994           if (infoPtr->himlSmall == NULL)
2995           {
2996             nIconWidth = infoPtr->iconSize.cx;
2997           }
2998
2999           switch(lprc->left)  
3000           {  
3001           case LVIR_BOUNDS:  
3002             lprc->left = pt.x;
3003             lprc->top = pt.y;
3004             lprc->right = lprc->left + nStateWidth + nIconWidth + nLabelWidth;
3005             lprc->bottom = lprc->top + infoPtr->nItemHeight;
3006             bResult = TRUE;
3007             break;
3008           case LVIR_ICON:
3009             lprc->left = pt.x + nStateWidth;
3010             lprc->top = pt.y;
3011             lprc->right = lprc->left + nIconWidth;
3012             lprc->bottom = lprc->top + infoPtr->nItemHeight;
3013             bResult = TRUE;
3014             break;
3015           case LVIR_LABEL: 
3016             lprc->left = pt.x + nIconWidth + nStateWidth;
3017             lprc->top = pt.y;
3018             lprc->right = lprc->left + nLabelWidth;
3019             lprc->bottom = infoPtr->nItemHeight;
3020             bResult = TRUE;
3021             break;
3022           case LVIR_SELECTBOUNDS:
3023             lprc->left = pt.x + nStateWidth;
3024             lprc->top = pt.y;
3025             lprc->right = lprc->left + nIconWidth + nLabelWidth;
3026             lprc->bottom = lprc->top + infoPtr->nItemHeight;
3027             bResult = TRUE;
3028           }
3029         }
3030       }
3031     }
3032   }
3033         
3034   return bResult;
3035 }
3036
3037 /***
3038  * DESCRIPTION:
3039  * Retrieves the spacing between listview control items.
3040  * 
3041  * PARAMETER(S):
3042  * [I] HWND : window handle
3043  * [I] BOOL : flag for small or large icon 
3044  *
3045  * RETURN:
3046  * Horizontal + vertical spacing
3047  */
3048 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
3049 {
3050   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3051   LONG lResult;
3052
3053   if (bSmall == TRUE)
3054   {
3055     lResult = MAKELONG(infoPtr->largeIconSpacing.cx, 
3056                        infoPtr->largeIconSpacing.cy);
3057   }
3058   else
3059   {
3060     lResult = MAKELONG(infoPtr->smallIconSpacing.cx, 
3061                        infoPtr->smallIconSpacing.cy);
3062   }
3063
3064   return lResult;
3065 }
3066
3067 /***
3068  * DESCRIPTION:
3069  * Retrieves the state of a listview control item.
3070  * 
3071  * PARAMETER(S):
3072  * [I] HWND : window handle
3073  * [I] INT : item index
3074  * [I] UINT : state mask
3075  * 
3076  * RETURN:
3077  * State specified by the mask.
3078  */
3079 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
3080 {
3081   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3082   LVITEMA lvItem;
3083   UINT uState = 0;
3084
3085   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3086   {
3087     ZeroMemory(&lvItem, sizeof(LVITEMA));
3088     lvItem.iItem = nItem;
3089     lvItem.stateMask = uMask;
3090     lvItem.mask = LVIF_STATE;
3091     if (ListView_GetItemA(hwnd, &lvItem) == TRUE)
3092     {
3093       uState = lvItem.state;
3094     }
3095   }
3096
3097   return uState;
3098 }
3099
3100 /***
3101  * DESCRIPTION:
3102  * Retrieves the text of a listview control item or subitem. 
3103  * 
3104  * PARAMETER(S):
3105  * [I] HWND : window handle
3106  * [I] INT : item index
3107  * [IO] LPLVITEMA : item information
3108  * 
3109  * RETURN:
3110  * None
3111  */
3112 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, 
3113                                        LPLVITEMA lpLVItem)
3114 {
3115   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3116   LISTVIEW_ITEM *lpItem;
3117   LISTVIEW_SUBITEM *lpSubItem;
3118   HDPA hdpaSubItems;
3119   INT nLength = 0;
3120   
3121   if (lpLVItem != NULL)
3122   {
3123     if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3124     {
3125       hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3126       if (hdpaSubItems != NULL)
3127       {
3128         if (lpLVItem->iSubItem == 0)
3129         {
3130           lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3131           if (lpItem != NULL)
3132           {
3133             if (lpLVItem->mask & LVIF_TEXT) 
3134             {
3135               if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
3136               {
3137                 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
3138               }
3139               else
3140               {
3141                 nLength = Str_GetPtrA(lpItem->pszText, lpLVItem->pszText, 
3142                                         lpLVItem->cchTextMax);
3143               }
3144             }
3145           }
3146         }
3147         else
3148         {
3149           lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, 
3150                                                      lpLVItem->iSubItem);
3151           if (lpSubItem != NULL)
3152           {
3153             if (lpLVItem->mask & LVIF_TEXT) 
3154             {
3155               if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
3156               {
3157                 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
3158               }
3159               else
3160               {
3161                 nLength = Str_GetPtrA(lpSubItem->pszText, lpLVItem->pszText, 
3162                                         lpLVItem->cchTextMax);
3163               }
3164             }
3165           }
3166         }
3167       }
3168     }
3169   }
3170
3171   return nLength;
3172 }
3173
3174 /***
3175  * DESCRIPTION:
3176  * Searches for an item based on properties + relationships.
3177  * 
3178  * PARAMETER(S):
3179  * [I] HWND : window handle
3180  * [I] INT : item index
3181  * [I] UINT : relationship flag
3182  * 
3183  * RETURN:
3184  *   SUCCESS : item index
3185  *   FAILURE : -1
3186  */
3187 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
3188 {
3189   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3190   INT nResult = -1;
3191
3192   if (nItem == -1)
3193   {
3194     /* start at begin */
3195     nItem = 0;
3196   }
3197   else
3198   {
3199     /* exclude specified item */
3200     nItem++;
3201   }
3202
3203   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3204   {
3205     /* TO DO */
3206   }  
3207   
3208   return nResult;
3209 }
3210
3211 /* << LISTVIEW_GetNumberOfWorkAreas >> */
3212
3213 /***
3214  * DESCRIPTION:
3215  * Retrieves the current origin when in icon or small icon display mode.
3216  * 
3217  * PARAMETER(S):
3218  * [I] HWND : window handle
3219  * [O] LPPOINT : coordinate information
3220  * 
3221  * RETURN:
3222  *   SUCCESS : TRUE
3223  *   FAILURE : FALSE
3224  */
3225 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpOrigin)
3226 {
3227   LONG lStyle = GetWindowLongA(hwnd, GWL_ID);
3228   BOOL bResult = FALSE;
3229
3230   if ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON) 
3231   {
3232     /* TO DO */
3233     lpOrigin->x = 0;
3234     lpOrigin->y = 0;
3235   }
3236   else if ((lStyle & LVS_TYPEMASK) == LVS_ICON) 
3237   {
3238     /* TO DO */
3239     lpOrigin->x = 0;
3240     lpOrigin->y = 0;
3241   }
3242
3243   return bResult;
3244 }
3245
3246 /***
3247  * DESCRIPTION:
3248  * Retrieves the number of items that are marked as selected.
3249  * 
3250  * PARAMETER(S):
3251  * [I] HWND : window handle
3252  * 
3253  * RETURN:
3254  * Number of items selected.
3255  */
3256 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
3257 {
3258   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3259   INT nSelectedCount = 0;
3260   INT i;
3261
3262   for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
3263   {
3264     if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
3265     {
3266       nSelectedCount++;
3267     }
3268   }
3269
3270   return nSelectedCount;
3271 }
3272
3273 /***
3274  * DESCRIPTION:
3275  * Retrieves item index that marks the start of a multiple selection.
3276  * 
3277  * PARAMETER(S):
3278  * [I] HWND : window handle
3279  * 
3280  * RETURN:
3281  * Index number or -1 if there is no selection mark.
3282  */
3283 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
3284 {
3285   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3286
3287   return infoPtr->nSelectionMark;
3288 }
3289
3290 /***
3291  * DESCRIPTION:
3292  * Retrieves the width of a string.
3293  * 
3294  * PARAMETER(S):
3295  * [I] HWND : window handle
3296  * 
3297  * RETURN:
3298  *   SUCCESS : string width (in pixels)
3299  *   FAILURE : zero
3300  */
3301 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpsz)
3302 {
3303   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3304   HFONT hFont, hOldFont;
3305   HDC hdc;
3306   SIZE textSize;
3307
3308   /* initialize */ 
3309   ZeroMemory(&textSize, sizeof(SIZE));
3310   if (lpsz != NULL)
3311   {
3312     hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
3313     hdc = GetDC(hwnd);
3314     hOldFont = SelectObject(hdc, hFont);
3315     GetTextExtentPointA(hdc, lpsz, lstrlenA(lpsz), &textSize);
3316     SelectObject(hdc, hOldFont);
3317     ReleaseDC(hwnd, hdc);
3318   }
3319
3320   return textSize.cx;
3321 }
3322
3323 /***
3324  * DESCRIPTION:
3325  * Retrieves the text backgound color.
3326  * 
3327  * PARAMETER(S):
3328  * [I] HWND : window handle
3329  * 
3330  * RETURN:
3331  * COLORREF associated with the the background.
3332  */
3333 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
3334 {
3335   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
3336
3337   return infoPtr->clrTextBk;
3338 }
3339
3340 /***
3341  * DESCRIPTION:
3342  * Retrieves the text color.
3343  * 
3344  * PARAMETER(S):
3345  * [I] HWND : window handle
3346  * 
3347  * RETURN:
3348  * COLORREF associated with the text.
3349  */
3350 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
3351 {
3352   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
3353
3354   return infoPtr->clrText;
3355 }
3356
3357 /***
3358  * DESCRIPTION:
3359  * Retrieves the bounding rectangle of all the items.
3360  * 
3361  * PARAMETER(S):
3362  * [I] HWND : window handle
3363  * [O] LPRECT : bounding rectangle
3364  *
3365  * RETURN:
3366  *   SUCCESS : TRUE
3367  *   FAILURE : FALSE
3368  */
3369 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprc)
3370 {
3371   /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
3372   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3373   BOOL bResult = FALSE;
3374
3375   if (lprc != NULL)
3376   {
3377     if (((lStyle & LVS_TYPEMASK) == LVS_ICON) || 
3378         ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON))
3379     {
3380       /* TO DO */
3381     }
3382   }
3383
3384   return bResult;
3385 }
3386
3387 /***
3388  * DESCRIPTION:
3389  * Determines which section of the item was selected (if any).
3390  * 
3391  * PARAMETER(S):
3392  * [I] HWND : window handle
3393  * [I] INT : item index
3394  * [IO] LPLVHITTESTINFO : hit test information
3395  *
3396  * RETURN:
3397  *   SUCCESS : item index
3398  *   FAILURE : -1
3399  */
3400 static INT LISTVIEW_HitTestItem(HWND hwnd, INT nItem, 
3401                                   LPLVHITTESTINFO lpHitTestInfo)
3402 {
3403   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3404   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3405   HDPA hdpaSubItems;
3406   LISTVIEW_ITEM *lpItem;
3407   INT nOffset;
3408   INT nLabelWidth;
3409   INT nPosX = 0;
3410   CHAR szDispText[DISP_TEXT_SIZE];
3411   LPSTR pszDispText;
3412
3413   /*init pointer */
3414   pszDispText = szDispText;
3415
3416   if ((LVS_TYPEMASK & lStyle) == LVS_LIST)
3417   {
3418     /* calculate offset from start of item (in pixels) */
3419     nOffset = lpHitTestInfo->pt.x % infoPtr->nColumnWidth;
3420   }
3421   else
3422   {
3423     nOffset = lpHitTestInfo->pt.x;
3424   }
3425
3426   /* verify existance of item */
3427   if (nItem < GETITEMCOUNT(infoPtr))
3428   {
3429     /* get item */
3430     hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3431     if (hdpaSubItems != NULL)
3432     {
3433       lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3434       if (lpItem != NULL)
3435       {
3436         if (infoPtr->himlState != NULL)
3437         {
3438           nPosX += infoPtr->iconSize.cx;
3439           if (nOffset <= nPosX)
3440           {
3441             lpHitTestInfo->flags = LVHT_ONITEMSTATEICON | LVHT_ONITEM;
3442             lpHitTestInfo->iItem = nItem;
3443             lpHitTestInfo->iSubItem = 0;
3444             return nItem;
3445           }
3446         }
3447
3448         if (infoPtr->himlSmall != NULL)
3449         {
3450           nPosX += infoPtr->iconSize.cx;
3451           if (nOffset <= nPosX)
3452           {
3453             lpHitTestInfo->flags = LVHT_ONITEMICON | LVHT_ONITEM;
3454             lpHitTestInfo->iItem = nItem;
3455             lpHitTestInfo->iSubItem = 0;
3456             return nItem;
3457           }
3458         }
3459
3460         /* get width of label in pixels */
3461         LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, NULL, NULL, 
3462                                  &pszDispText, DISP_TEXT_SIZE);
3463         nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText); 
3464         nLabelWidth += nPosX;
3465
3466         if (nOffset <= nLabelWidth)
3467         {
3468           lpHitTestInfo->flags = LVHT_ONITEMLABEL | LVHT_ONITEM;
3469           lpHitTestInfo->iItem = nItem;
3470           lpHitTestInfo->iSubItem = 0;
3471           return nItem;
3472         }
3473       }
3474     }
3475   }
3476
3477   /* hit is not on item */
3478   lpHitTestInfo->flags = LVHT_NOWHERE; 
3479      
3480   return -1;
3481 }
3482
3483 /***
3484  * DESCRIPTION:
3485  * Determines wich listview item is located at the specified position.
3486  * 
3487  * PARAMETER(S):
3488  * [I] HWND : window handle
3489  * [IO} LPLVHITTESTINFO : hit test information
3490  *
3491  * RETURN:
3492  *   SUCCESS : item index
3493  *   FAILURE : -1
3494  */
3495 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
3496 {
3497   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3498   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3499   INT nColumn;
3500   INT nRow;
3501   INT nTopIndex;
3502   INT nItem = -1;
3503
3504   lpHitTestInfo->flags = 0;
3505   if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
3506   {
3507     lpHitTestInfo->flags = LVHT_TOLEFT;
3508   }
3509   else if (infoPtr->rcList.right < lpHitTestInfo->pt.x) 
3510   {
3511     lpHitTestInfo->flags = LVHT_TORIGHT;
3512   }
3513   
3514   if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
3515   {
3516     lpHitTestInfo->flags |= LVHT_ABOVE;
3517   } 
3518   else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y) 
3519   {
3520     lpHitTestInfo->flags |= LVHT_BELOW;
3521   }
3522
3523   if (lpHitTestInfo->flags == 0)
3524   {
3525     switch (LVS_TYPEMASK & lStyle)
3526     {
3527     case LVS_LIST:
3528       /* get current column */
3529       nColumn = lpHitTestInfo->pt.x / infoPtr->nColumnWidth;
3530
3531       /* get current row */ 
3532       nRow = lpHitTestInfo->pt.y / infoPtr->nItemHeight;
3533     
3534       /* get the index of the first visible item */
3535       nTopIndex = ListView_GetTopIndex(hwnd);
3536
3537       nItem = nColumn * infoPtr->nCountPerColumn + nTopIndex + nRow;
3538       nItem = LISTVIEW_HitTestItem(hwnd, nItem, lpHitTestInfo);
3539       break;
3540
3541     case LVS_REPORT:
3542       /* get current row */ 
3543       nRow = ((lpHitTestInfo->pt.y - infoPtr->rcList.top) / 
3544               infoPtr->nItemHeight);
3545
3546       /* get the index of the first visible item */
3547       nTopIndex = ListView_GetTopIndex(hwnd);
3548     
3549       nItem = nTopIndex + nRow;
3550       nItem = LISTVIEW_HitTestItem(hwnd, nItem, lpHitTestInfo);
3551       break;
3552
3553     default:
3554 /*       nItem = LISTVIEW_HitTestItem(hwnd, nItem, lpHitTestInfo); */
3555     }
3556   }
3557
3558   return nItem;
3559 }
3560
3561 /***
3562  * DESCRIPTION:
3563  * Inserts a new column.
3564  * 
3565  * PARAMETER(S):
3566  * [I] HWND : window handle
3567  * [I] INT : column index
3568  * [I] LPLVCOLUMNA : column information
3569  *
3570  * RETURN:
3571  *   SUCCESS : new column index
3572  *   FAILURE : -1
3573  */
3574 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn, 
3575                                         LPLVCOLUMNA lpColumn)
3576 {
3577   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3578   HDITEMA hdi;
3579   INT nNewColumn = -1;
3580
3581   if (lpColumn != NULL) 
3582   {
3583     /* initialize memory */
3584     ZeroMemory(&hdi, sizeof(HDITEMA));
3585
3586     if (lpColumn->mask & LVCF_FMT) 
3587     {
3588       /* format member is valid */
3589       hdi.mask |= HDI_FORMAT;
3590
3591       /* set text alignment (leftmost column must be left-aligned) */
3592       if (nColumn == 0)
3593       {
3594         hdi.fmt |= HDF_LEFT;
3595       }
3596       else
3597       {
3598         if (lpColumn->fmt & LVCFMT_LEFT)
3599         {
3600           hdi.fmt |= HDF_LEFT;
3601         }
3602         else if (lpColumn->fmt & LVCFMT_RIGHT)
3603         {
3604           hdi.fmt |= HDF_RIGHT;
3605         }
3606         else if (lpColumn->fmt & LVCFMT_CENTER)
3607         {
3608           hdi.fmt |= HDF_CENTER;
3609         }
3610       }
3611  
3612       if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
3613       {
3614         hdi.fmt |= HDF_BITMAP_ON_RIGHT;
3615         /* ??? */
3616       }
3617
3618       if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
3619       {
3620         /* ??? */
3621       }
3622       
3623       if (lpColumn->fmt & LVCFMT_IMAGE)
3624       {
3625         hdi.fmt |= HDF_IMAGE;
3626         hdi.iImage = I_IMAGECALLBACK;
3627       }
3628     }
3629
3630     if (lpColumn->mask & LVCF_WIDTH) 
3631     {
3632       hdi.mask |= HDI_WIDTH;
3633       hdi.cxy = lpColumn->cx;
3634     }
3635   
3636     if (lpColumn->mask & LVCF_TEXT) 
3637     {
3638       hdi.mask |= HDI_TEXT | HDI_FORMAT;
3639       hdi.pszText = lpColumn->pszText;
3640       hdi.cchTextMax = lstrlenA(lpColumn->pszText);
3641       hdi.fmt |= HDF_STRING;
3642     }
3643   
3644     if (lpColumn->mask & LVCF_IMAGE) 
3645     {
3646       hdi.mask |= HDI_IMAGE;
3647       hdi.iImage = lpColumn->iImage;
3648     }
3649
3650     if (lpColumn->mask & LVCF_ORDER) 
3651     {
3652       hdi.mask |= HDI_ORDER;
3653       hdi.iOrder = lpColumn->iOrder;
3654     }
3655
3656     /* insert item in header control */
3657     nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
3658                              (WPARAM)nColumn, (LPARAM)&hdi);
3659
3660     LISTVIEW_SetScroll(hwnd);
3661     InvalidateRect(hwnd, NULL, FALSE);
3662   }
3663
3664   return nNewColumn;
3665 }
3666
3667 /* << LISTVIEW_InsertColumnW >> */
3668
3669 /***
3670  * DESCRIPTION:
3671  * Inserts a new item in the listview control.
3672  * 
3673  * PARAMETER(S):
3674  * [I] HWND : window handle
3675  * [I] LPLVITEMA : item information
3676  *
3677  * RETURN:
3678  *   SUCCESS : new item index
3679  *   FAILURE : -1
3680  */
3681 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
3682 {
3683   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3684   LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3685   NMLISTVIEW nmlv;
3686   INT nItem = -1;
3687   HDPA hdpaSubItems;
3688   LISTVIEW_ITEM *lpItem = NULL;
3689
3690   if (lpLVItem != NULL)
3691   {
3692     /* make sure it's not a subitem; cannot insert a subitem */
3693     if (lpLVItem->iSubItem == 0)
3694     {
3695       lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
3696       if (lpItem != NULL)
3697       {
3698         ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
3699         if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) == TRUE)
3700         {
3701           /* insert item in listview control data structure */
3702           hdpaSubItems = DPA_Create(8);
3703           if (hdpaSubItems != NULL)
3704           {
3705             nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
3706             if (nItem != -1)
3707             {
3708               nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem, 
3709                                     hdpaSubItems);
3710               if (nItem != -1)
3711               {
3712                 /* manage item focus */
3713                 if (lpLVItem->mask & LVIF_STATE)
3714                 {
3715                   if (lpLVItem->stateMask & LVIS_FOCUSED)
3716                   {
3717                     LISTVIEW_SetItemFocus(hwnd, nItem);
3718                   }           
3719                 }
3720
3721                 /* send LVN_INSERTITEM notification */
3722                 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
3723                 nmlv.hdr.hwndFrom = hwnd;
3724                 nmlv.hdr.idFrom = lCtrlId;
3725                 nmlv.hdr.code = LVN_INSERTITEM;
3726                 nmlv.iItem = nItem;
3727                 nmlv.lParam = lpItem->lParam;;
3728                 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
3729
3730                 /* set scrolling parameters */
3731                 LISTVIEW_SetScroll(hwnd);
3732                 
3733                 /* refresh client area */
3734                 InvalidateRect(hwnd, NULL, FALSE);
3735               }
3736             }
3737           }
3738         }
3739       }
3740     }
3741   }
3742
3743   /* free memory if unsuccessful */
3744   if ((nItem == -1) && (lpItem != NULL))
3745   {
3746     COMCTL32_Free(lpItem);
3747   }
3748
3749   return nItem;
3750 }
3751
3752 /* << LISTVIEW_InsertItemW >> */
3753
3754 /***
3755  * DESCRIPTION:
3756  * Redraws a range of items.
3757  * 
3758  * PARAMETER(S):
3759  * [I] HWND : window handle
3760  * [I] INT : first item
3761  * [I] INT : last item
3762  *
3763  * RETURN:
3764  *   SUCCESS : TRUE
3765  *   FAILURE : FALSE
3766  */
3767 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
3768 {
3769   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); 
3770   BOOL bResult = FALSE;
3771   RECT rc;
3772
3773   if (nFirst <= nLast)
3774   {
3775     if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
3776     {
3777       if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
3778       {
3779         /* bResult = */
3780         InvalidateRect(hwnd, &rc, FALSE);
3781       }
3782     }
3783   }
3784
3785   return bResult;
3786 }
3787
3788 /***
3789  * DESCRIPTION:
3790  * Scrolls the content of a listview.
3791  * 
3792  * PARAMETER(S):
3793  * [I] HWND : window handle
3794  * [I] INT : amount of horizontal scrolling
3795  * [I] INT : amount of vertical scrolling
3796  *
3797  * RETURN:
3798  *   SUCCESS : TRUE
3799  *   FAILURE : FALSE
3800  */
3801 static LRESULT LISTVIEW_Scroll(HWND hwnd, INT nHScroll, INT nVScroll)
3802 {
3803   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3804   INT nScrollPos = 0;
3805   BOOL bResult = FALSE;
3806   INT nMinRange;
3807   INT nMaxRange;
3808
3809   if (lStyle & WS_HSCROLL)
3810   {
3811     nScrollPos = GetScrollPos(hwnd, SB_HORZ);
3812     GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
3813     nScrollPos += nHScroll;
3814
3815     if ((LVS_TYPEMASK & lStyle) == LVS_LIST)
3816     {
3817       nScrollPos = GetScrollPos(hwnd, SB_HORZ);
3818       GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
3819       nScrollPos += nHScroll;
3820       if ((nMinRange <= nScrollPos) && (nScrollPos <= nMaxRange))
3821       {
3822         bResult = TRUE;
3823         SetScrollPos(hwnd, SB_HORZ, nScrollPos, TRUE);
3824       }
3825     }
3826     else
3827     {
3828       /* TO DO */
3829     }
3830   }
3831   
3832   if (lStyle & WS_VSCROLL)
3833   {
3834     if ((LVS_TYPEMASK & lStyle) == LVS_REPORT)
3835     {
3836       nScrollPos = GetScrollPos(hwnd, SB_VERT);
3837       GetScrollRange(hwnd, SB_VERT, &nMinRange, &nMaxRange);
3838       nScrollPos += nVScroll;
3839       if ((nMinRange <= nScrollPos) && (nScrollPos <= nMaxRange))
3840       {
3841         bResult = TRUE;
3842         SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);
3843       }
3844     }
3845     else
3846     {
3847       /* TO DO */
3848     }
3849   }
3850
3851   if (bResult == TRUE)
3852   {
3853     /* refresh client area */
3854     InvalidateRect(hwnd, NULL, TRUE);
3855   }
3856
3857   return bResult; 
3858 }
3859
3860 /***
3861  * DESCRIPTION:
3862  * Sets the background color.
3863  * 
3864  * PARAMETER(S):
3865  * [I] HWND : window handle
3866  * [I] COLORREF : background color
3867  *
3868  * RETURN:
3869  *   SUCCESS : TRUE
3870  *   FAILURE : FALSE
3871  */
3872 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
3873 {
3874   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3875
3876   infoPtr->clrBk = clrBk;
3877   InvalidateRect(hwnd, NULL, TRUE);
3878   
3879   return TRUE;
3880 }
3881
3882 /***
3883  * DESCRIPTION:
3884  * Sets the callback mask. This mask will be used when the parent
3885  * window stores the state information (some or all).
3886  * 
3887  * PARAMETER(S):
3888  * [I] HWND : window handle
3889  * [I] UINT : state mask
3890  *
3891  * RETURN:
3892  *   SUCCESS : TRUE
3893  *   FAILURE : FALSE
3894  */
3895 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
3896 {
3897   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3898
3899   infoPtr->uCallbackMask = uMask;
3900
3901   return TRUE;
3902 }
3903
3904 /***
3905  * DESCRIPTION:
3906  * Sets column attributes.
3907  * 
3908  * PARAMETER(S):
3909  * [I] HWND : window handle
3910  * [I] INT : column index
3911  * [I] LPLVCOLUMNA : column attributes
3912  *
3913  * RETURN:
3914  *   SUCCESS : TRUE
3915  *   FAILURE : FALSE
3916  */
3917 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn, 
3918                                      LPLVCOLUMNA lpColumn)
3919 {
3920   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3921   HDITEMA hdi;
3922   BOOL bResult = FALSE;
3923
3924   if ((lpColumn != NULL) && (nColumn >= 0) && 
3925       (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
3926   {
3927     /* initialize memory */
3928     ZeroMemory(&hdi, sizeof(HDITEMA));
3929
3930     if (lpColumn->mask & LVCF_FMT) 
3931     {
3932       /* format member is valid */
3933       hdi.mask |= HDI_FORMAT;
3934
3935       /* set text alignment (leftmost column must be left-aligned) */
3936       if (nColumn == 0)
3937       {
3938         hdi.fmt |= HDF_LEFT;
3939       }
3940       else
3941       {
3942         if (lpColumn->fmt & LVCFMT_LEFT)
3943         {
3944           hdi.fmt |= HDF_LEFT;
3945         }
3946         else if (lpColumn->fmt & LVCFMT_RIGHT)
3947         {
3948           hdi.fmt |= HDF_RIGHT;
3949         }
3950         else if (lpColumn->fmt & LVCFMT_CENTER)
3951         {
3952           hdi.fmt |= HDF_CENTER;
3953         }
3954       }
3955       
3956       if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
3957       {
3958         hdi.fmt |= HDF_BITMAP_ON_RIGHT;
3959       }
3960
3961       if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
3962       {
3963         hdi.fmt |= HDF_IMAGE;
3964       }
3965       
3966       if (lpColumn->fmt & LVCFMT_IMAGE)
3967       {
3968         hdi.fmt |= HDF_IMAGE;
3969         hdi.iImage = I_IMAGECALLBACK;
3970       }
3971     }
3972
3973     if (lpColumn->mask & LVCF_WIDTH) 
3974     {
3975       hdi.mask |= HDI_WIDTH;
3976       hdi.cxy = lpColumn->cx;
3977     }
3978     
3979     if (lpColumn->mask & LVCF_TEXT) 
3980     {
3981       hdi.mask |= HDI_TEXT | HDI_FORMAT;
3982       hdi.pszText = lpColumn->pszText;
3983       hdi.cchTextMax = lstrlenA(lpColumn->pszText);
3984       hdi.fmt |= HDF_STRING;
3985     }
3986   
3987     if (lpColumn->mask & LVCF_IMAGE) 
3988     {
3989       hdi.mask |= HDI_IMAGE;
3990       hdi.iImage = lpColumn->iImage;
3991     }
3992
3993     if (lpColumn->mask & LVCF_ORDER) 
3994     {
3995       hdi.mask |= HDI_ORDER;
3996       hdi.iOrder = lpColumn->iOrder;
3997     }
3998
3999     /* set header item attributes */
4000     bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
4001   }
4002   
4003   return bResult;
4004 }
4005
4006 /***
4007  * DESCRIPTION:
4008  * Sets image list.
4009  * 
4010  * PARAMETER(S):
4011  * [I] HWND : window handle
4012  * [I] INT : image list type  
4013  * [I] HIMAGELIST : image list handle
4014  *
4015  * RETURN:
4016  *   SUCCESS : old image list
4017  *   FAILURE : NULL
4018  */
4019 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
4020 {
4021   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4022   HIMAGELIST himlTemp = 0;
4023
4024   switch (nType) 
4025   {
4026   case LVSIL_NORMAL:
4027     himlTemp = infoPtr->himlNormal;
4028     infoPtr->himlNormal = himl;
4029     return (LRESULT)himlTemp;
4030
4031   case LVSIL_SMALL:
4032     himlTemp = infoPtr->himlSmall;
4033     infoPtr->himlSmall = himl;
4034     return (LRESULT)himlTemp;
4035
4036   case LVSIL_STATE:
4037     himlTemp = infoPtr->himlState;
4038     infoPtr->himlState = himl;
4039     return (LRESULT)himlTemp;
4040   }
4041
4042   return (LRESULT)NULL;
4043 }
4044
4045
4046 /***
4047  * DESCRIPTION:
4048  * Sets item attributes.
4049  * 
4050  * PARAMETER(S):
4051  * [I] HWND : window handle
4052  * [I] LPLVITEM : item information 
4053  *
4054  * RETURN:
4055  *   SUCCESS : TRUE
4056  *   FAILURE : FALSE
4057  */
4058 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
4059 {
4060   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4061   BOOL bResult = FALSE;
4062
4063   if (lpLVItem != NULL)
4064   {
4065     if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
4066     {
4067       if (lpLVItem->iSubItem == 0)
4068       {
4069         bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
4070       }
4071       else
4072       {
4073         bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
4074       }
4075     }
4076   }
4077
4078
4079   return bResult;
4080 }
4081
4082 /* << LISTVIEW_SetItemW >> */
4083
4084 /***
4085  * DESCRIPTION:
4086  * Preallocates memory.
4087  * 
4088  * PARAMETER(S):
4089  * [I] HWND : window handle
4090  * [I] INT : item count (prjected number of items)
4091  *
4092  * RETURN:
4093  * None
4094  */
4095 static VOID LISTVIEW_SetItemCount(HWND hwnd, INT nItemCount)
4096 {
4097   /* TO DO */
4098 }
4099
4100 /***
4101  * DESCRIPTION:
4102  * Sets item position.
4103  * 
4104  * PARAMETER(S):
4105  * [I] HWND : window handle
4106  * [I] INT : item index
4107  * [I] INT : x coordinate
4108  * [I] INT : y coordinate
4109  *
4110  * RETURN:
4111  *   SUCCESS : TRUE
4112  *   FAILURE : FALSE
4113  */
4114 static LRESULT LISTVIEW_SetItemPosition(HWND hwnd, INT nItem, 
4115                                         INT nPosX, INT nPosY)
4116 {
4117   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4118   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4119   BOOL bResult = FALSE;
4120
4121   if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
4122   {
4123     if (((lStyle & LVS_TYPEMASK) == LVS_ICON) || 
4124         ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON))
4125     {
4126       /* TO DO */
4127     }
4128   }
4129
4130   return bResult;
4131 }
4132
4133 /***
4134  * DESCRIPTION:
4135  * Sets the state of one or many items.
4136  * 
4137  * PARAMETER(S):
4138  * [I] HWND : window handle
4139  * [I]INT : item index
4140  * [I] LPLVITEM : item or subitem info
4141  *
4142  * RETURN:
4143  *   SUCCESS : TRUE
4144  *   FAILURE : FALSE
4145  */
4146 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, 
4147                                      LPLVITEMA lpLVItem)
4148 {
4149   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4150   BOOL bResult = FALSE;
4151   LVITEMA lvItem;
4152   INT i;
4153
4154   if (nItem == -1)
4155   {
4156     bResult = TRUE;
4157     ZeroMemory(&lvItem, sizeof(LVITEMA));
4158     lvItem.mask = LVIF_STATE;
4159     lvItem.state = lpLVItem->state;
4160     lvItem.stateMask = lpLVItem->stateMask;
4161     
4162     /* apply to all items */
4163     for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
4164     {
4165       lvItem.iItem = i;
4166       if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
4167       {
4168         bResult = FALSE;
4169       }
4170     }
4171   }
4172   else
4173   {
4174     ZeroMemory(&lvItem, sizeof(LVITEMA));
4175     lvItem.mask = LVIF_STATE;
4176     lvItem.state = lpLVItem->state;
4177     lvItem.stateMask = lpLVItem->stateMask;
4178     lvItem.iItem = nItem;
4179     bResult = ListView_SetItemA(hwnd, &lvItem);
4180   }
4181
4182   return bResult;
4183 }
4184
4185 /***
4186  * DESCRIPTION:
4187  * Sets the text of an item or subitem.
4188  * 
4189  * PARAMETER(S):
4190  * [I] HWND : window handle
4191  * [I] INT : item index
4192  * [I] LPLVITEMA : item or subitem info
4193  *
4194  * RETURN:
4195  *   SUCCESS : TRUE
4196  *   FAILURE : FALSE
4197  */
4198 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, 
4199                                       LPLVITEMA lpLVItem)
4200 {
4201   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4202   BOOL bResult = FALSE;
4203   LVITEMA lvItem;
4204
4205   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4206   {
4207     ZeroMemory(&lvItem, sizeof(LVITEMA));
4208     lvItem.mask = LVIF_TEXT;
4209     lvItem.pszText = lpLVItem->pszText;
4210     lvItem.iItem = nItem;
4211     lvItem.iSubItem = lpLVItem->iSubItem;
4212     bResult = ListView_SetItemA(hwnd, &lvItem);
4213   }
4214   
4215   return bResult;
4216 }
4217
4218 /***
4219  * DESCRIPTION:
4220  * Sets the text background color.
4221  * 
4222  * PARAMETER(S):
4223  * [I] HWND : window handle
4224  * [I] COLORREF : text background color
4225  *
4226  * RETURN:
4227  *   SUCCESS : TRUE
4228  *   FAILURE : FALSE
4229  */
4230 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
4231 {
4232   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4233
4234   infoPtr->clrTextBk = clrTextBk;
4235
4236   return TRUE;
4237 }
4238
4239 /***
4240  * DESCRIPTION:
4241  * Sets the text background color.
4242  * 
4243  * PARAMETER(S):
4244  * [I] HWND : window handle
4245  * [I] COLORREF : text color 
4246  *
4247  * RETURN:
4248  *   SUCCESS : TRUE
4249  *   FAILURE : FALSE
4250  */
4251 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
4252 {
4253   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4254
4255   infoPtr->clrText = clrText;
4256
4257   return TRUE;
4258 }
4259
4260 /***
4261  * DESCRIPTION:
4262  * Sort items.
4263  * 
4264  * PARAMETER(S):
4265  * [I] HWND : window handle
4266  *
4267  * RETURN:
4268  *   SUCCESS : TRUE
4269  *   FAILURE : FALSE
4270  */
4271 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
4272 {
4273   FIXME (listview, "empty stub!\n");
4274
4275   return TRUE;
4276 }
4277
4278 /***
4279  * DESCRIPTION:
4280  * Updates an items or rearranges the listview control.
4281  * 
4282  * PARAMETER(S):
4283  * [I] HWND : window handle
4284  * [I] INT : item index
4285  *
4286  * RETURN:
4287  *   SUCCESS : TRUE
4288  *   FAILURE : FALSE
4289  */
4290 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
4291 {
4292   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4293   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4294   BOOL bResult = FALSE;
4295   RECT rc;
4296
4297   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4298   {
4299     bResult = TRUE;
4300
4301     /* rearrange with default alignment style */
4302     if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
4303         ((lStyle & LVS_TYPEMASK)  == LVS_SMALLICON)))
4304     {
4305       ListView_Arrange(hwnd, 0);
4306     }
4307     else
4308     {
4309       /* get item bounding rectangle */
4310       rc.left = LVIR_BOUNDS;
4311       ListView_GetItemRect(hwnd, nItem, &rc);
4312       InvalidateRect(hwnd, &rc, FALSE);
4313     }
4314   }
4315
4316   return bResult;
4317 }
4318
4319 /***
4320  * DESCRIPTION:
4321  * Creates a listview control.
4322  * 
4323  * PARAMETER(S):
4324  * [I] HWND : window handle
4325  *
4326  * RETURN:
4327  * Zero
4328  */
4329 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
4330 {
4331   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4332   LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
4333   LOGFONTA logFont;
4334   HDLAYOUT hl;
4335   WINDOWPOS wp;
4336
4337   /* determine the type of structures to use */
4338   infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT, 
4339                                        (WPARAM)hwnd, (LPARAM)NF_QUERY);
4340   if (infoPtr->notifyFormat != NFR_ANSI)
4341   {
4342     FIXME (listview, "ANSI notify format is NOT used\n");
4343   }
4344
4345   /* initialize color information  */
4346   infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
4347   infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
4348   infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW); 
4349
4350   /* set default values */
4351   infoPtr->uCallbackMask = 0;
4352   infoPtr->nFocusedItem = -1;
4353   infoPtr->nSelectionMark = -1;
4354   infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
4355   infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
4356   ZeroMemory(&infoPtr->rcList, sizeof(RECT));
4357
4358   /* get default font (icon title) */
4359   SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
4360   infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
4361   infoPtr->hFont = infoPtr->hDefaultFont;
4362   
4363   /* create header */
4364   infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL, 
4365                                         WS_CHILD | HDS_HORZ | HDS_BUTTONS , 
4366                                         0, 0, 0, 0, hwnd, (HMENU)0, 
4367                                         lpcs->hInstance, NULL);
4368
4369   /* set header font */
4370   SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, 
4371                (LPARAM)TRUE);
4372
4373   switch (lpcs->style & LVS_TYPEMASK)
4374   {
4375   case LVS_REPORT:
4376     /* reset header */
4377     hl.prc = &infoPtr->rcList;
4378     hl.pwpos = &wp;
4379     Header_Layout(infoPtr->hwndHeader, &hl);
4380     SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy, 
4381                    wp.flags);
4382
4383     /* set new top coord */
4384     infoPtr->rcList.top = wp.cy;
4385
4386     /* display header */
4387     ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
4388     break;
4389
4390   case LVS_LIST:
4391     break;
4392
4393   default:
4394     /*  temporary (until there is support) */
4395     SetWindowLongA(hwnd, GWL_STYLE, 
4396                      (lpcs->style & ~LVS_TYPEMASK) | LVS_LIST);
4397   }
4398
4399   /* TEMPORARY */
4400   LISTVIEW_UnsupportedStyles(lpcs->style);
4401
4402   /* allocate memory */
4403   infoPtr->hdpaItems = DPA_Create(10);
4404
4405   /* set view dependent information */
4406   LISTVIEW_SetViewInfo(hwnd);
4407
4408   return 0;
4409 }
4410
4411
4412 /***
4413  * DESCRIPTION:
4414  * Destroys the window
4415  * 
4416  * PARAMETER(S):
4417  * [I] HWND : window handle
4418  * 
4419  * RETURN:
4420  * Zero
4421  */
4422 static LRESULT LISTVIEW_Destroy(HWND hwnd)
4423 {
4424   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4425
4426   /* delete all items */
4427   LISTVIEW_DeleteAllItems(hwnd);
4428
4429   /* destroy dpa */
4430   DPA_Destroy(infoPtr->hdpaItems);
4431
4432   /* destroy header */
4433   if (infoPtr->hwndHeader)
4434   {
4435     DestroyWindow(infoPtr->hwndHeader);
4436   }
4437
4438   /* destroy font */
4439   infoPtr->hFont = (HFONT)0;
4440   if (infoPtr->hDefaultFont)
4441   {
4442     DeleteObject(infoPtr->hDefaultFont);
4443   }
4444
4445   return 0;
4446 }
4447
4448 /***
4449  * DESCRIPTION:
4450  * Erases the background of the listview control
4451  * 
4452  * PARAMETER(S):
4453  * [I] HWND : window handle
4454  * [I] WPARAM : device context handle
4455  * [I] LPARAM : not used
4456  * 
4457  * RETURN:
4458  *   SUCCESS : TRUE
4459  *   FAILURE : FALSE
4460  */
4461 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam, 
4462                                         LPARAM lParam)
4463 {
4464   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4465   BOOL bResult;
4466
4467   if (infoPtr->clrBk == CLR_NONE) 
4468   {
4469     bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
4470   }
4471   else 
4472   {
4473     HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
4474     FillRect((HDC)wParam, &infoPtr->rcList, hBrush);
4475     DeleteObject(hBrush);
4476     bResult = TRUE;
4477   }
4478
4479   return bResult;
4480 }
4481
4482 /***
4483  * DESCRIPTION:
4484  * Gets the listview control font.
4485  * 
4486  * PARAMETER(S):
4487  * [I] HWND : window handle
4488  *
4489  * RETURN:
4490  * Font handle.
4491  */
4492 static LRESULT LISTVIEW_GetFont(HWND hwnd)
4493 {
4494   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4495
4496   return infoPtr->hFont;
4497 }
4498
4499 /***
4500  * DESCRIPTION:
4501  * Performs horizontal scrolling.
4502  * 
4503  * PARAMETER(S):
4504  * [I] HWND : window handle
4505  * [I] INT : scroll code
4506  * [I] INT : scroll position
4507  * [I] HWND : scrollbar control window handle
4508  *
4509  * RETURN:
4510  * Zero
4511  */
4512 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, 
4513                                 INT nScroll, HWND hScrollWnd)
4514 {
4515   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4516   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4517   INT nScrollPos, nOldScrollPos;
4518   INT nMinRange;
4519   INT nMaxRange;
4520
4521   GetScrollRange(hwnd, SB_VERT, &nMinRange, &nMaxRange);
4522   nOldScrollPos = nScrollPos = GetScrollPos(hwnd, SB_VERT);
4523
4524   switch (LVS_TYPEMASK & lStyle)
4525   {
4526   case LVS_REPORT:
4527     switch (nScrollCode)
4528     {
4529     case SB_LINEUP:
4530       if (nScrollPos > nMinRange)
4531       {
4532         nScrollPos--;
4533       }
4534       break;
4535     case SB_LINEDOWN:
4536       if (nScrollPos < nMaxRange)
4537       {
4538         nScrollPos++;
4539       }
4540       break;
4541     case SB_PAGEUP:
4542       if (nScrollPos > nMinRange + infoPtr->nCountPerColumn)
4543       {
4544         nScrollPos -= infoPtr->nCountPerColumn;
4545       }
4546       else
4547       {
4548         nScrollPos = nMinRange;
4549       }
4550       break;
4551     case SB_PAGEDOWN:
4552       if (nScrollPos < nMaxRange - infoPtr->nCountPerColumn)
4553       {
4554         nScrollPos += infoPtr->nCountPerColumn;
4555       }
4556       else
4557       {
4558         nScrollPos = nMaxRange;
4559       }
4560       break;
4561     case SB_THUMBPOSITION:
4562       nScrollPos = nScroll;
4563       break;
4564     }
4565     break;
4566
4567     default:
4568       /* TO DO */
4569   }
4570
4571   /* set new scroll position */
4572   if (nScrollPos != nOldScrollPos)
4573   {
4574     SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);
4575     
4576     /* refresh client area */
4577     InvalidateRect(hwnd, NULL, TRUE);
4578   }
4579
4580   return 0;
4581 }
4582
4583
4584 /***
4585  * DESCRIPTION:
4586  * Performs horizontal scrolling.
4587  * 
4588  * PARAMETER(S):
4589  * [I] HWND : window handle
4590  * [I] INT : scroll code
4591  * [I] INT : scroll position
4592  * [I] HWND : scrollbar control window handle
4593  *
4594  * RETURN:
4595  * Zero
4596  */
4597 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, 
4598                                 INT nScroll, HWND hScrollWnd)
4599 {
4600   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4601   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4602   INT nScrollPos, nOldScrollPos;
4603   INT nMinRange;
4604   INT nMaxRange;
4605
4606   GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
4607   nOldScrollPos = nScrollPos = GetScrollPos(hwnd, SB_HORZ);
4608
4609   switch (LVS_TYPEMASK & lStyle)
4610   {
4611   case LVS_LIST:
4612
4613     /* list display mode horizontal scrolling */
4614     switch (nScrollCode)
4615     {
4616     case SB_LINELEFT:
4617       if (nScrollPos > nMinRange)
4618       {
4619         nScrollPos--;
4620       }
4621       break;
4622     case SB_LINERIGHT:
4623       if (nScrollPos < nMaxRange)
4624       {
4625         nScrollPos++;
4626       }
4627       break;
4628     case SB_PAGELEFT:
4629       if (nScrollPos > nMinRange)
4630       {
4631         nScrollPos = max(nMinRange, nScrollPos - infoPtr->nCountPerRow);
4632       }
4633       else
4634       {
4635         nScrollPos = nMinRange;
4636       }
4637       break;
4638     case SB_PAGERIGHT:
4639       if (nScrollPos < nMaxRange - 1)
4640       {
4641         nScrollPos = min(nMaxRange, nScrollPos + infoPtr->nCountPerRow);
4642       }
4643       else
4644       {
4645         nScrollPos = nMaxRange;
4646       }
4647       break;
4648     case SB_THUMBPOSITION:
4649       nScrollPos = nScroll;
4650       break;
4651     }
4652     break;
4653
4654   case LVS_REPORT:
4655
4656     /* report/details display mode horizontal scrolling */
4657     switch (nScrollCode)
4658     {
4659     case SB_LINELEFT:
4660       if (nScrollPos > nMinRange)
4661       {
4662         nScrollPos--;
4663       }
4664       break;
4665     case SB_LINERIGHT:
4666       if (nScrollPos < nMaxRange)
4667       {
4668         nScrollPos++;
4669       }
4670       break;
4671     case SB_PAGELEFT:
4672       if (nScrollPos > nMinRange)
4673       {
4674         nScrollPos = max(nMinRange, nScrollPos - infoPtr->rcList.right);
4675       }
4676       else
4677       {
4678         nScrollPos = nMinRange;
4679       }
4680       break;
4681     case SB_PAGERIGHT:
4682       if (nScrollPos < nMaxRange)
4683       {
4684         nScrollPos = min(nMaxRange, nScrollPos + infoPtr->rcList.right);
4685       }
4686       else
4687       {
4688         nScrollPos = nMaxRange;
4689       }
4690       break;
4691     case SB_THUMBPOSITION:
4692       nScrollPos = nScroll;
4693       break;
4694     }
4695     break;
4696
4697     default:
4698       /* TO DO */
4699   }
4700
4701   /* set new scroll position */
4702   if (nScrollPos != nOldScrollPos)
4703   {
4704     SetScrollPos(hwnd, SB_HORZ, nScrollPos, TRUE);
4705
4706     /* refresh client area */
4707     InvalidateRect(hwnd, NULL, TRUE);
4708   }
4709
4710   return 0;
4711 }
4712
4713 /***
4714  * DESCRIPTION:
4715  * ??? 
4716  * 
4717  * PARAMETER(S):
4718  * [I] HWND : window handle
4719  * [I] INT : virtual key 
4720  * [I] LONG : key data
4721  *
4722  * RETURN:
4723  * Zero
4724  */
4725 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
4726 {
4727   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4728   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4729   INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4730   HWND hwndParent = GetParent(hwnd);
4731   NMLVKEYDOWN nmKeyDown; 
4732   NMHDR nmh;
4733
4734   /* send LVN_KEYDOWN notification */
4735   ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
4736   nmKeyDown.hdr.hwndFrom = hwnd;  
4737   nmKeyDown.hdr.idFrom = nCtrlId;  
4738   nmKeyDown.hdr.code = LVN_KEYDOWN;  
4739   nmKeyDown.wVKey = nVirtualKey; 
4740   nmKeyDown.flags = 0; 
4741   SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown); 
4742   
4743   /* initialize */
4744   nmh.hwndFrom = hwnd;
4745   nmh.idFrom = nCtrlId;
4746
4747   switch (nVirtualKey)
4748   {
4749   case VK_RETURN:
4750     if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
4751     {
4752       /* send NM_RETURN notification */
4753       nmh.code = NM_RETURN;
4754       ListView_Notify(hwndParent, nCtrlId, &nmh);
4755
4756       /* send LVN_ITEMACTIVATE notification */
4757       nmh.code = LVN_ITEMACTIVATE;
4758       ListView_Notify(hwndParent, nCtrlId, &nmh);
4759     }
4760     break;
4761
4762   case VK_HOME:
4763     if (GETITEMCOUNT(infoPtr) > 0)
4764     {
4765       LISTVIEW_KeySelection(hwnd, 0); 
4766     }
4767     break;
4768
4769   case VK_END:
4770     if (GETITEMCOUNT(infoPtr) > 0)
4771     {
4772       LISTVIEW_KeySelection(hwnd, GETITEMCOUNT(infoPtr) - 1);
4773     }
4774     break;
4775
4776   case VK_LEFT:
4777     switch (LVS_TYPEMASK & lStyle)
4778     {
4779     case LVS_LIST:
4780       if (infoPtr->nFocusedItem >= infoPtr->nCountPerColumn) 
4781       {
4782         LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - infoPtr->nCountPerColumn);
4783       }
4784       break;
4785     case LVS_REPORT:
4786       break;
4787
4788     default:
4789       if (infoPtr->nFocusedItem % infoPtr->nCountPerRow != 0)
4790       {
4791         LISTVIEW_SetSelection(hwnd, infoPtr->nFocusedItem - 1); 
4792       }
4793     }
4794     break;
4795
4796   case VK_UP:
4797     switch (LVS_TYPEMASK & lStyle)
4798     {
4799     case LVS_LIST:
4800     case LVS_REPORT:
4801       if (infoPtr->nFocusedItem > 0)
4802       {
4803         LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - 1);
4804       }
4805       break;
4806
4807     default:
4808       if (infoPtr->nFocusedItem >= infoPtr->nCountPerRow)
4809       {
4810         LISTVIEW_SetSelection(hwnd, infoPtr->nFocusedItem - 
4811                               infoPtr->nCountPerRow);
4812       }
4813     }
4814     break;
4815     
4816   case VK_RIGHT:
4817     switch (LVS_TYPEMASK & lStyle)
4818     {
4819     case LVS_LIST:
4820       if (infoPtr->nFocusedItem < 
4821           (GETITEMCOUNT(infoPtr) - infoPtr->nCountPerColumn))
4822       {
4823         LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + 
4824                               infoPtr->nCountPerColumn);
4825       }
4826     case LVS_REPORT:
4827       break;
4828
4829     default:
4830       if (infoPtr->nCountPerRow > 0)
4831       {
4832       }
4833     }
4834     break;
4835
4836   case VK_DOWN:
4837     switch (LVS_TYPEMASK & lStyle)
4838     {
4839     case LVS_LIST:
4840     case LVS_REPORT:
4841       if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - 1)
4842       {
4843         LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + 1);
4844       }
4845     default:
4846       if (infoPtr->nCountPerRow > 0)
4847       {
4848       }
4849     }
4850     break;
4851
4852   case VK_PRIOR:
4853     break;
4854
4855   case VK_NEXT:
4856     break;
4857   }
4858
4859   /* refresh client area */
4860   InvalidateRect(hwnd, NULL, TRUE);
4861
4862   return 0;
4863 }
4864
4865 /***
4866  * DESCRIPTION:
4867  * Kills the focus.
4868  * 
4869  * PARAMETER(S):
4870  * [I] HWND : window handle
4871  *
4872  * RETURN:
4873  * Zero
4874  */
4875 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
4876 {
4877   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4878   INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4879   NMHDR nmh;
4880
4881   /* send NM_KILLFOCUS notification */
4882   nmh.hwndFrom = hwnd;
4883   nmh.idFrom = nCtrlId;
4884   nmh.code = NM_KILLFOCUS;
4885   ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
4886
4887   /* set window focus flag */
4888   infoPtr->bFocus = FALSE;
4889
4890   return 0;
4891 }
4892
4893 /***
4894  * DESCRIPTION:
4895  * Left mouse button double click.
4896  * 
4897  * PARAMETER(S):
4898  * [I] HWND : window handle
4899  * [I] WORD : key flag
4900  * [I] WORD : x coordinate
4901  * [I] WORD : y coordinate
4902  *
4903  * RETURN:
4904  * Zero
4905  */
4906 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX, 
4907                                       WORD wPosY)
4908 {
4909   LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4910   NMHDR nmh;
4911
4912   /* send NM_DBLCLK notification */
4913   nmh.hwndFrom = hwnd;
4914   nmh.idFrom = nCtrlId;
4915   nmh.code = NM_DBLCLK;
4916   ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
4917
4918   /* send LVN_ITEMACTIVATE notification */
4919   nmh.code = LVN_ITEMACTIVATE;
4920   ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
4921
4922   return 0;
4923 }
4924
4925 /***
4926  * DESCRIPTION:
4927  * Left mouse button down.
4928  * 
4929  * PARAMETER(S):
4930  * [I] HWND : window handle
4931  * [I] WORD : key flag
4932  * [I] WORD : x coordinate
4933  * [I] WORD : y coordinate
4934  *
4935  * RETURN:
4936  * Zero
4937  */
4938 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX, 
4939                                     WORD wPosY)
4940 {
4941   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4942   INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
4943   LVHITTESTINFO hitTestInfo;
4944   NMHDR nmh;
4945   INT nItem;
4946   static BOOL bGroupSelect = TRUE;
4947
4948   /* send NM_RELEASEDCAPTURE notification */ 
4949   nmh.hwndFrom = hwnd;
4950   nmh.idFrom = nCtrlId;
4951   nmh.code = NM_RELEASEDCAPTURE;
4952   ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
4953  
4954   if (infoPtr->bFocus == FALSE)
4955   {
4956     SetFocus(hwnd);
4957   }
4958
4959   /* set left button down flag */
4960   infoPtr->bLButtonDown = TRUE;
4961
4962   /* set left button hit coordinates */
4963   hitTestInfo.pt.x = wPosX;
4964   hitTestInfo.pt.y = wPosY;
4965   
4966   /* perform hit test */
4967   nItem = ListView_HitTest(hwnd, &hitTestInfo);
4968   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4969   {
4970     if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
4971     {
4972       if (bGroupSelect == TRUE)
4973       {
4974         LISTVIEW_AddGroupSelection(hwnd, nItem);
4975       }
4976       else
4977       {
4978         LISTVIEW_AddSelection(hwnd, nItem);
4979       }
4980     }
4981     else if (wKey & MK_CONTROL)
4982     {
4983       bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
4984     }
4985     else  if (wKey & MK_SHIFT)
4986     {
4987       LISTVIEW_SetGroupSelection(hwnd, nItem);
4988     }
4989     else
4990     {
4991       LISTVIEW_SetSelection(hwnd, nItem);
4992     }
4993   }
4994   else
4995   {
4996     /* remove all selections */
4997     LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
4998   }
4999
5000   InvalidateRect(hwnd, NULL, TRUE);
5001
5002   return 0;
5003 }
5004
5005 /***
5006  * DESCRIPTION:
5007  * Left mouse button up.
5008  * 
5009  * PARAMETER(S):
5010  * [I] HWND : window handle
5011  * [I] WORD : key flag
5012  * [I] WORD : x coordinate
5013  * [I] WORD : y coordinate
5014  *
5015  * RETURN:
5016  * Zero
5017  */
5018 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX, 
5019                                   WORD wPosY)
5020 {
5021   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5022   INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5023   NMHDR nmh;
5024
5025   if (infoPtr->bLButtonDown == TRUE) 
5026   {
5027     /* send NM_CLICK notification */
5028     nmh.hwndFrom = hwnd;
5029     nmh.idFrom = nCtrlId;
5030     nmh.code = NM_CLICK;
5031     ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5032
5033     /* set left button flag */
5034     infoPtr->bLButtonDown = FALSE;
5035   }
5036
5037   return 0;
5038 }
5039
5040 /***
5041  * DESCRIPTION:
5042  * Creates the listview control (called before WM_CREATE).
5043  * 
5044  * PARAMETER(S):
5045  * [I] HWND : window handle
5046  * [I] WPARAM : unhandled 
5047  * [I] LPARAM : widow creation info
5048  * 
5049  * RETURN:
5050  * Zero
5051  */
5052 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
5053 {
5054   LISTVIEW_INFO *infoPtr;
5055
5056   /* allocate memory for info structure */
5057   infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
5058   SetWindowLongA(hwnd, 0, (LONG)infoPtr);
5059   if (infoPtr == NULL) 
5060   {
5061     ERR(listview, "could not allocate info memory!\n");
5062     return 0;
5063   }
5064
5065   if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr) 
5066   {
5067     ERR(listview, "pointer assignment error!\n");
5068     return 0;
5069   }
5070
5071   return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
5072 }
5073
5074 /***
5075  * DESCRIPTION:
5076  * Destroys the listview control (called after WM_DESTROY).
5077  * 
5078  * PARAMETER(S):
5079  * [I] HWND : window handle
5080  * 
5081  * RETURN:
5082  * Zero
5083  */
5084 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
5085 {
5086   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5087
5088   /* free listview info */
5089   COMCTL32_Free(infoPtr);
5090
5091   return 0;
5092 }
5093
5094 /***
5095  * DESCRIPTION:
5096  * Handles notification from children.
5097  * 
5098  * PARAMETER(S):
5099  * [I] HWND : window handle
5100  * [I] INT : control identifier
5101  * [I] LPNMHDR : notification information
5102  * 
5103  * RETURN:
5104  * Zero
5105  */
5106 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
5107 {
5108   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5109   
5110   if (lpnmh->hwndFrom == infoPtr->hwndHeader) 
5111   {
5112     /* handle notification from header control */
5113     if (lpnmh->code == HDN_ENDTRACKA)
5114     {
5115       InvalidateRect(hwnd, NULL, TRUE);
5116     }
5117   }
5118
5119   return 0;
5120 }
5121
5122 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
5123 {
5124   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5125   
5126   if (nCommand == NF_REQUERY)
5127   {
5128     /* determine the type of structures to use */
5129     infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT, 
5130                                          (WPARAM)hwnd, (LPARAM)NF_QUERY);
5131     if (infoPtr->notifyFormat == NFR_UNICODE)
5132     {
5133       FIXME (listview, "NO support for unicode structures");
5134     }
5135   }
5136
5137   return 0;
5138 }
5139
5140 /***
5141  * DESCRIPTION:
5142  * Draws the listview control.
5143  * 
5144  * PARAMETER(S):
5145  * [I] HWND : window handle
5146  * [I] HDC : device context handle
5147  *
5148  * RETURN:
5149  * Zero
5150  */
5151 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
5152 {
5153   PAINTSTRUCT ps;
5154
5155   if (hdc == 0)
5156   {
5157     hdc = BeginPaint(hwnd, &ps);
5158     LISTVIEW_Refresh(hwnd, hdc);
5159     EndPaint(hwnd, &ps);
5160   }
5161   else
5162   {
5163     LISTVIEW_Refresh(hwnd, hdc);
5164   }
5165
5166   return 0;
5167 }
5168
5169 /***
5170  * DESCRIPTION:
5171  * Right mouse button double click.
5172  * 
5173  * PARAMETER(S):
5174  * [I] HWND : window handle
5175  * [I] WORD : key flag
5176  * [I] WORD : x coordinate
5177  * [I] WORD : y coordinate
5178  *
5179  * RETURN:
5180  * Zero
5181  */
5182 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX, 
5183                                       WORD wPosY)
5184 {
5185   INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5186   NMHDR nmh;
5187
5188   /* send NM_RELEASEDCAPTURE notification */ 
5189   nmh.hwndFrom = hwnd;
5190   nmh.idFrom = nCtrlId;
5191   nmh.code = NM_RELEASEDCAPTURE;
5192   ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5193
5194   /* send NM_RDBLCLK notification */
5195   nmh.code = NM_RDBLCLK;
5196   ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5197
5198   return 0;
5199 }
5200
5201 /***
5202  * DESCRIPTION:
5203  * Right mouse button input.
5204  * 
5205  * PARAMETER(S):
5206  * [I] HWND : window handle
5207  * [I] WORD : key flag
5208  * [I] WORD : x coordinate
5209  * [I] WORD : y coordinate
5210  *
5211  * RETURN:
5212  * Zero
5213  */
5214 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX, 
5215                                     WORD wPosY)
5216 {
5217   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5218   INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5219   LVHITTESTINFO hitTestInfo;
5220   NMHDR nmh;
5221   INT nItem;
5222
5223   /* send NM_RELEASEDCAPTURE notification */
5224   nmh.hwndFrom = hwnd;
5225   nmh.idFrom = nCtrlId;
5226   nmh.code = NM_RELEASEDCAPTURE;
5227   ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5228  
5229   /* make sure the listview control window has the focus */
5230   if (infoPtr->bFocus == FALSE)
5231   {
5232     SetFocus(hwnd);
5233   }
5234
5235   /* set right button down flag */
5236   infoPtr->bRButtonDown = TRUE;
5237
5238   /* set hit coordinates */
5239   hitTestInfo.pt.x = wPosX;
5240   hitTestInfo.pt.y = wPosY;
5241
5242   /* perform hit test */
5243   nItem = ListView_HitTest(hwnd, &hitTestInfo);
5244   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5245   {
5246     if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
5247     {
5248       LISTVIEW_SetSelection(hwnd, nItem);
5249     }
5250   }
5251   else
5252   {
5253     LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
5254   }
5255
5256   return 0;
5257 }
5258
5259 /***
5260  * DESCRIPTION:
5261  * Right mouse button up.
5262  * 
5263  * PARAMETER(S):
5264  * [I] HWND : window handle
5265  * [I] WORD : key flag
5266  * [I] WORD : x coordinate
5267  * [I] WORD : y coordinate
5268  *
5269  * RETURN:
5270  * Zero
5271  */
5272 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX, 
5273                                   WORD wPosY)
5274 {
5275   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5276   INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5277   NMHDR nmh;
5278
5279   if (infoPtr->bRButtonDown == TRUE) 
5280   {
5281     /* send NM_RClICK notification */
5282     ZeroMemory(&nmh, sizeof(NMHDR));
5283     nmh.hwndFrom = hwnd;
5284     nmh.idFrom = nCtrlId;
5285     nmh.code = NM_RCLICK;
5286     ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5287
5288     /* set button flag */
5289     infoPtr->bRButtonDown = FALSE;
5290   }
5291   
5292   return 0;
5293 }
5294
5295 /***
5296  * DESCRIPTION:
5297  * Sets the focus.  
5298  * 
5299  * PARAMETER(S):
5300  * [I] HWND : window handle
5301  * [I] HWND : window handle of previously focused window
5302  *
5303  * RETURN:
5304  * Zero
5305  */
5306 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
5307 {
5308   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5309   INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5310   NMHDR nmh;
5311
5312   /* send NM_SETFOCUS notification */
5313   nmh.hwndFrom = hwnd;
5314   nmh.idFrom = nCtrlId;
5315   nmh.code = NM_SETFOCUS;
5316   ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5317
5318   /* set window focus flag */
5319   infoPtr->bFocus = TRUE;
5320
5321   return 0;
5322 }
5323
5324 /***
5325  * DESCRIPTION:
5326  * Sets the font.  
5327  * 
5328  * PARAMETER(S):
5329  * [I] HWND : window handle
5330  * [I] HFONT : font handle
5331  * [I] WORD : redraw flag
5332  *
5333  * RETURN:
5334  * Zero
5335  */
5336 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
5337 {
5338   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5339   LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5340
5341   if (hFont == 0)
5342   {
5343     infoPtr->hFont = infoPtr->hDefaultFont;
5344   }
5345   else
5346   {
5347     infoPtr->hFont = hFont;
5348   }
5349
5350   if ((LVS_TYPEMASK & lStyle ) == LVS_REPORT)
5351   {
5352     /* set header font */
5353     SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont, 
5354                    MAKELPARAM(fRedraw, 0));
5355   }
5356
5357   /* invalidate listview control client area */
5358   InvalidateRect(hwnd, NULL, FALSE);
5359   
5360   if (fRedraw == TRUE)
5361   {
5362     UpdateWindow(hwnd);
5363   }
5364
5365   return 0;
5366 }
5367
5368 /***
5369  * DESCRIPTION:
5370  * Resizes the listview control.  
5371  * 
5372  * PARAMETER(S):
5373  * [I] HWND : window handle
5374  * [I] WORD : new width
5375  * [I] WORD : new height
5376  *
5377  * RETURN:
5378  * Zero
5379  */
5380 static LRESULT LISTVIEW_Size(HWND hwnd, WORD wWidth, WORD wHeight)
5381 {
5382   LISTVIEW_SetSize(hwnd, GetWindowLongA(hwnd, GWL_STYLE), wWidth, wHeight);
5383   LISTVIEW_SetViewInfo(hwnd);
5384   LISTVIEW_SetScroll(hwnd);
5385
5386   /* invalidate + erase background */
5387   InvalidateRect(hwnd, NULL, TRUE);
5388
5389   return 0;
5390 }
5391
5392 /***
5393  * DESCRIPTION:
5394  * Sets the size information for a given style.
5395  * 
5396  * PARAMETER(S):
5397  * [I] HWND : window handle
5398  * [I] LONG : window style
5399  * [I] WORD : new width
5400  * [I] WORD : new height
5401  *
5402  * RETURN:
5403  * Zero
5404  */
5405 static VOID LISTVIEW_SetSize(HWND hwnd, LONG lStyle, LONG lWidth, LONG lHeight)
5406 {
5407   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5408   HDLAYOUT hl;
5409   WINDOWPOS wp;
5410   INT lTop = 0;
5411   RECT rc;
5412
5413   switch (lStyle & LVS_TYPEMASK)
5414   {
5415   case LVS_LIST:
5416     if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
5417     {
5418       if (!(lStyle & WS_HSCROLL))
5419       {
5420         INT nHScrollHeight;
5421       
5422         nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
5423         if (lHeight > nHScrollHeight)
5424         { 
5425           lHeight -= nHScrollHeight;
5426         }
5427       }
5428     }
5429     break;
5430
5431   case LVS_REPORT:
5432     rc.left = 0;
5433     rc.top = 0;
5434     rc.right = lWidth;
5435     rc.bottom = lHeight;
5436     hl.prc = &rc;
5437     hl.pwpos = &wp;
5438     Header_Layout(infoPtr->hwndHeader, &hl);
5439     lTop = wp.cy;
5440     break;
5441   }
5442     
5443   infoPtr->rcList.top = lTop;
5444   infoPtr->rcList.left = 0;
5445   infoPtr->rcList.bottom = lHeight;
5446   infoPtr->rcList.right = lWidth;
5447 }
5448
5449 /***
5450  * DESCRIPTION:
5451  * Notification sent when the window style is modified.
5452  * 
5453  * PARAMETER(S):
5454  * [I] HWND : window handle
5455  * [I] WPARAM : window style type (normal or extended)
5456  * [I] LPSTYLESTRUCT : window style information
5457  *
5458  * RETURN:
5459  * Zero
5460  */
5461 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType, 
5462                                  LPSTYLESTRUCT lpss)
5463 {
5464   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5465   HDLAYOUT hl;
5466   WINDOWPOS wp;
5467   HDC hdc;
5468   RECT rc;
5469   HBRUSH hBrush;
5470
5471   if (wStyleType == GWL_STYLE)
5472   {
5473     /* remove vertical scrollbar */
5474     if (lpss->styleOld & WS_VSCROLL)
5475     {
5476       ShowScrollBar(hwnd, SB_VERT, FALSE);
5477     }
5478
5479     /* remove horizontal scrollbar */
5480     if (lpss->styleOld & WS_HSCROLL)
5481     {
5482       ShowScrollBar(hwnd, SB_HORZ, FALSE);
5483     }
5484
5485     if ((LVS_TYPEMASK & lpss->styleOld) == LVS_REPORT)
5486     {
5487       /* hide header */
5488       ShowWindow(infoPtr->hwndHeader, SW_HIDE);
5489     }
5490
5491     /* erase everything */
5492     GetClientRect(hwnd, &rc);
5493     hdc = GetDC(hwnd);
5494     hBrush = CreateSolidBrush(infoPtr->clrBk);
5495     FillRect(hdc, &rc, hBrush);
5496     DeleteObject(hBrush);
5497     ReleaseDC(hwnd, hdc);
5498
5499     if ((lpss->styleNew & LVS_TYPEMASK) == LVS_REPORT)
5500     {
5501       hl.prc = &rc;
5502       hl.pwpos = &wp;
5503       Header_Layout(infoPtr->hwndHeader, &hl);
5504       SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy, 
5505                    wp.flags);
5506       ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5507     }
5508     else if (((lpss->styleNew & LVS_TYPEMASK) == LVS_ICON) ||
5509              ((lpss->styleNew & LVS_TYPEMASK) == LVS_SMALLICON))
5510     {
5511       /* for NOW (it's only temporary) */
5512       SetWindowLongA(hwnd, GWL_STYLE, (lpss->styleNew&~LVS_TYPEMASK)|LVS_LIST);
5513     }
5514
5515     /* TEMPORARY */
5516     LISTVIEW_UnsupportedStyles(lpss->styleNew);
5517
5518     /* set new size */
5519     LISTVIEW_SetSize(hwnd, lpss->styleNew, rc.right, rc.bottom);
5520
5521     /* recalculate attributes */
5522     LISTVIEW_SetViewInfo(hwnd);
5523
5524     /* set scrollbars, if needed */
5525     LISTVIEW_SetScroll(hwnd);
5526     
5527     /* invalidate + erase background */
5528     InvalidateRect(hwnd, NULL, TRUE);
5529   }
5530
5531   return 0;
5532 }
5533
5534 /***
5535  * DESCRIPTION:
5536  * Window procedure of the listview control.
5537  * 
5538  * PARAMETER(S):
5539  * [I] HWND :
5540  * [I] UINT :
5541  * [I] WPARAM :
5542  * [I] LPARAM : 
5543  *
5544  * RETURN:
5545  * 
5546  */
5547 LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
5548                                    LPARAM lParam)
5549 {
5550   switch (uMsg)
5551   {
5552   case LVM_APPROXIMATEVIEWRECT: 
5553     return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam, 
5554                                         LOWORD(lParam), HIWORD(lParam));
5555   case LVM_ARRANGE: 
5556     return LISTVIEW_Arrange(hwnd, (INT)wParam);
5557
5558 /* case LVM_CREATEDRAGIMAGE: */
5559
5560   case LVM_DELETEALLITEMS:
5561     return LISTVIEW_DeleteAllItems(hwnd);
5562
5563   case LVM_DELETECOLUMN:
5564     return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
5565
5566   case LVM_DELETEITEM:
5567     return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
5568
5569 /*      case LVM_EDITLABEL: */
5570
5571   case LVM_ENSUREVISIBLE:
5572     return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
5573
5574   case LVM_FINDITEMA:
5575     return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
5576
5577   case LVM_GETBKCOLOR:
5578     return LISTVIEW_GetBkColor(hwnd);
5579
5580 /*      case LVM_GETBKIMAGE: */
5581
5582   case LVM_GETCALLBACKMASK:
5583     return LISTVIEW_GetCallbackMask(hwnd);
5584
5585   case LVM_GETCOLUMNA:
5586     return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
5587
5588 /*      case LVM_GETCOLUMNW: */
5589 /*      case LVM_GETCOLUMNORDERARRAY: */
5590
5591   case LVM_GETCOLUMNWIDTH:
5592     return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
5593
5594   case LVM_GETCOUNTPERPAGE:
5595     return LISTVIEW_GetCountPerPage(hwnd);
5596
5597 /*      case LVM_GETEDITCONTROL: */
5598 /*      case LVM_GETEXTENDEDLISTVIEWSTYLE: */
5599
5600   case LVM_GETHEADER:
5601     return LISTVIEW_GetHeader(hwnd);
5602
5603 /*      case LVM_GETHOTCURSOR: */
5604 /*      case LVM_GETHOTITEM: */
5605 /*      case LVM_GETHOVERTIME: */
5606
5607   case LVM_GETIMAGELIST:
5608     return LISTVIEW_GetImageList(hwnd, (INT)wParam);
5609
5610 /*      case LVM_GETISEARCHSTRING: */
5611
5612   case LVM_GETITEMA:
5613     return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam);
5614
5615 /*      case LVM_GETITEMW: */
5616
5617   case LVM_GETITEMCOUNT:
5618     return LISTVIEW_GetItemCount(hwnd);
5619
5620   case LVM_GETITEMPOSITION:
5621     return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
5622
5623   case LVM_GETITEMRECT: 
5624     return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
5625
5626   case LVM_GETITEMSPACING: 
5627     return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
5628
5629   case LVM_GETITEMSTATE: 
5630     return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
5631     
5632   case LVM_GETITEMTEXTA:
5633     LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
5634     break;
5635
5636 /*      case LVM_GETITEMTEXTW: */
5637
5638   case LVM_GETNEXTITEM:
5639     return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
5640
5641 /*      case LVM_GETNUMBEROFWORKAREAS: */
5642   case LVM_GETORIGIN:
5643     return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
5644
5645   case LVM_GETSELECTEDCOUNT:
5646     return LISTVIEW_GetSelectedCount(hwnd);
5647
5648   case LVM_GETSELECTIONMARK: 
5649     return LISTVIEW_GetSelectionMark(hwnd);
5650
5651   case LVM_GETSTRINGWIDTHA:
5652     return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
5653
5654 /*      case LVM_GETSTRINGWIDTHW: */
5655 /*      case LVM_GETSUBITEMRECT: */
5656
5657   case LVM_GETTEXTBKCOLOR:
5658     return LISTVIEW_GetTextBkColor(hwnd);
5659
5660   case LVM_GETTEXTCOLOR:
5661     return LISTVIEW_GetTextColor(hwnd);
5662
5663 /*      case LVM_GETTOOLTIPS: */
5664
5665   case LVM_GETTOPINDEX:
5666     return LISTVIEW_GetTopIndex(hwnd);
5667
5668 /*      case LVM_GETUNICODEFORMAT: */
5669
5670   case LVM_GETVIEWRECT:
5671     return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
5672
5673 /*      case LVM_GETWORKAREAS: */
5674
5675   case LVM_HITTEST:
5676     return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
5677
5678   case LVM_INSERTCOLUMNA:
5679     return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, 
5680                                     (LPLVCOLUMNA)lParam);
5681
5682 /*      case LVM_INSERTCOLUMNW: */
5683
5684   case LVM_INSERTITEMA:
5685     return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
5686
5687 /*      case LVM_INSERTITEMW: */
5688
5689   case LVM_REDRAWITEMS:
5690     return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
5691
5692   case LVM_SCROLL: 
5693     return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam);
5694
5695   case LVM_SETBKCOLOR:
5696     return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
5697
5698 /*      case LVM_SETBKIMAGE: */
5699
5700   case LVM_SETCALLBACKMASK:
5701     return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
5702
5703   case LVM_SETCOLUMNA:
5704     return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
5705
5706 /*      case LVM_SETCOLUMNW: */
5707 /*      case LVM_SETCOLUMNORDERARRAY: */
5708 /*      case LVM_SETCOLUMNWIDTH: */
5709 /*      case LVM_SETEXTENDEDLISTVIEWSTYLE: */
5710 /*      case LVM_SETHOTCURSOR: */
5711 /*      case LVM_SETHOTITEM: */
5712 /*      case LVM_SETHOVERTIME: */
5713 /*      case LVM_SETICONSPACING: */
5714         
5715   case LVM_SETIMAGELIST:
5716     return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
5717
5718   case LVM_SETITEMA:
5719     return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
5720
5721 /*      case LVM_SETITEMW: */
5722
5723   case LVM_SETITEMCOUNT: 
5724     LISTVIEW_SetItemCount(hwnd, (INT)wParam);
5725     break;
5726     
5727   case LVM_SETITEMPOSITION:
5728     return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
5729                                     (INT)HIWORD(lParam));
5730
5731 /*      case LVM_SETITEMPOSITION: */
5732
5733   case LVM_SETITEMSTATE: 
5734     return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
5735
5736   case LVM_SETITEMTEXTA:
5737     return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
5738
5739 /*      case LVM_SETSELECTIONMARK: */
5740
5741   case LVM_SETTEXTBKCOLOR:
5742     return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
5743
5744   case LVM_SETTEXTCOLOR:
5745     return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
5746
5747 /*      case LVM_SETTOOLTIPS: */
5748 /*      case LVM_SETUNICODEFORMAT: */
5749 /*      case LVM_SETWORKAREAS: */
5750
5751   case LVM_SORTITEMS:
5752     return LISTVIEW_SortItems(hwnd, wParam, lParam);
5753
5754 /*      case LVM_SUBITEMHITTEST: */
5755
5756   case LVM_UPDATE: 
5757     return LISTVIEW_Update(hwnd, (INT)wParam);
5758
5759 /*      case WM_CHAR: */
5760 /*      case WM_COMMAND: */
5761
5762   case WM_CREATE:
5763     return LISTVIEW_Create(hwnd, wParam, lParam);
5764     
5765   case WM_DESTROY:
5766     return LISTVIEW_Destroy(hwnd);
5767     
5768   case WM_ERASEBKGND:
5769     return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
5770
5771   case WM_GETDLGCODE:
5772     return DLGC_WANTTAB | DLGC_WANTARROWS;
5773
5774   case WM_GETFONT:
5775     return LISTVIEW_GetFont(hwnd);
5776
5777   case WM_HSCROLL:
5778     return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam), 
5779                             (INT)HIWORD(wParam), (HWND)lParam);
5780
5781   case WM_KEYDOWN:
5782     return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
5783
5784   case WM_KILLFOCUS:
5785     return LISTVIEW_KillFocus(hwnd);
5786
5787   case WM_LBUTTONDBLCLK:
5788     return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam), 
5789                                 HIWORD(lParam));
5790     
5791   case WM_LBUTTONDOWN:
5792     return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam), 
5793                                 HIWORD(lParam));
5794   case WM_LBUTTONUP:
5795     return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam), 
5796                               HIWORD(lParam));
5797     
5798 /*      case WM_MOUSEMOVE: */
5799 /*          return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
5800
5801   case WM_NCCREATE:
5802     return LISTVIEW_NCCreate(hwnd, wParam, lParam);
5803
5804   case WM_NCDESTROY:
5805     return LISTVIEW_NCDestroy(hwnd);
5806
5807   case WM_NOTIFY:
5808     return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
5809
5810   case WM_NOTIFYFORMAT:
5811     return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
5812
5813   case WM_PAINT: 
5814     return LISTVIEW_Paint(hwnd, (HDC)wParam); 
5815
5816   case WM_RBUTTONDBLCLK:
5817     return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam), 
5818                                   HIWORD(lParam));
5819
5820   case WM_RBUTTONDOWN:
5821     return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam), 
5822                                 HIWORD(lParam));
5823
5824   case WM_RBUTTONUP:
5825     return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam), 
5826                               HIWORD(lParam));
5827
5828   case WM_SETFOCUS:
5829     return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
5830
5831   case WM_SETFONT:
5832     return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
5833
5834 /*      case WM_SETREDRAW: */
5835
5836   case WM_SIZE:
5837     return LISTVIEW_Size(hwnd, LOWORD(lParam), HIWORD(lParam));
5838
5839   case WM_STYLECHANGED:
5840     return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
5841
5842 /*      case WM_TIMER: */
5843
5844   case WM_VSCROLL:
5845     return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam), 
5846                             (INT)HIWORD(wParam), (HWND)lParam);
5847
5848 /*      case WM_WINDOWPOSCHANGED: */
5849 /*      case WM_WININICHANGE: */
5850
5851   default:
5852     if (uMsg >= WM_USER)
5853     {
5854       ERR(listview, "unknown msg %04x wp=%08x lp=%08lx\n",
5855           uMsg, wParam, lParam);
5856     }
5857
5858     /* call default window procedure */
5859     return DefWindowProcA(hwnd, uMsg, wParam, lParam);
5860   }
5861
5862   return 0;
5863 }
5864
5865 /***
5866  * DESCRIPTION:`
5867  * Registers the window class.
5868  * 
5869  * PARAMETER(S):
5870  * None
5871  *
5872  * RETURN:
5873  * None
5874  */
5875 VOID LISTVIEW_Register(VOID)
5876 {
5877   WNDCLASSA wndClass;
5878
5879   if (!GlobalFindAtomA(WC_LISTVIEWA)) 
5880   {
5881     ZeroMemory(&wndClass, sizeof(WNDCLASSA));
5882     wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
5883     wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
5884     wndClass.cbClsExtra = 0;
5885     wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
5886     wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
5887     wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
5888     wndClass.lpszClassName = WC_LISTVIEWA;
5889     RegisterClassA (&wndClass);
5890   }
5891 }
5892
5893 /***
5894  * DESCRIPTION:
5895  * Unregisters the window class.
5896  * 
5897  * PARAMETER(S):
5898  * None
5899  *
5900  * RETURN:
5901  * None
5902  */
5903 VOID LISTVIEW_Unregister(VOID)
5904 {
5905   if (GlobalFindAtomA(WC_LISTVIEWA))
5906     UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
5907 }
5908