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