2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 #include <afs/param.h>
15 #define NO_DEBUG_ALLOC // Turn off memory-allocation instrumentation for this
21 #include <WINNT/fastlist.h>
22 #include <WINNT/subclass.h>
23 #include <WINNT/hashlist.h>
24 #include <WINNT/TaLocale.h>
28 * DEFINITIONS ________________________________________________________________
32 #define clrTRANSPARENT PALETTERGB(255,0,255)
34 typedef struct _FASTLISTITEM
42 HLISTITEM hTreeParent;
44 HLISTITEM hTreePrevious;
46 HLISTITEM hListPrevious;
48 HLISTITEM hSelectPrevious;
49 HLISTITEM hSelectNext;
59 } FASTLISTITEM, *LPFASTLISTITEM, LISTITEM, *LPLISTITEM;
62 // We over-allocate the aVisibleHeap[] array whenever it fills up,
63 // in order to perform fewer allocations. The allocation size
64 // defined by the macros below causes the following progression
67 // 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 24576, 32768, ...
69 #define cREALLOC_VISIBLEHEAP_MIN 128
70 #define cREALLOC_VISIBLEHEAP_MAX 4096
71 #define cREALLOC_VISIBLEHEAP(pfl) min(max(pfl->cVisibleHeap, cREALLOC_VISIBLEHEAP_MIN),cREALLOC_VISIBLEHEAP_MAX)
73 #define dwSigFASTLIST TEXT('FAST')
75 typedef struct FASTLIST
87 BOOL fSortBeforePaint;
88 BOOL fSyncScrollBeforePaint;
89 BOOL fSyncIndicesBeforePaint;
90 BOOL fRepaintRequired;
91 BOOL fSyncHeaderRequired;
95 LPFASTLISTTEXTCALLBACK pfnText;
97 LPFASTLISTSORTFUNC pfnSort;
100 HLISTITEM hEnsureVisible;
103 LPHASHLISTKEY lkUserParam;
104 HLISTITEM hTreeFirst;
105 HLISTITEM hListFirst;
106 HLISTITEM hSelectFirst;
115 HLISTITEM hHitOnDown;
116 BOOL fSelectedOnDown;
121 HLISTITEM *aVisibleHeap;
124 } FASTLIST, *LPFASTLIST;
128 * GLOBAL TO FASTLIST _________________________________________________________
132 static struct FASTLIST_GLOBAL
143 #define cREALLOC_OBJECTHEAP 512
147 * DISPLAY CONSTANTS __________________________________________________________
152 #define cxRECT(_r) ((_r).right - (_r).left)
156 #define cyRECT(_r) ((_r).bottom - (_r).top)
160 #define limit(_a,_x,_b) min(max((_x),(_a)),(_b))
164 #define DivRoundUp(_a,_b) (((_a) + (_b) -1) / (_b))
167 #define cyABOVE_LARGE_ICON 2
168 #define cyBELOW_LARGE_ICON 1
169 #define cyABOVE_LARGE_TEXT 1
170 #define cyBELOW_LARGE_TEXT 1
171 #define cxBEFORE_LARGE_TEXT 1
172 #define cxAFTER_LARGE_TEXT 2
174 #define cyABOVE_SMALL_TEXT 1
175 #define cyBELOW_SMALL_TEXT 1
176 #define cxBEFORE_SMALL_ICON 2
177 #define cxAFTER_SMALL_ICON 2
178 #define cxBEFORE_SMALL_TEXT 1
179 #define cxAFTER_SMALL_TEXT 2
181 #define cxBEFORE_LIST_ICON 2
182 #define cxAFTER_LIST_ICON 2
183 #define cyABOVE_LIST_TEXT 1
184 #define cyBELOW_LIST_TEXT 1
185 #define cxBETWEEN_LIST_ICONS 2
186 #define cxBEFORE_LIST_TEXT 1
187 #define cxAFTER_LIST_TEXT 4
188 #define cxBEFORE_COLUMN_TEXT 5
190 #define cxSPACE_TREELINE 2
191 #define cySPACE_TREELINE 2
195 #define TREELINE_HORIZONTAL 0x00000001
196 #define TREELINE_BOX 0x00000002
197 #define TREELINE_BOXOPEN (TREELINE_BOX)
198 #define TREELINE_BOXCLOSED (0x00000004 | TREELINE_BOX)
199 #define TREELINE_UP 0x00000008
200 #define TREELINE_DOWN 0x00000010
204 * VARIABLES __________________________________________________________________
210 * PROTOTYPES _________________________________________________________________
214 #define fIsShiftDown() (GetKeyState(VK_SHIFT) < 0)
215 #define fIsControlDown() (GetKeyState(VK_CONTROL) < 0)
217 BOOL OpenGlobalBitmap (HDC hdc, RECT *prClient);
218 void CloseGlobalBitmap (void);
220 BOOL OpenGlobalArray (size_t cObjects);
221 void CloseGlobalArray (void);
223 BOOL CALLBACK FastList_ControlProc (HWND hList, UINT msg, WPARAM wp, LPARAM lp);
224 BOOL CALLBACK FastList_ParentProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp);
226 void FastList_OnCreate (HWND hList);
227 void FastList_OnDestroy (HWND hList);
228 void FastList_OnStyleChange (HWND hList);
229 void FastList_OnSize (HWND hList);
230 void FastList_OnPaint (HWND hList);
231 void FastList_OnPaintItem (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi);
232 BOOL FastList_OnPaintItem_DrawImage (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, HIMAGELIST hil, int iImage, LONG xImage, LONG yImage, BOOL fHLines);
233 void FastList_OnPaintItem_GetItemColors (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, COLORREF *pclrFore, COLORREF *pclrBack);
234 void FastList_OnPaintItem_TreeLines (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, DWORD dwLines, RECT *prLines);
235 void FastList_OnPaintItem_Large (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi);
236 void FastList_OnPaintItem_Small (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi);
237 void FastList_OnPaintItem_Tree (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, HLISTITEM hItem, RECT *prThisColumn);
238 void FastList_OnPaintItem_List (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi);
239 void FastList_OnScroll (HWND hList, UINT msg, WPARAM wp, LPARAM lp);
240 void FastList_OnRightButtonDown (HWND hList);
241 void FastList_OnLeftButtonDown (HWND hList);
242 void FastList_OnLeftButtonDouble (HWND hList);
243 void FastList_OnKeyPress (HWND hList, TCHAR ch);
244 BOOL FastList_OnKeyPress_EnsureSelection (LPFASTLIST pfl);
245 void FastList_OnKeyPress_ChangeSelection (LPFASTLIST pfl, HLISTITEM hSelect);
247 void FastList_OnCommand_Begin (HWND hList);
248 void FastList_OnCommand_End (HWND hList, BOOL fForce);
249 HLISTITEM FastList_OnCommand_AddItem (HWND hList, LPFASTLISTADDITEM pai);
250 void FastList_OnCommand_RemoveItem (HWND hList, HLISTITEM hItem);
251 LPCTSTR FastList_OnCommand_GetItemText (HWND hList, HLISTITEM hItem, int iColumn);
252 void FastList_OnCommand_SetItemText (HWND hList, LPFASTLISTITEMCOLUMN pflic, LPCTSTR pszText);
253 LPARAM FastList_OnCommand_GetItemParam (HWND hList, HLISTITEM hItem);
254 void FastList_OnCommand_SetItemParam (HWND hList, HLISTITEM hItem, LPARAM lpUser);
255 DWORD FastList_OnCommand_GetItemFlags (HWND hList, HLISTITEM hItem);
256 void FastList_OnCommand_SetItemFlags (HWND hList, HLISTITEM hItem, DWORD dwFlags);
257 int FastList_OnCommand_GetItemImage (HWND hList, HLISTITEM hItem, int iImage);
258 void FastList_OnCommand_SetItemImage (HWND hList, LPFASTLISTITEMIMAGE pflii, int iImage);
259 void FastList_OnCommand_GetImageLists (HWND hList, HIMAGELIST *phiSmall, HIMAGELIST *phiLarge);
260 void FastList_OnCommand_SetImageLists (HWND hList, HIMAGELIST hiSmall, HIMAGELIST hiLarge);
261 HIMAGELIST FastList_OnCommand_CreateDragImage (HWND hList, HLISTITEM hItem);
262 LPFASTLISTSORTFUNC FastList_OnCommand_GetSortFunc (HWND hList);
263 void FastList_OnCommand_SetSortFunc (HWND hList, LPFASTLISTSORTFUNC pfn);
264 void FastList_OnCommand_GetSortStyle (HWND hList, int *piColSort, BOOL *pfRevSort);
265 void FastList_OnCommand_SetSortStyle (HWND hList, int iColSort, BOOL fRevSort);
266 void FastList_OnCommand_Sort (HWND hList);
267 int FastList_OnCommand_GetColumnCount (HWND hList);
268 BOOL FastList_OnCommand_GetColumn (HWND hList, int iColumn, LPFASTLISTCOLUMN pcol);
269 void FastList_OnCommand_SetColumn (HWND hList, int iColumn, LPFASTLISTCOLUMN pcol);
270 BOOL FastList_OnCommand_IsSelected (HWND hList, HLISTITEM hItem);
271 void FastList_OnCommand_SelectItem (HWND hList, HLISTITEM hItem, BOOL fSelect);
272 HLISTITEM FastList_OnCommand_FindList (HWND hList, HLISTITEM hItem, DWORD dwCode);
273 HLISTITEM FastList_OnCommand_FindTree (HWND hList, HLISTITEM hItem, DWORD dwCode);
274 HLISTITEM FastList_OnCommand_FindSelected (HWND hList, HLISTITEM hItem);
275 HLISTITEM FastList_OnCommand_FindItem (HWND hList, LPENUM *ppEnum, LPARAM lpUser);
276 HLISTITEM FastList_OnCommand_FindNextItem (HWND hList, LPENUM *ppEnum);
277 HLISTITEM FastList_OnCommand_FindVisible (HWND hList, HLISTITEM hItem, DWORD dwCode);
278 void FastList_OnCommand_FindClose (HWND hList, LPENUM *ppEnum);
279 int FastList_OnCommand_GetItemCount (HWND hList, BOOL fVisibleOnly);
280 BOOL FastList_OnCommand_IsExpanded (HWND hList, HLISTITEM hItem);
281 void FastList_OnCommand_Expand (HWND hList, HLISTITEM hItem, BOOL fExpand);
282 BOOL FastList_OnCommand_ItemVisible (HWND hList, HLISTITEM hItem, BOOL fSet);
283 HLISTITEM FastList_OnCommand_ItemFocus (HWND hList, HLISTITEM hItem, BOOL fSet);
284 HLISTITEM FastList_OnCommand_ItemFromPoint (HWND hList, POINT *pptClient, BOOL fStrict);
285 void FastList_OnCommand_GetItemRegions (HWND hList, HLISTITEM hItem, LPFASTLISTITEMREGIONS pReg, POINT *pptTest = NULL, BOOL *pfHit = NULL);
286 LPFASTLISTTEXTCALLBACK FastList_OnCommand_GetTextCallback (HWND hList);
287 void FastList_OnCommand_SetTextCallback (HWND hList, LPFASTLISTTEXTCALLBACK pfn, DWORD dwCookie);
289 BOOL FastList_Notify_GetItemText (LPFASTLIST pfl, HLISTITEM hItem, int icol, LPTSTR pszText, size_t cchText, size_t *pcchRequired);
290 BOOL FastList_Notify_ItemChanged (LPFASTLIST pfl, HLISTITEM hItem);
291 BOOL FastList_Notify_AddItem (LPFASTLIST pfl, HLISTITEM hItem);
292 BOOL FastList_Notify_RemoveItem (LPFASTLIST pfl, HLISTITEM hItem);
293 BOOL FastList_Notify_ColumnClick (LPFASTLIST pfl, int icol, BOOL fDouble);
294 BOOL FastList_Notify_ColumnResize (LPFASTLIST pfl, int icol, LONG cxWidth);
295 BOOL FastList_Notify_ItemSelect (LPFASTLIST pfl);
296 BOOL FastList_Notify_ItemExpand (LPFASTLIST pfl, HLISTITEM hItem);
297 BOOL FastList_Notify_Generic (LPFASTLIST pfl, DWORD dwCode);
298 BOOL FastList_Notify_Drag (LPFASTLIST pfl, DWORD dwCode, LPFLN_DRAG_PARAMS pfln);
300 void FastList_Repaint (LPFASTLIST pfl);
301 HLISTITEM FastList_CreateItem (LPFASTLIST pfl);
302 void FastList_DeleteItem (LPFASTLIST pfl, HLISTITEM hItem);
303 int FastList_GetListHeight (LPFASTLIST pfl);
304 int FastList_GetListWidth (LPFASTLIST pfl);
305 void FastList_CalcItemRect (LPFASTLIST pfl, int index, RECT *prItem, BOOL fScrollH, BOOL fScrollV);
306 void FastList_CalcFieldSize (LPFASTLIST pfl, LONG *pcxField, LONG *pcyField, BOOL fScrollH, BOOL fScrollV);
307 void FastList_GetHeaderRect (LPFASTLIST pfl, RECT *prHeader);
308 LONG FastList_GetHeaderHeight (LPFASTLIST pfl);
309 void FastList_UpdateColumn (LPFASTLIST pfl, int iColumn);
310 void FastList_SyncHeader (LPFASTLIST pfl);
311 void FastList_SyncScroll (LPFASTLIST pfl);
312 void FastList_SyncScrollPos (LPFASTLIST pfl);
313 void FastList_CallPaintItem (LPFASTLIST pfl, HDC hdc, BOOL fDraw, BOOL fDragImage, int iItem, RECT *prItem, LPFASTLISTITEMREGIONS pReg, POINT *pptTest, BOOL *pfHit);
314 LPTSTR FastList_GetColumnText (LPFASTLIST pfl, HLISTITEM hItem, int icol, BOOL fAlternateBuffer = FALSE);
315 void FastList_PerformSort (LPFASTLIST pfl);
316 void FastList_PerformSortLevel (LPFASTLIST pfl, HLISTITEM hParent, BOOL fTreeSort);
317 int __cdecl FastList_SortFunction (const void *lp1, const void *lp2);
318 void FastList_RepairOneVisibilityFlag (LPFASTLIST pfl, HLISTITEM hItem);
319 void FastList_RepairVisibilityFlags (LPFASTLIST pfl, HLISTITEM hParent = NULL, BOOL fForceHidden = FALSE);
320 void FastList_RepairVisibilityIndices (LPFASTLIST pfl, HLISTITEM hParent = NULL);
321 void FastList_ScrollHeader (LPFASTLIST pfl);
322 void FastList_PerformSelectTest (LPFASTLIST pfl, HLISTITEM hItem);
323 void FastList_PerformSelectItem (LPFASTLIST pfl, HLISTITEM hItem, BOOL fSelect);
324 void FastList_PerformSelectRange (LPFASTLIST pfl, HLISTITEM hItem1, HLISTITEM hItem2);
325 void FastList_PerformEnsureVisible (LPFASTLIST pfl);
326 void FastList_ButtonDown (HWND hList, BOOL fRightButton, BOOL fActivate);
327 void FastList_MouseMove (HWND hList);
328 void FastList_ButtonUp (HWND hList, BOOL fRightButton, BOOL fActivate);
330 LPFASTLIST GetFastList (HWND hList);
332 BOOL CALLBACK FastList_KeyUserParam_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData);
333 HASHVALUE CALLBACK FastList_KeyUserParam_HashObject (LPHASHLISTKEY pKey, PVOID pObject);
334 HASHVALUE CALLBACK FastList_KeyUserParam_HashData (LPHASHLISTKEY pKey, PVOID pData);
338 * REALLOC ____________________________________________________________________
345 #define REALLOC(_a,_c,_r,_i) FastList_ReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
346 BOOL FastList_ReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
351 if (cReq <= *pcTarget)
354 if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
357 if ((pNew = (LPVOID)Allocate (cbElement * cNew)) == NULL)
359 memset (pNew, 0x00, cbElement * cNew);
363 memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
374 * WINDOW CLASS SUPPORT _______________________________________________________
378 BOOL RegisterFastListClass (void)
380 static BOOL fRegistered = FALSE;
384 memset (&fg, 0x00, sizeof(fg));
385 InitializeCriticalSection (&fg.cs);
388 GetClassInfo (THIS_HINST, TEXT("LISTBOX"), &wc);
389 wc.style = CS_GLOBALCLASS | CS_DBLCLKS;
391 wc.lpfnWndProc = (WNDPROC)FastList_ControlProc;
392 wc.hInstance = THIS_HINST;
393 wc.hCursor = LoadCursor (NULL, MAKEINTRESOURCE (IDC_ARROW));
394 wc.hbrBackground = NULL;
395 wc.lpszClassName = WC_FASTLIST;
397 if (RegisterClass (&wc))
405 BOOL OpenGlobalBitmap (HDC hdc, RECT *prClient)
407 EnterCriticalSection (&fg.cs);
409 if ((!fg.bmp) || (fg.cxBmp < prClient->right) || (fg.cyBmp < prClient->bottom))
412 DeleteObject (fg.bmp);
414 fg.cxBmp = 128 * DivRoundUp (prClient->right, 128);
415 fg.cyBmp = 64 * DivRoundUp (prClient->bottom, 64);
416 fg.bmp = CreateCompatibleBitmap (hdc, fg.cxBmp, fg.cyBmp);
421 LeaveCriticalSection (&fg.cs);
429 void CloseGlobalBitmap (void)
431 LeaveCriticalSection (&fg.cs);
435 BOOL OpenGlobalArray (size_t cObjects)
437 EnterCriticalSection (&fg.cs);
438 REALLOC (fg.aObjects, fg.cObjects, cObjects, cREALLOC_OBJECTHEAP);
439 memset (fg.aObjects, 0x00, sizeof(HLISTITEM) * fg.cObjects);
444 void CloseGlobalArray (void)
446 LeaveCriticalSection (&fg.cs);
450 BOOL CALLBACK FastList_ControlProc (HWND hList, UINT msg, WPARAM wp, LPARAM lp)
455 FastList_OnCreate (hList);
456 if (GetParent (hList))
457 Subclass_AddHook (GetParent (hList), FastList_ParentProc);
461 if (GetParent (hList))
462 Subclass_RemoveHook (GetParent (hList), FastList_ParentProc);
463 FastList_OnDestroy (hList);
467 return DLGC_WANTARROWS;
469 case WM_STYLECHANGED:
470 FastList_OnStyleChange (hList);
474 FastList_Repaint (GetFastList (hList));
478 FastList_OnSize (hList);
482 FastList_OnPaint (hList);
486 FastList_OnLeftButtonDown (hList);
490 FastList_OnRightButtonDown (hList);
494 FastList_ButtonUp (hList, FALSE, FALSE);
498 FastList_ButtonUp (hList, TRUE, FALSE);
502 FastList_MouseMove (hList);
505 case WM_LBUTTONDBLCLK:
506 FastList_OnLeftButtonDouble (hList);
510 FastList_OnKeyPress (hList, (TCHAR)wp);
514 switch (((NMHDR*)lp)->code)
517 FastList_Notify_ColumnClick (GetFastList (hList), ((HD_NOTIFY*)lp)->iItem, FALSE);
520 case HDN_ITEMDBLCLICK:
521 FastList_Notify_ColumnClick (GetFastList (hList), ((HD_NOTIFY*)lp)->iItem, TRUE);
524 case HDN_ITEMCHANGED:
527 FastList_UpdateColumn (GetFastList (hList), ((HD_NOTIFY*)lp)->iItem);
534 FastList_OnScroll (hList, msg, wp, lp);
538 FastList_OnCommand_Begin (hList);
542 FastList_OnCommand_End (hList, (BOOL)wp);
546 return (BOOL)FastList_OnCommand_AddItem (hList, (LPFASTLISTADDITEM)lp);
549 FastList_OnCommand_RemoveItem (hList, (HLISTITEM)wp);
552 case FLM_GETITEMTEXT:
553 return (BOOL)FastList_OnCommand_GetItemText (hList, (HLISTITEM)wp, (int)lp);
555 case FLM_SETITEMTEXT:
556 FastList_OnCommand_SetItemText (hList, (LPFASTLISTITEMCOLUMN)wp, (LPCTSTR)lp);
559 case FLM_GETITEMPARAM:
560 return (BOOL)FastList_OnCommand_GetItemParam (hList, (HLISTITEM)wp);
562 case FLM_SETITEMPARAM:
563 FastList_OnCommand_SetItemParam (hList, (HLISTITEM)wp, lp);
566 case FLM_GETITEMFLAGS:
567 return (BOOL)FastList_OnCommand_GetItemFlags (hList, (HLISTITEM)wp);
569 case FLM_SETITEMFLAGS:
570 FastList_OnCommand_SetItemFlags (hList, (HLISTITEM)wp, (DWORD)lp);
573 case FLM_GETITEMIMAGE:
574 return (BOOL)FastList_OnCommand_GetItemImage (hList, (HLISTITEM)wp, (int)lp);
576 case FLM_SETITEMIMAGE:
577 FastList_OnCommand_SetItemImage (hList, (LPFASTLISTITEMIMAGE)wp, (int)lp);
581 return (BOOL)FastList_OnCommand_IsExpanded (hList, (HLISTITEM)wp);
584 FastList_OnCommand_Expand (hList, (HLISTITEM)wp, (BOOL)lp);
587 case FLM_ITEMVISIBLE:
588 return (BOOL)FastList_OnCommand_ItemVisible (hList, (HLISTITEM)wp, (BOOL)lp);
591 return (BOOL)FastList_OnCommand_ItemFocus (hList, (HLISTITEM)wp, (BOOL)lp);
593 case FLM_GETIMAGELISTS:
594 FastList_OnCommand_GetImageLists (hList, (HIMAGELIST*)wp, (HIMAGELIST*)lp);
597 case FLM_SETIMAGELISTS:
598 FastList_OnCommand_SetImageLists (hList, (HIMAGELIST)wp, (HIMAGELIST)lp);
601 case FLM_CREATEDRAGIMAGE:
602 return (BOOL)FastList_OnCommand_CreateDragImage (hList, (HLISTITEM)wp);
604 case FLM_GETSORTFUNC:
605 return (BOOL)FastList_OnCommand_GetSortFunc (hList);
607 case FLM_SETSORTFUNC:
608 FastList_OnCommand_SetSortFunc (hList, (LPFASTLISTSORTFUNC)lp);
611 case FLM_GETSORTSTYLE:
612 FastList_OnCommand_GetSortStyle (hList, (int*)wp, (BOOL*)lp);
615 case FLM_SETSORTSTYLE:
616 FastList_OnCommand_SetSortStyle (hList, (int)wp, (BOOL)lp);
620 FastList_OnCommand_Sort (hList);
623 case FLM_GETCOLUMNCOUNT:
624 return (BOOL)FastList_OnCommand_GetColumnCount (hList);
627 return FastList_OnCommand_GetColumn (hList, (int)wp, (LPFASTLISTCOLUMN)lp);
630 FastList_OnCommand_SetColumn (hList, (int)wp, (LPFASTLISTCOLUMN)lp);
634 return (BOOL)FastList_OnCommand_IsSelected (hList, (HLISTITEM)wp);
637 FastList_OnCommand_SelectItem (hList, (HLISTITEM)wp, (BOOL)lp);
641 return (BOOL)FastList_OnCommand_FindList (hList, (HLISTITEM)wp, (DWORD)lp);
644 return (BOOL)FastList_OnCommand_FindTree (hList, (HLISTITEM)wp, (DWORD)lp);
646 case FLM_FINDSELECTED:
647 return (BOOL)FastList_OnCommand_FindSelected (hList, (HLISTITEM)wp);
650 return (BOOL)FastList_OnCommand_FindItem (hList, (LPENUM*)wp, lp);
652 case FLM_FINDNEXTITEM:
653 return (BOOL)FastList_OnCommand_FindNextItem (hList, (LPENUM*)wp);
656 FastList_OnCommand_FindClose (hList, (LPENUM*)wp);
659 case FLM_FINDVISIBLE:
660 return (BOOL)FastList_OnCommand_FindVisible (hList, (HLISTITEM)wp, (DWORD)lp);
662 case FLM_GETITEMCOUNT:
663 return (BOOL)FastList_OnCommand_GetItemCount (hList, (BOOL)wp);
665 case FLM_ITEMFROMPOINT:
666 return (BOOL)FastList_OnCommand_ItemFromPoint (hList, (POINT*)wp, (BOOL)lp);
668 case FLM_GETITEMREGIONS:
669 FastList_OnCommand_GetItemRegions (hList, (HLISTITEM)wp, (LPFASTLISTITEMREGIONS)lp);
672 case FLM_GETTEXTCALLBACK:
673 return (BOOL)FastList_OnCommand_GetTextCallback (hList);
675 case FLM_SETTEXTCALLBACK:
676 FastList_OnCommand_SetTextCallback (hList, (LPFASTLISTTEXTCALLBACK)wp, (DWORD)lp);
680 return DefWindowProc (hList, msg, wp, lp);
684 BOOL CALLBACK FastList_ParentProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
686 PVOID oldProc = Subclass_FindNextHook (hDlg, FastList_ParentProc);
692 if ((pfl = GetFastList (GetDlgItem (hDlg, wp))) != NULL)
694 FastList_OnPaintItem (pfl, (LPFASTLISTDRAWITEM)lp);
700 if ((pfl = GetFastList (GetDlgItem (hDlg, wp))) != NULL)
702 switch (((NMHDR*)lp)->code)
704 case FLN_COLUMNCLICK:
705 if (pfl->dwStyle & FLS_AUTOSORTHEADER)
707 LPFLN_COLUMNCLICK_PARAMS pp = (LPFLN_COLUMNCLICK_PARAMS)lp;
709 if (pfl->iColSort == pp->icol)
710 FastList_SetSortStyle (pfl->hList, pp->icol, !pfl->fRevSort);
712 FastList_SetSortStyle (pfl->hList, pp->icol, FALSE);
720 return CallWindowProc ((WNDPROC)oldProc, hDlg, msg, wp, lp);
725 * MESSAGE HANDLING ___________________________________________________________
729 void FastList_OnCreate (HWND hList)
731 LPFASTLIST pfl = New (FASTLIST);
732 memset (pfl, 0x00, sizeof(FASTLIST));
733 SetWindowLong (hList, 0, (LONG)pfl);
736 pfl->dwCookieText = 0;
738 InitializeCriticalSection (&pfl->cs);
739 pfl->dwSig = dwSigFASTLIST;
741 pfl->dwStyle = GetWindowLong (hList, GWL_STYLE);
742 pfl->hf = (HFONT)GetStockObject (DEFAULT_GUI_FONT);
744 pfl->lItems = New (HASHLIST);
745 pfl->lItems->SetCriticalSection (&pfl->cs);
746 pfl->lkUserParam = pfl->lItems->CreateKey ("User Param", FastList_KeyUserParam_Compare, FastList_KeyUserParam_HashObject, FastList_KeyUserParam_HashData);
748 FastList_Begin (pfl->hList);
750 if (!(pfl->dwStyle & WS_CLIPCHILDREN))
751 SetWindowLong (pfl->hList, GWL_STYLE, pfl->dwStyle | WS_CLIPCHILDREN);
753 FastList_SyncHeader (pfl);
754 FastList_Repaint (pfl);
755 FastList_End (pfl->hList);
759 void FastList_OnDestroy (HWND hList)
762 if ((pfl = GetFastList (hList)) != NULL)
765 DestroyWindow (pfl->hHeader);
767 DestroyWindow (pfl->hScrollH);
769 DestroyWindow (pfl->hScrollV);
770 if (pfl->aVisibleHeap)
771 Free (pfl->aVisibleHeap);
774 for (size_t iColumn = 0; iColumn < pfl->cColumns; ++iColumn)
775 if (pfl->aColumns[ iColumn ].pszText)
776 Free (pfl->aColumns[ iColumn ].pszText);
777 Free (pfl->aColumns);
779 DeleteObject (pfl->hf);
780 Delete (pfl->lItems);
781 DeleteCriticalSection (&pfl->cs);
782 SetWindowLong (hList, 0, 0);
788 void FastList_OnStyleChange (HWND hList)
791 if ((pfl = GetFastList (hList)) != NULL)
793 BOOL fWasTree = ((pfl->dwStyle & FLS_VIEW_TREE) == FLS_VIEW_TREE) ? TRUE : FALSE;
795 pfl->dwStyle = GetWindowLong (hList, GWL_STYLE);
797 BOOL fIsTree = ((pfl->dwStyle & FLS_VIEW_TREE) == FLS_VIEW_TREE) ? TRUE : FALSE;
798 if (fWasTree != fIsTree)
800 FastList_RepairVisibilityFlags (pfl);
801 pfl->fSortBeforePaint = TRUE;
804 FastList_SyncHeader (pfl);
805 FastList_Repaint (pfl);
810 void FastList_OnSize (HWND hList)
813 if ((pfl = GetFastList (hList)) != NULL)
815 FastList_SyncHeader (pfl);
816 FastList_Repaint (pfl);
821 void FastList_OnPaint (HWND hList)
824 if ((pfl = GetFastList (hList)) != NULL)
828 pfl->fRepaintRequired = TRUE;
830 else // (!pfl->nBegin)
832 if (pfl->fSortBeforePaint)
833 FastList_PerformSort (pfl);
834 if (pfl->fSyncIndicesBeforePaint)
835 FastList_RepairVisibilityIndices (pfl);
836 if (pfl->fSyncScrollBeforePaint)
837 FastList_SyncScroll (pfl);
838 if (pfl->hEnsureVisible)
839 FastList_PerformEnsureVisible (pfl);
843 HDC hdc = BeginPaint (hList, &ps);
845 // If we're showing both scrollbars, grey-wash the rectangle
846 // in the bottom-right where they meet.
848 if ((pfl->hScrollH) && (pfl->hScrollV))
851 GetClientRect (pfl->hList, &rBox);
852 rBox.left = rBox.right - GetSystemMetrics(SM_CXVSCROLL);
853 rBox.top = rBox.bottom - GetSystemMetrics(SM_CYHSCROLL);
855 HBRUSH hbr = CreateSolidBrush (GetSysColor (COLOR_BTNFACE));
856 FillRect (hdc, &rBox, hbr);
860 // Just what client area is left, after we skip the scrollbar and
864 GetClientRect (pfl->hList, &rClient);
866 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
868 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
870 rClient.top += FastList_GetHeaderHeight (pfl);
872 // If possible, we want to draw onto an off-screen bitmap then blit
873 // the relevant sections onto the client area; this eliminates flicker
874 // as items are erased and redrawn.
877 HBITMAP bmpTargetOld = NULL;
880 if ((fDoubleBuffer = OpenGlobalBitmap (hdc, &rClient)) == TRUE)
882 hdcTarget = CreateCompatibleDC (hdc);
883 bmpTargetOld = (HBITMAP)SelectObject (hdcTarget, fg.bmp);
886 HFONT hfOld = (HFONT)SelectObject (hdcTarget, pfl->hf);
888 // Determine which objects we can display on the screen, and paint
889 // each in turn. If there is no object at a particular location,
890 // just white- or grey-fill the background.
893 FastList_CalcItemRect (pfl, 0, &rTemplate, !!pfl->hScrollH, !!pfl->hScrollV);
895 HBRUSH hbrBackground = CreateSolidBrush (GetSysColor( (IsWindowEnabled(pfl->hList)) ? COLOR_WINDOW : COLOR_BTNFACE ));
896 FillRect (hdcTarget, &rClient, hbrBackground);
900 switch (pfl->dwStyle & FLS_VIEW_MASK)
904 // In Large mode, icons are stacked left-to-right, top-to-bottom.
905 // Find the top index, and for each vertical index thereafter,
906 // find and paint the relevant horizontal indices.
908 LONG cxItems = cxRECT(rClient) / cxRECT(rTemplate);
910 LONG iyTopItem = pfl->dyPixel / cyRECT(rTemplate);
911 LONG iyBottomItem = iyTopItem + DivRoundUp (cyRECT(rClient), cyRECT(rTemplate));
913 for (LONG iyItem = iyTopItem; iyItem <= iyBottomItem; ++iyItem)
915 for (LONG ixItem = 0; ixItem < cxItems; ++ixItem)
917 int iItem = (int)( ixItem + cxItems * iyItem );
918 if (iItem < (int)pfl->cVisible)
921 rItem.top = rClient.top + iyItem * cyRECT(rTemplate) - pfl->dyPixel;
922 rItem.bottom = rItem.top + cyRECT(rTemplate);
923 rItem.left = rClient.left + ixItem * cxRECT(rTemplate) - pfl->dxPixel;
924 rItem.right = rItem.left + cxRECT(rTemplate);
926 FastList_CallPaintItem (pfl, hdcTarget, TRUE, FALSE, iItem, &rItem, NULL, NULL, NULL);
935 // In Small mode, icons are stacked top-to-bottom, left-to-right.
936 // Find the left index, and for each horizontal index thereafter,
937 // find and paint the relevant vertical indices.
939 LONG cyItems = cyRECT(rClient) / cyRECT(rTemplate);
941 LONG ixLeftItem = pfl->dxPixel / cxRECT(rTemplate);
942 LONG ixRightItem = ixLeftItem + DivRoundUp (cxRECT(rClient), cxRECT(rTemplate));
944 for (LONG ixItem = ixLeftItem; ixItem <= ixRightItem; ++ixItem)
946 for (LONG iyItem = 0; iyItem < cyItems; ++iyItem)
948 int iItem = (int)( iyItem + cyItems * ixItem );
949 if (iItem < (int)pfl->cVisible)
952 rItem.top = rClient.top + iyItem * cyRECT(rTemplate) - pfl->dyPixel;
953 rItem.bottom = rItem.top + cyRECT(rTemplate);
954 rItem.left = rClient.left + ixItem * cxRECT(rTemplate) - pfl->dxPixel;
955 rItem.right = rItem.left + cxRECT(rTemplate);
957 FastList_CallPaintItem (pfl, hdcTarget, TRUE, FALSE, iItem, &rItem, NULL, NULL, NULL);
966 case FLS_VIEW_TREELIST:
968 // In these modes, icons are stacked top-to-bottom; each takes
969 // the entire width we can give it. Find the top index, and
970 // paint all indices which fit on the screen.
972 LONG iTopItem = pfl->dyPixel / cyRECT(rTemplate);
973 LONG iBottomItem = iTopItem + DivRoundUp (cyRECT(rClient), cyRECT(rTemplate));
975 for (LONG iItem = iTopItem; iItem <= iBottomItem; ++iItem)
977 if (iItem < (int)pfl->cVisible)
980 rItem.top = rClient.top + iItem * cyRECT(rTemplate) - pfl->dyPixel;
981 rItem.bottom = rItem.top + cyRECT(rTemplate);
982 rItem.left = rClient.left - pfl->dxPixel;
983 rItem.right = rItem.left + cxRECT(rTemplate);
985 FastList_CallPaintItem (pfl, hdcTarget, TRUE, FALSE, iItem, &rItem, NULL, NULL, NULL);
995 BitBlt (hdc, rClient.left, rClient.top, cxRECT(rClient), cyRECT(rClient),
996 hdcTarget, rClient.left, rClient.top, SRCCOPY);
997 SelectObject (hdcTarget, bmpTargetOld);
998 DeleteDC (hdcTarget);
1002 DeleteObject (hbrBackground);
1003 SelectObject (hdcTarget, hfOld);
1004 EndPaint (hList, &ps);
1009 void FastList_OnPaintItem (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi)
1011 // Initialize the output FASTLISTITEMREGIONS structure.
1012 // We were given the object's overall rectangle, and will
1013 // calculate each of the other regions as we go along.
1015 memset (&pdi->reg, 0x00, sizeof(pdi->reg));
1016 pdi->reg.rItem = pdi->rItem;
1017 pdi->fTextTestHit = FALSE;
1019 // The actual paint routine we'll use depends on the current view.
1021 switch (pfl->dwStyle & FLS_VIEW_MASK)
1023 case FLS_VIEW_LARGE:
1024 FastList_OnPaintItem_Large (pfl, pdi);
1027 case FLS_VIEW_SMALL:
1028 FastList_OnPaintItem_Small (pfl, pdi);
1033 case FLS_VIEW_TREELIST:
1034 FastList_OnPaintItem_List (pfl, pdi);
1038 UnionRect (&pdi->reg.rSelect, &pdi->reg.rHighlight, &pdi->reg.rImage);
1042 void FastList_OnPaintItem_TreeLines (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, DWORD dwLines, RECT *prThisColumn)
1044 if (prThisColumn->left >= prThisColumn->right)
1048 rLines.left = prThisColumn->left;
1049 rLines.right = rLines.left +GetSystemMetrics(SM_CXSMICON) +cxAFTER_LIST_ICON;
1050 rLines.top = prThisColumn->top;
1051 rLines.bottom = prThisColumn->bottom;
1052 prThisColumn->left = rLines.right;
1054 LONG xBox = rLines.left + (GetSystemMetrics(SM_CXSMICON) - cxTREE_BOX)/2;
1055 LONG xLine = xBox + cxTREE_BOX/2;
1057 LONG yLine = rLines.top + cyRECT(rLines)/2;
1058 LONG yBox = yLine - cyTREE_BOX/2;
1060 if (dwLines & TREELINE_BOX)
1062 pdi->reg.rButton.left = xBox;
1063 pdi->reg.rButton.right = xBox +cxTREE_BOX +1;
1064 pdi->reg.rButton.top = yBox;
1065 pdi->reg.rButton.bottom = yBox +cyTREE_BOX +1;
1070 COLORREF clrBG = GetSysColor (COLOR_WINDOW);
1071 COLORREF clrFG = GetSysColor (COLOR_BTNSHADOW);
1072 if (!IsWindowEnabled (pfl->hList))
1073 clrBG = GetSysColor (COLOR_BTNFACE);
1075 if (dwLines & TREELINE_HORIZONTAL)
1077 for (LONG xx = (dwLines & TREELINE_BOX) ? (xBox +cxTREE_BOX) : (dwLines & TREELINE_UP) ? xLine : (rLines.left+1); xx <= rLines.right+1; xx += cxSPACE_TREELINE)
1078 SetPixel (pdi->hdc, xx, yLine, clrFG);
1081 if (dwLines & TREELINE_UP)
1083 for (LONG yy = (dwLines & TREELINE_BOX) ? yBox : yLine; yy >= rLines.top; yy -= cySPACE_TREELINE)
1084 SetPixel (pdi->hdc, xLine, yy, clrFG);
1087 if (dwLines & TREELINE_DOWN)
1089 for (LONG yy = (dwLines & TREELINE_BOX) ? (yBox +cyTREE_BOX) : yLine; yy <= rLines.bottom; yy += cySPACE_TREELINE)
1090 SetPixel (pdi->hdc, xLine, yy, clrFG);
1093 if (dwLines & TREELINE_BOX)
1095 HPEN hpNew = CreatePen (PS_SOLID, 1, clrFG);
1096 HPEN hpOld = (HPEN)SelectObject (pdi->hdc, hpNew);
1098 MoveToEx (pdi->hdc, xBox, yBox, NULL);
1099 LineTo (pdi->hdc, xBox +cxTREE_BOX, yBox);
1100 LineTo (pdi->hdc, xBox +cxTREE_BOX, yBox +cyTREE_BOX);
1101 LineTo (pdi->hdc, xBox, yBox +cyTREE_BOX);
1102 LineTo (pdi->hdc, xBox, yBox);
1104 SelectObject (pdi->hdc, GetStockObject (BLACK_PEN));
1106 MoveToEx (pdi->hdc, xBox +2, yLine, NULL);
1107 LineTo (pdi->hdc, xBox +cxTREE_BOX -1, yLine);
1109 if ((dwLines & TREELINE_BOXCLOSED) == TREELINE_BOXCLOSED)
1111 MoveToEx (pdi->hdc, xLine, yBox +2, NULL);
1112 LineTo (pdi->hdc, xLine, yBox +cyTREE_BOX -1);
1115 SelectObject (pdi->hdc, hpOld);
1116 DeleteObject (hpNew);
1122 BOOL FastList_OnPaintItem_DrawImage (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, HIMAGELIST hil, int iImage, LONG xImage, LONG yImage, BOOL fHLines)
1126 if (iImage == IMAGE_NOIMAGE)
1130 rImage.left = xImage;
1131 rImage.right = rImage.left + GetSystemMetrics ((hil == pfl->hilLarge) ? SM_CXICON : SM_CXSMICON);
1132 rImage.top = yImage;
1133 rImage.bottom = rImage.top + GetSystemMetrics ((hil == pfl->hilLarge) ? SM_CYICON : SM_CYSMICON);
1137 if (iImage == IMAGE_BLANKIMAGE)
1139 if (fHLines && ((pfl->dwStyle & FLS_VIEW_TREE) == FLS_VIEW_TREE))
1142 rLine.left = xImage;
1143 rLine.right = rLine.left + GetSystemMetrics(SM_CXSMICON);
1145 rLine.bottom = rLine.top + GetSystemMetrics(SM_CYSMICON);
1146 FastList_OnPaintItem_TreeLines (pfl, pdi, TREELINE_HORIZONTAL, &rLine);
1149 else // An actual image was specified to be drawn.
1151 if (!ImageList_Draw (hil, iImage, pdi->hdc, rImage.left, rImage.top, (pdi->fDragImage) ? ILD_TRANSPARENT : (!IsWindowEnabled(pfl->hList)) ? ILD_TRANSPARENT : (pdi->hItem->fSelected) ? ILD_SELECTED : (pdi->hItem->fFocused) ? ILD_FOCUS : ILD_TRANSPARENT))
1156 if (IsRectEmpty (&pdi->reg.rImage))
1157 pdi->reg.rImage = rImage;
1159 UnionRect (&pdi->reg.rImage, &pdi->reg.rImage, &rImage);
1165 void FastList_OnPaintItem_GetItemColors (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, COLORREF *pclrFore, COLORREF *pclrBack)
1167 if (pdi->fDragImage)
1169 *pclrFore = GetSysColor (COLOR_WINDOWTEXT);
1170 *pclrBack = clrTRANSPARENT;
1172 else if (!IsWindowEnabled (pfl->hList))
1174 *pclrFore = GetSysColor (COLOR_GRAYTEXT);
1175 *pclrBack = GetSysColor (COLOR_BTNFACE);
1177 else if ( (pdi->hItem->fSelected) || (pdi->hItem->dwFlags & FLIF_DROPHIGHLIGHT) )
1179 *pclrFore = GetSysColor (COLOR_HIGHLIGHTTEXT);
1180 *pclrBack = GetSysColor (COLOR_HIGHLIGHT);
1182 else // normal colors
1184 *pclrFore = GetSysColor (COLOR_WINDOWTEXT);
1185 *pclrBack = GetSysColor (COLOR_WINDOW);
1190 void FastList_OnPaintItem_Large (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi)
1192 // If there is an image associated with this item, draw it. Remember
1193 // that if there are *two* images, draw the second one--it's the primary
1194 // image, or the user wouldn't have bothered adding it.
1196 int iImage = pdi->hItem->iFirstImage;
1197 if (pdi->hItem->iSecondImage != IMAGE_NOIMAGE)
1198 iImage = pdi->hItem->iSecondImage;
1199 if (iImage != IMAGE_NOIMAGE)
1201 LONG xImage = pdi->rItem.left + (cxRECT(pdi->rItem) - GetSystemMetrics(SM_CXICON))/2;
1202 LONG yImage = pdi->rItem.top + cyABOVE_LARGE_ICON;
1203 FastList_OnPaintItem_DrawImage (pfl, pdi, pfl->hilLarge, iImage, xImage, yImage, FALSE);
1206 // If there is any column-0 text supplied for this item, draw that below
1209 LPTSTR pszColumnText = FastList_GetColumnText (pfl, pdi->hItem, 0);
1210 if (pszColumnText && *pszColumnText)
1213 SetRectEmpty (&rTextSize);
1214 rTextSize.right = cxRECT(pdi->rItem) - cxBEFORE_LARGE_TEXT - cxAFTER_LARGE_TEXT -2;
1216 if (!DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText), &rTextSize, DT_CENTER | DT_CALCRECT | DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX, 0))
1217 rTextSize.right = rTextSize.left;
1219 RECT rText = pdi->rItem;
1220 rText.left += (cxRECT(pdi->rItem)-cxRECT(rTextSize))/2;
1221 rText.right -= (cxRECT(pdi->rItem)-cxRECT(rTextSize))/2;
1222 rText.top += cyABOVE_LARGE_ICON + GetSystemMetrics(SM_CYICON) + cyBELOW_LARGE_ICON + cyABOVE_LARGE_TEXT;
1223 rText.bottom = min( pdi->rItem.bottom - cyBELOW_LARGE_TEXT, (rText.top + cyRECT(rTextSize)) );
1225 pdi->reg.rHighlight = rText;
1226 pdi->reg.rHighlight.left -= cxBEFORE_LARGE_TEXT;
1227 pdi->reg.rHighlight.right += cxAFTER_LARGE_TEXT;
1228 pdi->reg.rHighlight.top -= cyABOVE_LARGE_TEXT;
1229 pdi->reg.rHighlight.bottom += cyBELOW_LARGE_TEXT;
1231 pdi->reg.rLabel = pdi->reg.rHighlight;
1232 if (PtInRect (&rText, pdi->ptTextTest))
1233 pdi->fTextTestHit = TRUE;
1239 FastList_OnPaintItem_GetItemColors (pfl, pdi, &clrFore, &clrBack);
1241 if (pdi->hItem->fSelected)
1243 HBRUSH hbr = CreateSolidBrush (clrBack);
1244 FillRect (pdi->hdc, &pdi->reg.rHighlight, hbr);
1248 COLORREF clrBackOld = SetBkColor (pdi->hdc, clrBack);
1249 COLORREF clrForeOld = SetTextColor (pdi->hdc, clrFore);
1251 DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText),
1252 &rText, DT_CENTER | DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX, 0);
1254 SetTextColor (pdi->hdc, clrForeOld);
1255 SetBkColor (pdi->hdc, clrBackOld);
1257 if (pdi->hItem->fFocused && IsWindowEnabled (pfl->hList))
1258 DrawFocusRect (pdi->hdc, &pdi->reg.rHighlight);
1264 void FastList_OnPaintItem_Small (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi)
1266 // If there is an image associated with this item, draw it. Remember
1267 // that if there are *two* images, draw the second one--it's the primary
1268 // image, or the user wouldn't have bothered adding it.
1270 BOOL fImage = FALSE;
1272 int iImage = pdi->hItem->iFirstImage;
1273 if (pdi->hItem->iSecondImage != IMAGE_NOIMAGE)
1274 iImage = pdi->hItem->iSecondImage;
1275 if (iImage != IMAGE_NOIMAGE)
1277 LONG xImage = pdi->rItem.left + cxBEFORE_SMALL_ICON;
1278 LONG yImage = pdi->rItem.top + (cyRECT(pdi->rItem) - GetSystemMetrics(SM_CYSMICON))/2;
1279 fImage = FastList_OnPaintItem_DrawImage (pfl, pdi, pfl->hilSmall, iImage, xImage, yImage, FALSE);
1282 // If there is any column-0 text supplied for this item, draw that to the
1283 // right of the item's icon.
1285 LPTSTR pszColumnText = FastList_GetColumnText (pfl, pdi->hItem, 0);
1286 if (pszColumnText && *pszColumnText)
1288 RECT rTextSize = pdi->rItem;
1289 if (!DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText), &rTextSize, DT_CALCRECT | DT_END_ELLIPSIS | DT_NOPREFIX, 0))
1290 rTextSize.right = rTextSize.left;
1292 RECT rText = pdi->rItem;
1293 rText.left += cxBEFORE_SMALL_TEXT + fImage * (GetSystemMetrics(SM_CXSMICON) + cxBEFORE_SMALL_ICON + cxAFTER_SMALL_ICON);
1294 rText.right = min( pdi->rItem.right - cxAFTER_SMALL_TEXT, (rText.left + cxRECT(rTextSize)) );
1295 rText.top += cyABOVE_SMALL_TEXT;
1296 rText.bottom -= cyBELOW_SMALL_TEXT;
1298 pdi->reg.rHighlight = rText;
1299 pdi->reg.rHighlight.left -= cxBEFORE_SMALL_TEXT;
1300 pdi->reg.rHighlight.right += cxAFTER_SMALL_TEXT;
1301 pdi->reg.rHighlight.top -= cyABOVE_SMALL_TEXT;
1302 pdi->reg.rHighlight.bottom += cyBELOW_SMALL_TEXT;
1304 pdi->reg.rLabel = pdi->reg.rHighlight;
1305 if (PtInRect (&rText, pdi->ptTextTest))
1306 pdi->fTextTestHit = TRUE;
1312 FastList_OnPaintItem_GetItemColors (pfl, pdi, &clrFore, &clrBack);
1314 if (pdi->hItem->fSelected)
1316 HBRUSH hbr = CreateSolidBrush (clrBack);
1317 FillRect (pdi->hdc, &pdi->reg.rHighlight, hbr);
1321 COLORREF clrBackOld = SetBkColor (pdi->hdc, clrBack);
1322 COLORREF clrForeOld = SetTextColor (pdi->hdc, clrFore);
1324 DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText),
1325 &rText, DT_END_ELLIPSIS | DT_NOPREFIX, 0);
1327 SetTextColor (pdi->hdc, clrForeOld);
1328 SetBkColor (pdi->hdc, clrBackOld);
1330 if (pdi->hItem->fFocused && IsWindowEnabled (pfl->hList))
1331 DrawFocusRect (pdi->hdc, &pdi->reg.rHighlight);
1337 void FastList_OnPaintItem_Tree (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, HLISTITEM hItem, RECT *prThisColumn)
1339 // This routine is supposed to draw the tree structure off to the left
1340 // of an item. To do that, it calls itself recursively to draw the
1341 // icon areas of each of its parents.
1343 if (hItem->hTreeParent != NULL)
1345 FastList_OnPaintItem_Tree (pfl, pdi, hItem->hTreeParent, prThisColumn);
1348 // For any given item, the first thing to determine is how many icons
1351 int iLeftImage = hItem->iFirstImage;
1352 int iRightImage = IMAGE_NOIMAGE;
1354 if (hItem->iSecondImage != IMAGE_NOIMAGE)
1356 iLeftImage = hItem->iSecondImage;
1357 iRightImage = hItem->iFirstImage;
1360 // What lines/boxes should we draw?
1362 BOOL fHLines = FALSE;
1364 if ((hItem->hTreeParent) || (pfl->dwStyle & FLS_LINESATROOT))
1369 if (hItem == pdi->hItem)
1370 dwLines |= TREELINE_HORIZONTAL;
1371 if ((hItem == pdi->hItem) && (hItem->hTreeChild))
1372 dwLines |= (hItem->fExpanded) ? TREELINE_BOXOPEN : TREELINE_BOXCLOSED;
1373 if (hItem->hTreeNext)
1374 dwLines |= TREELINE_DOWN;
1375 if ((dwLines != 0) && !((!hItem->hTreeParent && !hItem->hTreePrevious) && (hItem == pdi->hItem)))
1376 dwLines |= TREELINE_UP;
1378 FastList_OnPaintItem_TreeLines (pfl, pdi, dwLines, prThisColumn);
1381 // The lines we (maybe) just drew took the place of an icon for this
1382 // item. Maybe draw blank space, to pad for the second icon
1384 if ( (hItem != pdi->hItem) && (iLeftImage != IMAGE_NOIMAGE) && (iRightImage != IMAGE_NOIMAGE) )
1386 FastList_OnPaintItem_TreeLines (pfl, pdi, 0, prThisColumn);
1391 void FastList_OnPaintItem_List (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi)
1393 // Painting a tree or list is done column by column. Remember
1394 // We may have a "long column"--that's a column that doesn't
1395 // necessarily respect the header column boundaries.
1397 RECT rItemRemaining = pdi->rItem;
1398 pdi->reg.rHighlight = pdi->rItem;
1401 if (pdi->fDragImage)
1405 else if ((pfl->dwStyle & FLS_VIEW_TREELIST) == FLS_VIEW_TREE)
1409 else if (pfl->dwStyle & FLS_LONGCOLUMNS)
1411 for (size_t icol = 0; icol < pfl->cColumns; ++icol)
1413 if (!pfl->aColumns[ icol ].pszText)
1416 LPTSTR pszColumnText = FastList_GetColumnText (pfl, pdi->hItem, icol);
1420 if ((pfl->aColumns[ icol ].fmt & HDF_JUSTIFYMASK) != HDF_LEFT)
1421 icolLong = -1; // this can't be the long column
1426 // Select appropriate text colors. Since FastLists always draw highlights
1427 // all the way across the item, we won't change colors from column to
1432 FastList_OnPaintItem_GetItemColors (pfl, pdi, &clrFore, &clrBack);
1434 COLORREF clrBackOld = SetBkColor (pdi->hdc, clrBack);
1435 COLORREF clrForeOld = SetTextColor (pdi->hdc, clrFore);
1437 // Now that we know where the long column is, we're ready to start
1438 // painting columns.
1440 for (int icol = 0; (icolLong == -1) || (icol <= icolLong); ++icol)
1442 if (icol && !pfl->cColumns)
1444 else if ((pfl->cColumns) && ((icol >= (int)pfl->cColumns) || (!pfl->aColumns[ icol ].pszText)))
1447 // The rules for the long column are slightly different than the
1448 // rules for all other columns.
1450 LONG cxColumn = pdi->rItem.right - rItemRemaining.left;
1451 int fmtColumn = HDF_LEFT;
1453 if ((icol != icolLong) && (pfl->cColumns) && (icol < (int)pfl->cColumns))
1455 cxColumn = pfl->aColumns[ icol ].cxy;
1456 fmtColumn = pfl->aColumns[ icol ].fmt & HDF_JUSTIFYMASK;
1459 // Remember where this column ends and the next column begins.
1461 RECT rThisColumn = rItemRemaining;
1462 rThisColumn.right = rThisColumn.left + cxColumn;
1464 // Get the text for this column, and figure out how big it will be.
1466 LPTSTR pszColumnText = FastList_GetColumnText (pfl, pdi->hItem, icol);
1468 RECT rTextSize = rThisColumn;
1469 if (!DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText), &rTextSize, DT_CALCRECT | DT_END_ELLIPSIS | DT_NOPREFIX, 0))
1470 rTextSize.right = rTextSize.left;
1472 // Draw the icons and/or lines for the column. The behavior here
1473 // depends on whether we're drawing a tree or a list, or both.
1475 BOOL fHLines = FALSE;
1476 if ((icol == 0) && ((pfl->dwStyle & FLS_VIEW_TREE) == FLS_VIEW_TREE) && (!pdi->fDragImage))
1478 FastList_OnPaintItem_Tree (pfl, pdi, pdi->hItem, &rThisColumn);
1484 int iLeftImage = pdi->hItem->iFirstImage;
1485 int iRightImage = IMAGE_NOIMAGE;
1487 if ((pdi->hItem->iSecondImage != IMAGE_NOIMAGE) &&
1488 (rThisColumn.left < rThisColumn.right) &&
1491 iLeftImage = pdi->hItem->iSecondImage;
1492 iRightImage = pdi->hItem->iFirstImage;
1495 if ((iLeftImage != IMAGE_NOIMAGE) &&
1496 (rThisColumn.left < rThisColumn.right))
1498 rThisColumn.left += cxBEFORE_LIST_ICON;
1499 pdi->reg.rImage = rThisColumn;
1501 LONG xImage = rThisColumn.left;
1502 LONG yImage = rThisColumn.top + (cyRECT(pdi->rItem) - GetSystemMetrics(SM_CYSMICON))/2;
1503 if (FastList_OnPaintItem_DrawImage (pfl, pdi, pfl->hilSmall, iLeftImage, xImage, yImage, fHLines))
1505 rThisColumn.left += GetSystemMetrics (SM_CXSMICON);
1506 if (iRightImage != IMAGE_NOIMAGE)
1508 rThisColumn.left += cxBETWEEN_LIST_ICONS;
1509 xImage = rThisColumn.left;
1510 yImage = rThisColumn.top + (cyRECT(pdi->rItem) - GetSystemMetrics(SM_CYSMICON))/2;
1511 if (FastList_OnPaintItem_DrawImage (pfl, pdi, pfl->hilSmall, iRightImage, xImage, yImage, fHLines))
1512 rThisColumn.left += GetSystemMetrics (SM_CXSMICON);
1516 pdi->reg.rImage.right = rThisColumn.left;
1517 rThisColumn.left += cxAFTER_LIST_ICON;
1521 // Determine where the text will go in this column. We have to pass
1522 // that information back (for column 0) as reg.rLabel; we also have
1523 // to test the text's position against {pdi->ptTextTest} to see if the
1524 // user just clicked on the text.
1526 RECT rText = rThisColumn;
1527 rText.left += cxBEFORE_LIST_TEXT;
1528 rText.right -= cxAFTER_LIST_TEXT;
1529 rText.top += cyABOVE_LIST_TEXT;
1530 rText.bottom -= cyBELOW_LIST_TEXT;
1533 rText.left += cxBEFORE_COLUMN_TEXT;
1535 RECT rTextJustified = rText;
1536 rTextJustified.right = min( rText.right, rText.left + cxRECT(rTextSize) );
1539 if (fmtColumn == HDF_CENTER)
1540 dxJustify = (cxRECT(rText) - cxRECT(rTextJustified))/2;
1541 else if (fmtColumn == HDF_RIGHT)
1542 dxJustify = cxRECT(rText) - cxRECT(rTextJustified);
1543 rTextJustified.left += dxJustify;
1544 rTextJustified.right += dxJustify;
1547 pdi->reg.rLabel = rTextJustified;
1549 if (PtInRect (&rTextJustified, pdi->ptTextTest))
1550 pdi->fTextTestHit = TRUE;
1552 // Having determined where the text will go, we should record
1553 // where the highlight will be drawn.
1557 pdi->reg.rHighlight.left = rThisColumn.left;
1559 if (icol == icolLong)
1561 pdi->reg.rHighlight.right = min( pdi->reg.rHighlight.right, rTextJustified.right + cxAFTER_LIST_TEXT );
1564 // Okay, it's time to actually draw the text. Didn't think we'd
1565 // ever get here, did you? :)
1569 if ((!pdi->fDragImage) && ((pdi->hItem->fSelected) || (pdi->hItem->dwFlags & FLIF_DROPHIGHLIGHT)))
1571 RECT rHighlightInColumn;
1572 IntersectRect (&rHighlightInColumn, &pdi->reg.rHighlight, &rThisColumn);
1574 HBRUSH hbr = CreateSolidBrush (clrBack);
1575 FillRect (pdi->hdc, &rHighlightInColumn, hbr);
1579 DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText),
1580 &rTextJustified, DT_END_ELLIPSIS | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER, 0);
1583 rItemRemaining.left = rThisColumn.right;
1586 // Finally, draw the focus rectangle and restore the original text colors.
1588 if (pdi->hItem->fFocused && pdi->fDraw && IsWindowEnabled (pfl->hList) && (!pdi->fDragImage))
1589 DrawFocusRect (pdi->hdc, &pdi->reg.rHighlight);
1591 SetTextColor (pdi->hdc, clrForeOld);
1592 SetBkColor (pdi->hdc, clrBackOld);
1596 void FastList_OnScroll (HWND hList, UINT msg, WPARAM wp, LPARAM lp)
1599 if ((pfl = GetFastList (hList)) != NULL)
1601 HWND hScroll = (msg == WM_VSCROLL) ? pfl->hScrollV : pfl->hScrollH;
1604 memset (&si, 0x00, sizeof(si));
1605 si.cbSize = sizeof(si);
1606 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
1607 GetScrollInfo (hScroll, SB_CTL, &si);
1609 LONG posNew = si.nPos;
1610 BOOL fRepaint = TRUE;
1619 posNew = si.nMax - si.nPage;
1631 posNew -= FastList_GetListHeight (pfl);
1635 posNew += FastList_GetListHeight (pfl);
1639 posNew = si.nTrackPos;
1644 posNew = limit( 0, posNew, (LONG)(si.nMax - si.nPage) );
1645 SetScrollPos (hScroll, SB_CTL, posNew, fRepaint);
1647 // If we just scrolled vertically, repaint. If we just scrolled
1648 // horizontally, we'll have to sync the header first.
1650 if (msg == WM_HSCROLL)
1651 pfl->dxPixel = posNew;
1653 pfl->dyPixel = posNew;
1655 FastList_Repaint (pfl);
1656 if (msg == WM_HSCROLL)
1657 FastList_ScrollHeader (pfl);
1662 void FastList_OnRightButtonDown (HWND hList)
1664 FastList_ButtonDown (hList, TRUE, FALSE);
1665 FastList_Notify_Generic (GetFastList(hList), FLN_RCLICK);
1669 void FastList_OnLeftButtonDown (HWND hList)
1671 FastList_ButtonDown (hList, FALSE, FALSE);
1672 FastList_Notify_Generic (GetFastList(hList), FLN_LCLICK);
1676 void FastList_OnLeftButtonDouble (HWND hList)
1678 FastList_ButtonDown (hList, FALSE, TRUE);
1679 FastList_ButtonUp (hList, FALSE, TRUE);
1680 FastList_Notify_Generic (GetFastList(hList), FLN_LDBLCLICK);
1684 void FastList_OnKeyPress (HWND hList, TCHAR ch)
1687 if ((pfl = GetFastList (hList)) != NULL)
1692 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1694 if ((pfl->hFocused->hTreeChild) && (pfl->hFocused->fExpanded) && (!(pfl->hFocused->dwFlags & FLIF_DISALLOW_COLLAPSE)) && (pfl->dwStyle & FLS_VIEW_TREE))
1696 FastList_Collapse (hList, pfl->hFocused);
1699 if (pfl->hFocused->index != 0)
1700 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[ pfl->hFocused->index -1 ]);
1704 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1706 if (pfl->hFocused->index != 0)
1707 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[ pfl->hFocused->index -1 ]);
1711 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1713 if ((pfl->hFocused->hTreeChild) && (!pfl->hFocused->fExpanded) && (pfl->dwStyle & FLS_VIEW_TREE))
1715 FastList_Expand (hList, pfl->hFocused);
1716 FastList_Notify_ItemExpand (pfl, pfl->hFocused);
1719 if (pfl->hFocused->index < (int)(pfl->cVisible-1))
1720 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[ pfl->hFocused->index +1 ]);
1724 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1726 if (pfl->hFocused->index < (int)(pfl->cVisible-1))
1727 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[ pfl->hFocused->index +1 ]);
1731 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1734 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[0]);
1738 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1741 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[ pfl->cVisible -1 ]);
1745 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1747 FastList_Begin (pfl->hList);
1748 if (pfl->hFocused->fSelected && fIsControlDown())
1749 FastList_SelectItem (pfl->hList, pfl->hFocused, FALSE);
1750 else if (!pfl->hFocused->fSelected && !fIsShiftDown())
1751 FastList_SelectItem (pfl->hList, pfl->hFocused, TRUE);
1752 else if (!pfl->hFocused->fSelected)
1753 FastList_OnKeyPress_ChangeSelection (pfl, pfl->hFocused);
1754 FastList_End (pfl->hList);
1761 BOOL FastList_OnKeyPress_EnsureSelection (LPFASTLIST pfl)
1763 if (pfl->fSortBeforePaint)
1764 FastList_PerformSort (pfl);
1765 if (pfl->fSyncIndicesBeforePaint)
1766 FastList_RepairVisibilityIndices (pfl);
1767 if (pfl->hFocused && pfl->hFocused->fVisible)
1770 // Find the item at the top of the list.
1773 GetClientRect (pfl->hList, &rClient);
1775 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
1777 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
1779 rClient.top += FastList_GetHeaderHeight (pfl);
1782 FastList_CalcItemRect (pfl, 0, &rTemplate, !!pfl->hScrollH, !!pfl->hScrollV);
1784 int indexTopLeft = -1;
1786 switch (pfl->dwStyle & FLS_VIEW_MASK)
1788 case FLS_VIEW_LARGE:
1790 LONG cxItems = cxRECT(rClient) / cxRECT(rTemplate);
1791 indexTopLeft = pfl->dyPixel / cyRECT(rTemplate);
1795 case FLS_VIEW_SMALL:
1797 LONG cyItems = cyRECT(rClient) / cyRECT(rTemplate);
1798 indexTopLeft = pfl->dxPixel / cxRECT(rTemplate);
1804 case FLS_VIEW_TREELIST:
1805 indexTopLeft = pfl->dyPixel / cyRECT(rTemplate);
1809 if ((indexTopLeft >= 0) && (indexTopLeft < (int)pfl->cVisible))
1811 FastList_SetFocus (pfl->hList, pfl->aVisibleHeap[ indexTopLeft ]);
1818 void FastList_OnKeyPress_ChangeSelection (LPFASTLIST pfl, HLISTITEM hSelect)
1820 FastList_Begin (pfl->hList);
1821 FastList_SetFocus (pfl->hList, hSelect);
1822 FastList_EnsureVisible (pfl->hList, hSelect);
1824 // If Control is not down, begin by de-selecting all items
1825 // If Shift is not down, anchor and select the specified item
1826 // If Shift is down, select from the anchor to the specified item
1828 HLISTITEM hAnchor = pfl->hAnchor;
1829 if (!fIsControlDown())
1831 FastList_SelectNone (pfl->hList);
1833 if ((!fIsShiftDown() || !hAnchor) && (!fIsControlDown()))
1835 FastList_SelectItem (pfl->hList, hSelect, TRUE);
1836 pfl->hAnchor = hSelect;
1838 if (fIsShiftDown() && hAnchor)
1840 FastList_PerformSelectRange (pfl, hAnchor, hSelect);
1841 if (hAnchor->fSelected)
1842 pfl->hAnchor = hAnchor;
1845 FastList_End (pfl->hList);
1846 FastList_Notify_ItemSelect (pfl);
1851 * EXPORTED ROUTINES __________________________________________________________
1855 void FastList_OnCommand_Begin (HWND hList)
1858 if ((pfl = GetFastList (hList)) != NULL)
1865 void FastList_OnCommand_End (HWND hList, BOOL fForce)
1868 if ((pfl = GetFastList (hList)) != NULL)
1872 else if (pfl->nBegin)
1875 if (pfl->nBegin == 0)
1877 if (pfl->fSyncHeaderRequired)
1878 FastList_SyncHeader (pfl);
1879 if (pfl->fSortBeforePaint)
1880 pfl->fRepaintRequired = TRUE;
1881 if (pfl->fSyncScrollBeforePaint)
1882 pfl->fRepaintRequired = TRUE;
1883 if (pfl->fRepaintRequired)
1884 FastList_Repaint (pfl);
1890 HLISTITEM FastList_OnCommand_AddItem (HWND hList, LPFASTLISTADDITEM pai)
1892 HLISTITEM hItem = NULL;
1895 if ((pfl = GetFastList (hList)) != NULL)
1897 hItem = FastList_CreateItem (pfl);
1899 // Add this item to the hList chain
1901 if ((hItem->hListNext = pfl->hListFirst) != NULL)
1902 hItem->hListNext->hListPrevious = hItem;
1903 pfl->hListFirst = hItem;
1905 // Add this item to the hTree chain
1907 if ((hItem->hTreeParent = pai->hParent) != NULL)
1909 if ((hItem->hTreeNext = hItem->hTreeParent->hTreeChild) != NULL)
1910 hItem->hTreeNext->hTreePrevious = hItem;
1911 hItem->hTreeParent->hTreeChild = hItem;
1913 else // (hItem->hTreeParent == NULL)
1915 if ((hItem->hTreeNext = pfl->hTreeFirst) != NULL)
1916 hItem->hTreeNext->hTreePrevious = hItem;
1917 pfl->hTreeFirst = hItem;
1920 hItem->iFirstImage = pai->iFirstImage;
1921 hItem->iSecondImage = pai->iSecondImage;
1922 hItem->dwFlags = pai->dwFlags;
1923 hItem->lpUser = pai->lParam;
1927 REALLOC (hItem->apszText, hItem->cpszText, 1, max(1,pfl->cColumns));
1928 hItem->apszText[0] = (LPTSTR)Allocate (sizeof(TCHAR)*(1+lstrlen(pai->pszText)));
1929 lstrcpy (hItem->apszText[0], pai->pszText);
1932 hItem->fVisible = FALSE;
1933 FastList_RepairOneVisibilityFlag (pfl, hItem);
1935 pfl->lItems->Add (hItem);
1936 pfl->fSortBeforePaint = TRUE;
1937 pfl->fSyncScrollBeforePaint = TRUE;
1938 FastList_Notify_AddItem (pfl, hItem);
1939 FastList_Repaint (pfl);
1946 void FastList_OnCommand_RemoveItem (HWND hList, HLISTITEM hItem)
1949 if ((pfl = GetFastList (hList)) != NULL)
1953 FastList_DeleteItem (pfl, hItem);
1957 FastList_Begin (pfl->hList);
1959 while ((hItem = (HLISTITEM)(pfl->lItems->GetFirstObject())) != NULL)
1960 FastList_DeleteItem (pfl, hItem);
1962 FastList_End (pfl->hList);
1965 FastList_Repaint (pfl);
1966 FastList_Notify_ItemSelect (pfl);
1971 LPCTSTR FastList_OnCommand_GetItemText (HWND hList, HLISTITEM hItem, int iColumn)
1975 if ((iColumn < 0) || (iColumn >= (int)(hItem->cpszText)))
1977 return hItem->apszText[ iColumn ];
1981 void FastList_OnCommand_SetItemText (HWND hList, LPFASTLISTITEMCOLUMN pflic, LPCTSTR pszText)
1984 if ((pfl = GetFastList (hList)) != NULL)
1986 if ((pflic) && (pflic->hItem) && (pflic->icol >= 0))
1988 if (REALLOC (pflic->hItem->apszText, pflic->hItem->cpszText, pflic->icol+1, 1))
1990 if (pflic->hItem->apszText[ pflic->icol ] != NULL)
1992 Free (pflic->hItem->apszText[ pflic->icol ]);
1993 pflic->hItem->apszText[ pflic->icol ] = NULL;
1995 if (pszText != NULL)
1997 pflic->hItem->apszText[ pflic->icol ] = (LPTSTR)Allocate (sizeof(TCHAR)*(1+lstrlen(pszText)));
1998 lstrcpy (pflic->hItem->apszText[ pflic->icol ], pszText);
2000 pfl->fSortBeforePaint = TRUE;
2001 FastList_Notify_ItemChanged (pfl, pflic->hItem);
2002 FastList_Repaint (pfl);
2009 LPARAM FastList_OnCommand_GetItemParam (HWND hList, HLISTITEM hItem)
2011 return (hItem == NULL) ? 0 : (hItem->lpUser);
2015 void FastList_OnCommand_SetItemParam (HWND hList, HLISTITEM hItem, LPARAM lpUser)
2018 if ((pfl = GetFastList (hList)) != NULL)
2022 hItem->lpUser = lpUser;
2023 pfl->lItems->Update (hItem);
2025 pfl->fSortBeforePaint = TRUE;
2026 FastList_Notify_ItemChanged (pfl, hItem);
2027 FastList_Repaint (pfl);
2033 DWORD FastList_OnCommand_GetItemFlags (HWND hList, HLISTITEM hItem)
2035 return (hItem == NULL) ? 0 : (hItem->dwFlags);
2039 void FastList_OnCommand_SetItemFlags (HWND hList, HLISTITEM hItem, DWORD dwFlagsNew)
2042 if ((pfl = GetFastList (hList)) != NULL)
2046 FastList_Begin (hList);
2048 DWORD dwFlagsOld = hItem->dwFlags;
2049 hItem->dwFlags = dwFlagsNew;
2051 if ( (dwFlagsOld & FLIF_TREEVIEW_ONLY) != (dwFlagsNew & FLIF_TREEVIEW_ONLY) )
2053 FastList_RepairOneVisibilityFlag (pfl, hItem);
2054 FastList_Repaint (pfl);
2057 if ( (dwFlagsNew & FLIF_DISALLOW_SELECT) && (hItem->fSelected) )
2059 FastList_PerformSelectItem (pfl, hItem, FALSE);
2060 FastList_Repaint (pfl);
2063 if ( (dwFlagsNew & FLIF_DISALLOW_COLLAPSE) && !(hItem->fExpanded) )
2065 FastList_OnCommand_Expand (hList, hItem, TRUE);
2066 FastList_Repaint (pfl);
2069 if ( (dwFlagsOld & FLIF_DROPHIGHLIGHT) != (dwFlagsNew & FLIF_DROPHIGHLIGHT) )
2070 FastList_Repaint (pfl);
2072 FastList_Notify_ItemChanged (pfl, hItem);
2073 FastList_End (hList);
2079 int FastList_OnCommand_GetItemImage (HWND hList, HLISTITEM hItem, int iImage)
2081 if (hItem && (iImage==0 || iImage==1))
2082 return (iImage == 0) ? (hItem->iFirstImage) : (hItem->iSecondImage);
2084 return IMAGE_NOIMAGE;
2088 void FastList_OnCommand_SetItemImage (HWND hList, LPFASTLISTITEMIMAGE pflii, int iImage)
2091 if ((pfl = GetFastList (hList)) != NULL)
2093 if (pflii && pflii->hItem && (pflii->iImage==0 || pflii->iImage==1))
2095 if (pflii->iImage == 0)
2096 pflii->hItem->iFirstImage = iImage;
2097 else // (pflii->iImage == 1)
2098 pflii->hItem->iSecondImage = iImage;
2100 FastList_Notify_ItemChanged (pfl, pflii->hItem);
2101 FastList_Repaint (pfl);
2107 BOOL FastList_OnCommand_IsExpanded (HWND hList, HLISTITEM hItem)
2109 return (hItem) ? (hItem->fExpanded) : FALSE;
2113 void FastList_OnCommand_Expand (HWND hList, HLISTITEM hItem, BOOL fExpand)
2116 if ((pfl = GetFastList (hList)) != NULL)
2118 if (hItem && (hItem->fExpanded != fExpand) && (fExpand || !(hItem->dwFlags & FLIF_DISALLOW_COLLAPSE)))
2120 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE) ? TRUE : FALSE;
2122 hItem->fExpanded = fExpand;
2123 pfl->fSyncScrollBeforePaint = TRUE;
2124 pfl->fSyncIndicesBeforePaint = TRUE;
2125 FastList_RepairVisibilityFlags (pfl, hItem, (!hItem->fExpanded || !hItem->fVisible) && (fTreeMode));
2126 FastList_Notify_ItemChanged (pfl, hItem);
2127 FastList_Repaint (pfl);
2133 BOOL FastList_OnCommand_ItemVisible (HWND hList, HLISTITEM hItem, BOOL fSet)
2136 return (hItem) ? (hItem->fVisible) : FALSE;
2139 if ((pfl = GetFastList (hList)) != NULL)
2141 if (hItem && hItem->fVisible)
2143 pfl->hEnsureVisible = hItem;
2144 FastList_Repaint (pfl);
2151 HLISTITEM FastList_OnCommand_ItemFocus (HWND hList, HLISTITEM hItem, BOOL fSet)
2154 if ((pfl = GetFastList (hList)) != NULL)
2157 return (hItem) ? (HLISTITEM)(hItem->fFocused) : pfl->hFocused;
2159 if (pfl->hFocused != hItem)
2161 if (pfl->hFocused != NULL)
2163 pfl->hFocused->fFocused = FALSE;
2164 FastList_Notify_ItemChanged (pfl, pfl->hFocused);
2166 if ((pfl->hFocused = hItem) != NULL)
2168 pfl->hFocused->fFocused = TRUE;
2169 FastList_Notify_ItemChanged (pfl, pfl->hFocused);
2171 FastList_Repaint (pfl);
2179 void FastList_OnCommand_GetImageLists (HWND hList, HIMAGELIST *phiSmall, HIMAGELIST *phiLarge)
2182 if ((pfl = GetFastList (hList)) != NULL)
2185 *phiSmall = pfl->hilSmall;
2187 *phiLarge = pfl->hilLarge;
2192 void FastList_OnCommand_SetImageLists (HWND hList, HIMAGELIST hiSmall, HIMAGELIST hiLarge)
2195 if ((pfl = GetFastList (hList)) != NULL)
2197 pfl->hilSmall = hiSmall;
2198 pfl->hilLarge = hiLarge;
2199 FastList_Repaint (pfl);
2204 HIMAGELIST FastList_OnCommand_CreateDragImage (HWND hList, HLISTITEM hItem)
2206 HIMAGELIST hil = NULL;
2209 if ((pfl = GetFastList (hList)) != NULL)
2214 // First find out how big this item is. Note that we'll ask
2215 // for the item regions, while specifying the fDragImage flag
2216 // in the paintitem request--that will make it draw only the
2219 HDC hdc = CreateCompatibleDC (NULL);
2220 HFONT hfOld = (HFONT)SelectObject (hdc, pfl->hf);
2223 FastList_CalcItemRect (pfl, 0, &rItem, !!pfl->hScrollH, !!pfl->hScrollV);
2225 FASTLISTITEMREGIONS reg;
2226 FastList_CallPaintItem (pfl, hdc, FALSE, TRUE, hItem->index, &rItem, ®, NULL, NULL);
2228 SelectObject (hdc, hfOld);
2231 RECT rDragImage = reg.rSelect;
2233 rDragImage.left -= reg.rSelect.left;
2234 rDragImage.right -= reg.rSelect.left;
2235 rDragImage.top -= reg.rSelect.top;
2236 rDragImage.bottom -= reg.rSelect.top;
2238 rItem.left -= reg.rSelect.left;
2239 rItem.right -= reg.rSelect.left;
2240 rItem.top -= reg.rSelect.top;
2241 rItem.bottom -= reg.rSelect.top;
2243 // Okay, now we know how big the item will be. Create a bitmap,
2244 // draw onto it, and stuff it into an imagelist.
2247 HDC hdcBitmap = CreateCompatibleDC (hdc);
2248 HBITMAP bmp = CreateCompatibleBitmap (hdc, cxRECT(rDragImage), cyRECT(rDragImage));
2249 HBITMAP bmpOld = (HBITMAP)SelectObject (hdcBitmap, bmp);
2250 hfOld = (HFONT)SelectObject (hdcBitmap, pfl->hf);
2252 HBRUSH hbr = CreateSolidBrush (clrTRANSPARENT);
2253 FillRect (hdcBitmap, &rDragImage, hbr);
2256 FastList_CallPaintItem (pfl, hdcBitmap, TRUE, TRUE, hItem->index, &rItem, NULL, NULL, NULL);
2258 SelectObject (hdcBitmap, hfOld);
2259 SelectObject (hdcBitmap, bmpOld);
2260 DeleteDC (hdcBitmap);
2261 ReleaseDC (NULL, hdc);
2263 if ((hil = ImageList_Create (cxRECT(rDragImage), cyRECT(rDragImage), ILC_MASK, 1, 1)) != NULL)
2265 ImageList_AddMasked (hil, bmp, clrTRANSPARENT);
2276 LPFASTLISTSORTFUNC FastList_OnCommand_GetSortFunc (HWND hList)
2279 if ((pfl = GetFastList (hList)) != NULL)
2281 return pfl->pfnSort;
2288 void FastList_OnCommand_SetSortFunc (HWND hList, LPFASTLISTSORTFUNC pfn)
2291 if ((pfl = GetFastList (hList)) != NULL)
2294 pfl->fSortBeforePaint = TRUE;
2299 void FastList_OnCommand_GetSortStyle (HWND hList, int *piColSort, BOOL *pfRevSort)
2302 if ((pfl = GetFastList (hList)) != NULL)
2305 *piColSort = pfl->iColSort;
2307 *pfRevSort = pfl->fRevSort;
2312 void FastList_OnCommand_SetSortStyle (HWND hList, int iColSort, BOOL fRevSort)
2315 if ((pfl = GetFastList (hList)) != NULL)
2317 pfl->iColSort = iColSort;
2318 pfl->fRevSort = fRevSort;
2319 pfl->fSortBeforePaint = TRUE;
2320 FastList_Repaint (pfl);
2325 void FastList_OnCommand_Sort (HWND hList)
2328 if ((pfl = GetFastList (hList)) != NULL)
2330 pfl->fSortBeforePaint = FALSE;
2331 FastList_Repaint (pfl);
2336 int FastList_OnCommand_GetColumnCount (HWND hList)
2341 if ((pfl = GetFastList (hList)) != NULL)
2343 for (cColumns = 0; cColumns < (int)pfl->cColumns; ++cColumns)
2345 if (pfl->aColumns[ cColumns ].pszText == NULL)
2354 BOOL FastList_OnCommand_GetColumn (HWND hList, int iColumn, LPFASTLISTCOLUMN pcol)
2357 if ((pfl = GetFastList (hList)) == NULL)
2360 if ((iColumn < 0) || (iColumn >= (int)pfl->cColumns) || (!pfl->aColumns[ iColumn ].pszText))
2365 pcol->dwFlags = FLCF_JUSTIFY_LEFT;
2366 if ((pfl->aColumns[ iColumn ].fmt & HDF_JUSTIFYMASK) == HDF_RIGHT)
2367 pcol->dwFlags = FLCF_JUSTIFY_RIGHT;
2368 else if ((pfl->aColumns[ iColumn ].fmt & HDF_JUSTIFYMASK) == HDF_CENTER)
2369 pcol->dwFlags = FLCF_JUSTIFY_CENTER;
2370 pcol->cxWidth = pfl->aColumns[ iColumn ].cxy;
2371 lstrcpy (pcol->szText, pfl->aColumns[ iColumn ].pszText);
2378 void FastList_OnCommand_SetColumn (HWND hList, int iColumn, LPFASTLISTCOLUMN pcol)
2381 if ((pfl = GetFastList (hList)) != NULL)
2383 iColumn = limit (0, iColumn, (int)pfl->cColumns);
2385 if (REALLOC (pfl->aColumns, pfl->cColumns, 1+iColumn, 1))
2387 if (pfl->aColumns[ iColumn ].pszText)
2388 Free (pfl->aColumns[ iColumn ].pszText);
2389 memset (&pfl->aColumns[ iColumn ], 0x00, sizeof(HD_ITEM));
2393 if ((pcol->dwFlags & FLCF_JUSTIFY_MASK) == FLCF_JUSTIFY_RIGHT)
2394 pfl->aColumns[ iColumn ].fmt |= HDF_RIGHT;
2395 else if ((pcol->dwFlags & FLCF_JUSTIFY_MASK) == FLCF_JUSTIFY_CENTER)
2396 pfl->aColumns[ iColumn ].fmt |= HDF_CENTER;
2398 pfl->aColumns[ iColumn ].fmt |= HDF_LEFT;
2400 pfl->aColumns[ iColumn ].cxy = pcol->cxWidth;
2401 pfl->aColumns[ iColumn ].pszText = (LPTSTR)Allocate (sizeof(TCHAR)*(1+lstrlen(pcol->szText)));
2402 lstrcpy (pfl->aColumns[ iColumn ].pszText, pcol->szText);
2404 pfl->aColumns[ iColumn ].mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT;
2407 FastList_SyncHeader (pfl);
2413 BOOL FastList_OnCommand_IsSelected (HWND hList, HLISTITEM hItem)
2415 return hItem->fSelected;
2419 void FastList_OnCommand_SelectItem (HWND hList, HLISTITEM hItem, BOOL fSelect)
2422 if ((pfl = GetFastList (hList)) != NULL)
2426 if (!fSelect || !(hItem->dwFlags & FLIF_DISALLOW_SELECT))
2429 FastList_PerformSelectTest (pfl, hItem);
2430 FastList_PerformSelectItem (pfl, hItem, fSelect);
2435 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE);
2436 BOOL fMultiple = (pfl->dwStyle & FLS_SELECTION_MULTIPLE);
2437 BOOL fLevel = (pfl->dwStyle & (FLS_SELECTION_LEVEL & ~FLS_SELECTION_MULTIPLE));
2438 BOOL fSibling = (pfl->dwStyle & (FLS_SELECTION_SIBLING & ~FLS_SELECTION_MULTIPLE));
2441 (fMultiple && (!fTreeMode || (!fLevel && !fSibling))) )
2443 FastList_Begin (hList);
2445 for (LPENUM pEnum = pfl->lItems->FindFirst(); pEnum; pEnum = pEnum->FindNext())
2447 hItem = (HLISTITEM)(pEnum->GetObject());
2448 if (!fSelect || !(hItem->dwFlags & FLIF_DISALLOW_SELECT))
2449 FastList_PerformSelectItem (pfl, hItem, fSelect);
2452 FastList_End (hList);
2459 HLISTITEM FastList_OnCommand_FindList (HWND hList, HLISTITEM hItem, DWORD dwCode)
2462 if ((pfl = GetFastList (hList)) != NULL)
2466 case FLM_FINDLIST_FIRST:
2467 return pfl->hListFirst;
2469 case FLM_FINDLIST_PREVIOUS:
2470 return (hItem) ? (hItem->hListPrevious) : NULL;
2472 case FLM_FINDLIST_NEXT:
2473 return (hItem) ? (hItem->hListNext) : (pfl->hListFirst);
2481 HLISTITEM FastList_OnCommand_FindTree (HWND hList, HLISTITEM hItem, DWORD dwCode)
2484 if ((pfl = GetFastList (hList)) != NULL)
2488 case FLM_FINDTREE_PARENT:
2489 return (hItem) ? (hItem->hTreeParent) : NULL;
2491 case FLM_FINDTREE_CHILD:
2492 return (hItem) ? (hItem->hTreeChild) : (pfl->hTreeFirst);
2494 case FLM_FINDTREE_PREVIOUS:
2495 return (hItem) ? (hItem->hTreePrevious) : NULL;
2497 case FLM_FINDTREE_NEXT:
2498 return (hItem) ? (hItem->hTreeNext) : NULL;
2505 HLISTITEM FastList_OnCommand_FindSelected (HWND hList, HLISTITEM hItem)
2509 return hItem->hSelectNext;
2513 if ((pfl = GetFastList (hList)) != NULL)
2515 return pfl->hSelectFirst;
2522 HLISTITEM FastList_OnCommand_FindItem (HWND hList, LPENUM *ppEnum, LPARAM lpUser)
2525 if ((pfl = GetFastList (hList)) != NULL)
2528 return (HLISTITEM)(pfl->lkUserParam->GetFirstObject (&lpUser));
2529 else if (ppEnum && (((*ppEnum) = pfl->lkUserParam->FindFirst (&lpUser)) != NULL))
2530 return (HLISTITEM)((*ppEnum)->GetObject());
2536 HLISTITEM FastList_OnCommand_FindNextItem (HWND hList, LPENUM *ppEnum)
2538 if (ppEnum && (((*ppEnum) = (*ppEnum)->FindNext()) != NULL))
2539 return (HLISTITEM)((*ppEnum)->GetObject());
2544 void FastList_OnCommand_FindClose (HWND hList, LPENUM *ppEnum)
2546 if (ppEnum && (*ppEnum))
2554 HLISTITEM FastList_OnCommand_FindVisible (HWND hList, HLISTITEM hItem, DWORD dwCode)
2557 if ((pfl = GetFastList (hList)) != NULL)
2559 if (pfl->fSortBeforePaint)
2560 FastList_PerformSort (pfl);
2561 if (pfl->fSyncIndicesBeforePaint)
2562 FastList_RepairVisibilityIndices (pfl);
2566 case FLM_FINDVISIBLE_FIRST:
2567 return (pfl->cVisible) ? pfl->aVisibleHeap[0] : NULL;
2569 case FLM_FINDVISIBLE_NEXT:
2570 if (!hItem->fVisible)
2572 if (hItem->index == (int)(pfl->cVisible-1))
2574 return pfl->aVisibleHeap[ hItem->index +1 ];
2582 int FastList_OnCommand_GetItemCount (HWND hList, BOOL fVisibleOnly)
2585 if ((pfl = GetFastList (hList)) == NULL)
2588 return (fVisibleOnly) ? pfl->cVisible : pfl->lItems->GetCount();
2592 HLISTITEM FastList_OnCommand_ItemFromPoint (HWND hList, POINT *pptClient, BOOL fStrict)
2594 HLISTITEM hItem = NULL;
2597 if ((pfl = GetFastList (hList)) != NULL)
2599 if (pfl->fSortBeforePaint)
2600 FastList_PerformSort (pfl);
2601 if (pfl->fSyncIndicesBeforePaint)
2602 FastList_RepairVisibilityIndices (pfl);
2604 // Adjust the client coordinates we were given based on the current
2605 // position of the scrollbars.
2607 LONG xField = pptClient->x + pfl->dxPixel;
2608 LONG yField = pptClient->y + pfl->dyPixel;
2610 // Every item's overall RECT is symmetrical, regardless of the
2611 // current view mode. Find out how big those RECTs are.
2614 FastList_CalcItemRect (pfl, 0, &rTemplate, !!pfl->hScrollH, !!pfl->hScrollV);
2616 // How large is the current client area?
2619 GetClientRect (pfl->hList, &rClient);
2621 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
2623 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
2625 rClient.top += FastList_GetHeaderHeight (pfl);
2627 // The specified point exists in exactly one item (or none at all).
2628 // Just which item that is depends on what the current view mode is.
2632 switch (pfl->dwStyle & FLS_VIEW_MASK)
2634 case FLS_VIEW_LARGE:
2636 LONG ixIndex = xField / cxRECT(rTemplate);
2637 LONG iyIndex = yField / cyRECT(rTemplate);
2639 LONG cxArray = cxRECT(rClient) / cxRECT(rTemplate);
2640 cxArray = max( cxArray, 1 );
2642 index = ixIndex + iyIndex * cxArray;
2646 case FLS_VIEW_SMALL:
2648 LONG ixIndex = xField / cxRECT(rTemplate);
2649 LONG iyIndex = yField / cyRECT(rTemplate);
2651 LONG cyArray = cyRECT(rClient) / cyRECT(rTemplate);
2652 cyArray = max( cyArray, 1 );
2654 index = iyIndex + ixIndex * cyArray;
2660 case FLS_VIEW_TREELIST:
2661 index = (yField - rClient.top) / cyRECT(rTemplate);
2665 if ((index >= 0) && (index < (int)pfl->cVisible))
2666 hItem = pfl->aVisibleHeap[ index ];
2668 // If there is indeed an item underneath that point, test the item's
2669 // regions--and our window styles--to see if a click on the specified
2670 // point actually *changes* that item.
2672 if (hItem && fStrict)
2676 FASTLISTITEMREGIONS reg;
2677 FastList_OnCommand_GetItemRegions (hList, hItem, ®, pptClient, &fHit);
2679 if (!PtInRect (®.rSelect, *pptClient))
2681 else if (PtInRect (®.rHighlight, *pptClient) && !fHit && (pfl->dwStyle & FLS_HIT_TEXTONLY))
2690 void FastList_OnCommand_GetItemRegions (HWND hList, HLISTITEM hItem, LPFASTLISTITEMREGIONS pReg, POINT *pptTest, BOOL *pfHit)
2693 if ((pfl = GetFastList (hList)) != NULL)
2695 if (pfl->fSortBeforePaint)
2696 FastList_PerformSort (pfl);
2697 if (pfl->fSyncIndicesBeforePaint)
2698 FastList_RepairVisibilityIndices (pfl);
2700 if (hItem && !hItem->fVisible && pReg)
2702 memset (pReg, 0x00, sizeof(FASTLISTITEMREGIONS));
2704 else if (hItem && hItem->fVisible)
2706 HDC hdc = CreateCompatibleDC (NULL);
2707 HFONT hfOld = (HFONT)SelectObject (hdc, pfl->hf);
2710 FastList_CalcItemRect (pfl, hItem->index, &rItem, !!pfl->hScrollH, !!pfl->hScrollV);
2711 rItem.left -= pfl->dxPixel;
2712 rItem.right -= pfl->dxPixel;
2713 rItem.top -= pfl->dyPixel;
2714 rItem.bottom -= pfl->dyPixel;
2716 FastList_CallPaintItem (pfl, hdc, FALSE, FALSE, hItem->index, &rItem, pReg, pptTest, pfHit);
2718 SelectObject (hdc, hfOld);
2725 LPFASTLISTTEXTCALLBACK FastList_OnCommand_GetTextCallback (HWND hList)
2728 if ((pfl = GetFastList (hList)) != NULL)
2729 return pfl->pfnText;
2735 void FastList_OnCommand_SetTextCallback (HWND hList, LPFASTLISTTEXTCALLBACK pfn, DWORD dwCookie)
2738 if ((pfl = GetFastList (hList)) != NULL)
2741 pfl->dwCookieText = dwCookie;
2747 * NOTIFICATION ROUTINES ______________________________________________________
2751 BOOL FastList_Notify_GetItemText (LPFASTLIST pfl, HLISTITEM hItem, int icol, LPTSTR pszText, size_t cchText, size_t *pcchRequired)
2753 FLN_GETITEMTEXT_PARAMS fln;
2754 fln.hdr.hwndFrom = pfl->hList;
2755 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2756 fln.hdr.code = FLN_GETITEMTEXT;
2757 fln.item.hItem = hItem;
2758 fln.item.icol = icol;
2759 fln.item.lParam = hItem->lpUser;
2760 fln.item.pszText = pszText;
2761 fln.item.cchTextMax = cchText;
2765 if (!(*pfl->pfnText)( pfl->hList, &fln, pfl->dwCookieText ))
2770 if (!GetParent (pfl->hList))
2772 if (!SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln))
2776 *pcchRequired = fln.item.cchTextMax;
2781 BOOL FastList_Notify_ItemChanged (LPFASTLIST pfl, HLISTITEM hItem)
2783 if (!GetParent (pfl->hList))
2786 FLN_ITEMCHANGED_PARAMS fln;
2787 fln.hdr.hwndFrom = pfl->hList;
2788 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2789 fln.hdr.code = FLN_ITEMCHANGED;
2791 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2795 BOOL FastList_Notify_AddItem (LPFASTLIST pfl, HLISTITEM hItem)
2797 if (!GetParent (pfl->hList))
2800 FLN_ADDITEM_PARAMS fln;
2801 fln.hdr.hwndFrom = pfl->hList;
2802 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2803 fln.hdr.code = FLN_ADDITEM;
2805 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2809 BOOL FastList_Notify_RemoveItem (LPFASTLIST pfl, HLISTITEM hItem)
2811 if (!GetParent (pfl->hList))
2814 FLN_REMOVEITEM_PARAMS fln;
2815 fln.hdr.hwndFrom = pfl->hList;
2816 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2817 fln.hdr.code = FLN_REMOVEITEM;
2819 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2823 BOOL FastList_Notify_ColumnClick (LPFASTLIST pfl, int icol, BOOL fDouble)
2825 if (!GetParent (pfl->hList))
2828 FLN_COLUMNCLICK_PARAMS fln;
2829 fln.hdr.hwndFrom = pfl->hList;
2830 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2831 fln.hdr.code = FLN_COLUMNCLICK;
2833 fln.fDouble = fDouble;
2834 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2838 BOOL FastList_Notify_ColumnResize (LPFASTLIST pfl, int icol, LONG cxWidth)
2840 if (!GetParent (pfl->hList))
2843 FLN_COLUMNRESIZE_PARAMS fln;
2844 fln.hdr.hwndFrom = pfl->hList;
2845 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2846 fln.hdr.code = FLN_COLUMNRESIZE;
2848 fln.cxWidth = cxWidth;
2849 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2853 BOOL FastList_Notify_ItemSelect (LPFASTLIST pfl)
2855 if (!GetParent (pfl->hList))
2858 FLN_ITEMSELECT_PARAMS fln;
2859 fln.hdr.hwndFrom = pfl->hList;
2860 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2861 fln.hdr.code = FLN_ITEMSELECT;
2862 fln.hItem = pfl->hSelectFirst;
2863 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2867 BOOL FastList_Notify_ItemExpand (LPFASTLIST pfl, HLISTITEM hItem)
2869 if (!GetParent (pfl->hList))
2872 FLN_ITEMEXPAND_PARAMS fln;
2873 fln.hdr.hwndFrom = pfl->hList;
2874 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2875 fln.hdr.code = FLN_ITEMEXPAND;
2877 fln.fExpanded = hItem->fExpanded;
2878 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2882 BOOL FastList_Notify_Generic (LPFASTLIST pfl, DWORD dwCode)
2884 if (!GetParent (pfl->hList))
2888 hdr.hwndFrom = pfl->hList;
2889 hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2891 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)hdr.idFrom, (LPARAM)&hdr);
2895 BOOL FastList_Notify_Drag (LPFASTLIST pfl, DWORD dwCode, LPFLN_DRAG_PARAMS pfln)
2897 if (!GetParent (pfl->hList))
2900 pfln->hdr.hwndFrom = pfl->hList;
2901 pfln->hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2902 pfln->hdr.code = dwCode;
2903 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)pfln->hdr.idFrom, (LPARAM)pfln);
2908 * SUPPORT ROUTINES ___________________________________________________________
2912 void FastList_Repaint (LPFASTLIST pfl)
2914 if ((pfl->fRepaintRequired = (pfl->nBegin) ? TRUE : FALSE) == FALSE)
2917 GetClientRect (pfl->hList, &rClient);
2918 InvalidateRect (pfl->hList, &rClient, TRUE);
2919 UpdateWindow (pfl->hList);
2924 HLISTITEM FastList_CreateItem (LPFASTLIST pfl)
2926 HLISTITEM hItem = New (LISTITEM);
2927 memset (hItem, 0x00, sizeof(LISTITEM));
2928 hItem->fExpanded = TRUE;
2933 void FastList_DeleteItem (LPFASTLIST pfl, HLISTITEM hItem)
2937 // Remove any children of this item, even if we're not in
2938 // treeview mode now.
2940 while (hItem->hTreeChild)
2942 FastList_DeleteItem (pfl, hItem->hTreeChild);
2945 FastList_Notify_RemoveItem (pfl, hItem); // notify *before* delete
2947 if (pfl->hFocused == hItem)
2948 pfl->hFocused = FALSE;
2950 // Unlink this item from the List chain
2952 if (pfl->hListFirst == hItem)
2953 pfl->hListFirst = hItem->hListNext;
2954 if (hItem->hListPrevious)
2955 hItem->hListPrevious->hListNext = hItem->hListNext;
2956 if (hItem->hListNext)
2957 hItem->hListNext->hListPrevious = hItem->hListPrevious;
2959 // Unlink this item from the Tree chain
2961 if (pfl->hTreeFirst == hItem)
2962 pfl->hTreeFirst = hItem->hTreeNext;
2963 if (hItem->hTreePrevious)
2964 hItem->hTreePrevious->hTreeNext = hItem->hTreeNext;
2965 if (hItem->hTreeNext)
2966 hItem->hTreeNext->hTreePrevious = hItem->hTreePrevious;
2967 if (hItem->hTreeParent && (hItem->hTreeParent->hTreeChild == hItem))
2968 hItem->hTreeParent->hTreeChild = hItem->hTreeNext;
2970 // Unlink this item from the Selection chain
2972 if (hItem->hSelectPrevious)
2973 hItem->hSelectPrevious->hSelectNext = hItem->hSelectNext;
2974 if (hItem->hSelectNext)
2975 hItem->hSelectNext->hSelectPrevious = hItem->hSelectPrevious;
2976 if (pfl->hSelectFirst == hItem)
2977 pfl->hSelectFirst = hItem->hSelectNext;
2978 if (pfl->hAnchor == hItem)
2979 pfl->hAnchor = NULL;
2980 hItem->hSelectPrevious = NULL;
2981 hItem->hSelectNext = NULL;
2983 // If we're holding onto this item as the next guy who we should
2984 // ensure is visible, forget about it there too.
2986 if (pfl->hEnsureVisible == hItem)
2987 pfl->hEnsureVisible = NULL;
2989 // Remove this item from the hashlist, and deallocate any memory
2990 // associated with it.
2992 pfl->lItems->Remove (hItem);
2994 if (hItem->apszText)
2996 for (size_t iCol = 0; iCol < hItem->cpszText; ++iCol)
2998 if (hItem->apszText[ iCol ] != NULL)
2999 Free (hItem->apszText[ iCol ]);
3001 Free (hItem->apszText);
3005 memset (hItem, 0xFE, sizeof(_FASTLISTITEM));
3009 pfl->fSyncScrollBeforePaint = TRUE;
3010 pfl->fSyncIndicesBeforePaint = TRUE;
3015 int FastList_GetListHeight (LPFASTLIST pfl)
3017 static HFONT hfLast = NULL;
3018 static int cyLast = 0;
3020 if (!cyLast || (pfl->hf != hfLast))
3025 HDC hdc = CreateCompatibleDC (NULL);
3026 HFONT hfOld = (HFONT)SelectObject (hdc, pfl->hf);
3027 GetTextMetrics (hdc, &tm);
3028 SelectObject (hdc, hfOld);
3031 cyLast = tm.tmHeight + cyABOVE_LIST_TEXT + cyBELOW_LIST_TEXT;
3032 cyLast = max( cyLast, GetSystemMetrics(SM_CYSMICON) );
3034 cyLast ++; // make the height even (for vertical dotted lines)
3041 int FastList_GetListWidth (LPFASTLIST pfl)
3045 for (size_t iColumn = 0; iColumn < pfl->cColumns; ++iColumn)
3046 if (pfl->aColumns[ iColumn ].pszText)
3047 cxWidth += pfl->aColumns[ iColumn ].cxy;
3049 if (cxWidth == 0) // no columns specified? pretend there's just one.
3052 GetClientRect (pfl->hList, &rClient);
3054 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
3055 cxWidth = cxRECT(rClient);
3062 LONG FastList_GetHeaderHeight (LPFASTLIST pfl)
3065 HDC hdc = CreateCompatibleDC (NULL);
3066 HFONT hfOld = (HFONT)SelectObject (hdc, pfl->hf);
3067 GetTextMetrics (hdc, &tm);
3068 SelectObject (hdc, hfOld);
3070 return 4*GetSystemMetrics(SM_CYBORDER) + tm.tmHeight;
3074 void FastList_GetHeaderRect (LPFASTLIST pfl, RECT *prHeader)
3076 GetClientRect (pfl->hList, prHeader);
3077 prHeader->bottom = prHeader->top + FastList_GetHeaderHeight (pfl);
3081 void FastList_UpdateColumn (LPFASTLIST pfl, int iColumn)
3083 if ((iColumn >= 0) && (iColumn < (int)pfl->cColumns) && (pfl->aColumns[ iColumn ].pszText))
3086 memset (&col, 0x00, sizeof(col));
3087 col.mask |= HDI_WIDTH;
3088 Header_GetItem (pfl->hHeader, iColumn, &col);
3090 if (pfl->aColumns[ iColumn ].cxy != col.cxy)
3092 pfl->aColumns[ iColumn ].cxy = col.cxy;
3093 pfl->fSyncScrollBeforePaint = TRUE;
3094 FastList_Notify_ColumnResize (pfl, iColumn, col.cxy);
3095 FastList_Repaint (pfl);
3101 void FastList_SyncHeader (LPFASTLIST pfl)
3103 if ((pfl->fSyncHeaderRequired = (pfl->nBegin) ? TRUE : FALSE) == FALSE)
3105 BOOL fNeedsHeader = ((pfl->dwStyle & FLS_VIEW_LIST) == FLS_VIEW_LIST);
3106 BOOL fNoSortHeader = (pfl->dwStyle & FLS_NOSORTHEADER);
3108 if (pfl->cColumns == 0)
3109 fNeedsHeader = FALSE;
3113 FastList_GetHeaderRect (pfl, &rHeader);
3115 if (fNeedsHeader && !pfl->hHeader)
3117 pfl->hHeader = CreateWindow (WC_HEADER, TEXT(""),
3118 0x80 | WS_CHILD | WS_VISIBLE | ((fNoSortHeader) ? 0 : HDS_BUTTONS),
3119 rHeader.left, rHeader.top,
3120 cxRECT(rHeader), cyRECT(rHeader),
3126 SendMessage (pfl->hHeader, WM_SETFONT, (WPARAM)(pfl->hf), 0);
3128 else if (fNeedsHeader && pfl->hHeader)
3130 DWORD dwStyle = GetWindowLong (pfl->hHeader, GWL_STYLE);
3132 dwStyle &= ~HDS_BUTTONS;
3134 dwStyle |= HDS_BUTTONS;
3135 SetWindowLong (pfl->hHeader, GWL_STYLE, dwStyle);
3137 SetWindowPos (pfl->hHeader, 0,
3138 rHeader.left, rHeader.top, cxRECT(rHeader), cyRECT(rHeader),
3139 SWP_NOACTIVATE | SWP_NOZORDER);
3141 else if (!fNeedsHeader && pfl->hHeader)
3143 DestroyWindow (pfl->hHeader);
3144 pfl->hHeader = NULL;
3147 // If we ended up with a header window, update its columns.
3151 while (Header_DeleteItem (pfl->hHeader, 0))
3153 for (size_t iCol = 0; iCol < pfl->cColumns; ++iCol)
3154 Header_InsertItem (pfl->hHeader, iCol, &pfl->aColumns[ iCol ]);
3157 pfl->fSyncScrollBeforePaint = TRUE;
3162 void FastList_SyncScroll (LPFASTLIST pfl)
3164 pfl->fSyncScrollBeforePaint = FALSE;
3167 GetClientRect (pfl->hList, &rClient);
3169 rClient.top += FastList_GetHeaderHeight (pfl);
3174 // First find out how much space we'd need, horizontally and vertically,
3175 // to display all the items we can. Remember that the number of items
3176 // we can display changes depending on whether the scrollbars appear or
3179 BOOL fAllowHScroll = ((pfl->dwStyle & FLS_VIEW_MASK) != FLS_VIEW_LARGE);
3180 BOOL fAllowVScroll = ((pfl->dwStyle & FLS_VIEW_MASK) != FLS_VIEW_SMALL);
3182 BOOL fNeedHScroll = FALSE;
3183 BOOL fNeedVScroll = FALSE;
3185 FastList_CalcFieldSize (pfl, &cxField, &cyField, fNeedHScroll, fNeedVScroll);
3187 if ( (cxField > cxRECT(rClient)) && (fAllowHScroll) )
3188 fNeedHScroll = TRUE;
3189 if ( (cyField > cyRECT(rClient)) && (fAllowVScroll) )
3190 fNeedVScroll = TRUE;
3192 FastList_CalcFieldSize (pfl, &cxField, &cyField, fNeedHScroll, fNeedVScroll);
3194 RECT rTest = rClient;
3196 rTest.right -= GetSystemMetrics(SM_CXVSCROLL);
3198 rTest.bottom -= GetSystemMetrics(SM_CYHSCROLL);
3200 if ( (cxField > cxRECT(rTest)) && (fAllowHScroll) )
3201 fNeedHScroll = TRUE;
3202 if ( (cyField > cyRECT(rTest)) && (fAllowVScroll) )
3203 fNeedVScroll = TRUE;
3205 // Now that we know the field size, create, remove or position
3208 if (pfl->hScrollV && !fNeedVScroll)
3210 DestroyWindow (pfl->hScrollV);
3211 pfl->hScrollV = NULL;
3214 else if (fNeedVScroll)
3216 RECT rScroll = rClient;
3217 rScroll.left = rScroll.right - GetSystemMetrics (SM_CXVSCROLL);
3219 rScroll.bottom -= GetSystemMetrics (SM_CYHSCROLL);
3223 pfl->hScrollV = CreateWindow ("ScrollBar", TEXT(""),
3224 WS_CHILD | WS_VISIBLE | SBS_VERT,
3225 rScroll.left, rScroll.top,
3226 cxRECT(rScroll), cyRECT(rScroll),
3234 SetWindowPos (pfl->hScrollV, 0,
3235 rScroll.left, rScroll.top, cxRECT(rScroll), cyRECT(rScroll),
3236 SWP_NOZORDER | SWP_NOACTIVATE);
3239 else // (!fNeedVScroll)
3244 if (pfl->hScrollH && !fNeedHScroll)
3246 DestroyWindow (pfl->hScrollH);
3247 pfl->hScrollH = NULL;
3250 else if (fNeedHScroll)
3252 RECT rScroll = rClient;
3253 rScroll.top = rScroll.bottom - GetSystemMetrics (SM_CYHSCROLL);
3255 rScroll.right -= GetSystemMetrics (SM_CXVSCROLL);
3259 pfl->hScrollH = CreateWindow ("ScrollBar", TEXT(""),
3260 WS_CHILD | WS_VISIBLE | SBS_HORZ,
3261 rScroll.left, rScroll.top,
3262 cxRECT(rScroll), cyRECT(rScroll),
3270 SetWindowPos (pfl->hScrollH, 0,
3271 rScroll.left, rScroll.top, cxRECT(rScroll), cyRECT(rScroll),
3272 SWP_NOZORDER | SWP_NOACTIVATE);
3275 else // (!fNeedHScroll)
3280 FastList_SyncScrollPos (pfl);
3284 void FastList_SyncScrollPos (LPFASTLIST pfl)
3287 GetClientRect (pfl->hList, &rClient);
3289 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
3291 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
3293 rClient.top += FastList_GetHeaderHeight (pfl);
3297 FastList_CalcFieldSize (pfl, &cxField, &cyField, !!pfl->hScrollH, !!pfl->hScrollV);
3300 pfl->dxPixel = limit( 0, pfl->dxPixel, (cxField-cxRECT(rClient)) );
3302 pfl->dyPixel = limit( 0, pfl->dyPixel, (cyField-cyRECT(rClient)) );
3307 memset (&si, 0x00, sizeof(SCROLLINFO));
3308 si.cbSize = sizeof(si);
3309 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
3312 si.nPage = cxRECT(rClient);
3313 si.nPos = pfl->dxPixel;
3314 SetScrollInfo (pfl->hScrollH, SB_CTL, &si, TRUE);
3319 memset (&si, 0x00, sizeof(SCROLLINFO));
3320 si.cbSize = sizeof(si);
3321 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
3324 si.nPage = cyRECT(rClient);
3325 si.nPos = pfl->dyPixel;
3326 SetScrollInfo (pfl->hScrollV, SB_CTL, &si, TRUE);
3329 FastList_ScrollHeader (pfl);
3333 void FastList_CalcFieldSize (LPFASTLIST pfl, LONG *pcxField, LONG *pcyField, BOOL fScrollH, BOOL fScrollV)
3336 GetClientRect (pfl->hList, &rClient);
3338 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
3340 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
3342 rClient.top += FastList_GetHeaderHeight (pfl);
3348 FastList_CalcItemRect (pfl, 0, &rItem, fScrollH, fScrollV);
3353 switch (pfl->dwStyle & FLS_VIEW_MASK)
3355 case FLS_VIEW_LARGE:
3356 cxArray = cxRECT(rClient) / cxRECT(rItem);
3357 cxArray = max (cxArray, 1);
3359 cyArray = DivRoundUp (pfl->cVisible, cxArray);
3362 case FLS_VIEW_SMALL:
3363 cyArray = cyRECT(rClient) / cyRECT(rItem);
3364 cyArray = max (cyArray, 1);
3366 cxArray = DivRoundUp (pfl->cVisible, cyArray);
3371 case FLS_VIEW_TREELIST:
3373 cyArray = pfl->cVisible;
3377 *pcxField = cxArray * cxRECT(rItem);
3378 *pcyField = cyArray * cyRECT(rItem);
3382 void FastList_CalcItemRect (LPFASTLIST pfl, int index, RECT *prItem, BOOL fScrollH, BOOL fScrollV)
3384 SetRectEmpty (prItem);
3387 GetClientRect (pfl->hList, &rClient);
3389 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
3391 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
3393 rClient.top += FastList_GetHeaderHeight (pfl);
3395 switch (pfl->dwStyle & FLS_VIEW_MASK)
3397 case FLS_VIEW_LARGE:
3399 // Large layout shows a two-dimensional list of 32x32 icons,
3400 // each followed beneath by text. The layout of the grid is
3401 // determined by well-known system metrics. There will be no
3402 // horizontal scrollbar; just a vertical one (if necessary).
3403 // Slots are filled in left-to-right, top-to-bottom.
3405 LONG cxRect = GetSystemMetrics (SM_CXICONSPACING);
3406 LONG cyRect = GetSystemMetrics (SM_CYICONSPACING);
3407 int cxLayout = cxRECT(rClient) / cxRect;
3408 cxLayout = max (cxLayout, 1);
3410 int vIndex = index / cxLayout; // 0 = top row
3411 int hIndex = index % cxLayout; // 0 = left row
3413 prItem->left = hIndex * cxRect;
3414 prItem->right = prItem->left + cxRect;
3415 prItem->top = vIndex * cyRect;
3416 prItem->bottom = prItem->top + cyRect;
3420 case FLS_VIEW_SMALL:
3422 // Small layout is similar: it shows a two-dimensional list of
3423 // 16x16 icons, each followed to the right by text. The vertical
3424 // layout of the grid is the same as the list default vertical
3425 // size; the horizontal layout is twice the default system metric.
3426 // Another difference: Small mode uses only a horizontal scrollbar,
3427 // not a vertical one. Slots are filled in top-to-bottom,
3430 LONG cxRect = GetSystemMetrics (SM_CXICONSPACING) * 2;
3431 LONG cyRect = FastList_GetListHeight (pfl);
3432 int cyLayout = cyRECT(rClient) / cyRect;
3433 cyLayout = max (cyLayout, 1);
3435 int hIndex = index / cyLayout; // 0 = left row
3436 int vIndex = index % cyLayout; // 0 = top row
3438 prItem->left = hIndex * cxRect;
3439 prItem->right = prItem->left + cxRect;
3440 prItem->top = vIndex * cyRect;
3441 prItem->bottom = prItem->top + cyRect;
3447 case FLS_VIEW_TREELIST:
3449 // List and Tree layouts are fairly straight-forward: they each show
3450 // a one-dimensional array of items, each of which runs horizontally
3451 // from edge to edge. The vertical layout of the grid is the default
3452 // vertical size (see FastList_GetListHeight()). A vertical scrollbar
3453 // is applied if necessary; a horizontal scrollbar is added for the
3456 LONG cyRect = FastList_GetListHeight (pfl);
3459 prItem->right = FastList_GetListWidth (pfl);
3460 prItem->top = rClient.top + index * cyRect;
3461 prItem->bottom = prItem->top + cyRect;
3468 void FastList_CallPaintItem (LPFASTLIST pfl, HDC hdc, BOOL fDraw, BOOL fDragImage, int iItem, RECT *prItem, LPFASTLISTITEMREGIONS pReg, POINT *pptTest, BOOL *pfHit)
3470 FASTLISTDRAWITEM di;
3471 memset (&di, 0x00, sizeof(di));
3474 di.fDragImage = fDragImage;
3475 di.hWnd = pfl->hList;
3476 di.hItem = pfl->aVisibleHeap[ iItem ];
3477 di.lParam = di.hItem->lpUser;
3481 di.ptTextTest = *pptTest;
3485 FastList_OnPaintItem (pfl, &di);
3486 // if (GetParent (pfl->hList))
3487 // SendMessage (GetParent (pfl->hList), WM_DRAWITEM, (WPARAM)GetWindowLong (pfl->hList, GWL_ID), (LPARAM)&di);
3489 // FastList_OnPaintItem (pfl, &di);
3492 *pfHit = di.fTextTestHit;
3494 memcpy (pReg, &di.reg, sizeof(FASTLISTITEMREGIONS));
3498 LPTSTR FastList_GetColumnText (LPFASTLIST pfl, HLISTITEM hItem, int icol, BOOL fAlternateBuffer)
3500 if ((icol < (int)hItem->cpszText) && (hItem->apszText[ icol ] != NULL))
3501 return hItem->apszText[ icol ];
3503 if (!GetParent (pfl->hList))
3506 // We'll have to send a message to the parent window, and hope the user
3507 // catches it to tell us what the text should be. We have two dynamically-
3508 // allocated buffers we use for storing text.
3510 static LPTSTR pszTextA = NULL;
3511 static size_t cchTextA = 0;
3513 static LPTSTR pszTextB = NULL;
3514 static size_t cchTextB = 0;
3516 LPTSTR *ppszText = (fAlternateBuffer) ? &pszTextB : &pszTextA;
3517 size_t *pcchText = (fAlternateBuffer) ? &cchTextB : &cchTextA;
3519 for (size_t cchRequired = 256; ; )
3521 if (!*pcchText || (*pcchText < cchRequired))
3525 if ((*ppszText = (LPTSTR)Allocate (sizeof(TCHAR)*(1+cchRequired))) == NULL)
3528 *pcchText = cchRequired;
3533 *(*ppszText) = TEXT('\0');
3534 if (!FastList_Notify_GetItemText (pfl, hItem, icol, *ppszText, *pcchText, &cchRequired))
3536 if (cchRequired <= *pcchText)
3540 return (*ppszText) ? (*ppszText) : TEXT("");
3544 void FastList_PerformSort (LPFASTLIST pfl)
3546 pfl->fSortBeforePaint = FALSE;
3548 // Sorting would be easy, except that we have to handle the tree case.
3549 // For a tree, "sorting" means ordering *sibling* items--we make no
3550 // attempt to order cousins, but all the children under a given parent
3551 // must be sorted. We don't sort the Visible heap directly--instead,
3552 // we sort the hashlist of items, and correct the Visible heap to match.
3553 // That way, the user can later expand/collapse items in the tree
3554 // without our having to re-sort.
3556 // In sorting the hashlist items, we're not so much interested in their
3557 // order of enumeration as we're interested in pointing each object's
3558 // {hPrevious} and {hNext} pointers to the right objects. (When sorting
3559 // a tree, this is even more clear; hPrevious and hNext point only to
3560 // siblings.) To perform a sort on these items, we must generate an
3561 // array of objects, qsort the array, then update the items' pointers.
3562 // That array of objects is in {fg}, the fastlist global structure.
3564 // The flow of sorting a list is:
3565 // 1- fill an array with HLISTITEM pointers for all items in the list
3566 // 2- qsort the array, using the {pfl->fnSort} comparison function
3567 // 3- update the HLISTITEMs' {hPrevious}, {hNext}, and {index} members
3568 // 4- call FastList_Update to fix the hash on the revised {index} members
3570 // The flow for sorting a tree is more complex:
3571 // 1- set indexNext = 0
3572 // 2- call SortLevel(NULL), to specify that we're sorting root items)
3573 // SortLevel(hParent):
3574 // 3- fill an array with HLISTITEM pointers for this item and siblings
3575 // 4- qsort the array, using the {pfl->fnSort} comparison function
3576 // 5- update the HLISTITEMs' {hPrevious}, {hNext} members
3577 // 6- use {indexNext++} to assign index values to all visible items
3578 // 7- if hParent->hTreeChild, call SortLevel(hParent->hTreeChild)
3579 // 8- call FastList_Update to fix the hash on the revised {index} members
3581 FastList_Begin (pfl->hList);
3584 if ((cItems = pfl->lItems->GetCount()) != 0)
3586 if (OpenGlobalArray (cItems))
3589 FastList_PerformSortLevel (pfl, NULL, ((pfl->dwStyle & FLS_VIEW_TREE) == FLS_VIEW_TREE));
3595 pfl->fSyncIndicesBeforePaint = TRUE;
3596 FastList_End (pfl->hList);
3600 void FastList_PerformSortLevel (LPFASTLIST pfl, HLISTITEM hParent, BOOL fTreeSort)
3602 // Find the first item in the chain that we're going to sort.
3603 // Then walk that chain, filling in the global array of HLISTITEMs
3604 // If we're sorting the thing as a tree, only add {hItem}'s siblings
3605 // to the fg.aObjects[] array; if we're sorting as a list, add
3606 // all items. Add items regardless of whether they're invisible.
3608 size_t cObjectsToSort = 0;
3612 for (HLISTITEM hItem = (hParent) ? hParent->hTreeChild : pfl->hTreeFirst; hItem; hItem = hItem->hTreeNext)
3613 fg.aObjects[ cObjectsToSort++ ] = hItem;
3615 else // Viewing by list, so sort items as if there were no tree structure
3617 for (HLISTITEM hItem = pfl->hListFirst; hItem; hItem = hItem->hListNext)
3618 fg.aObjects[ cObjectsToSort++ ] = hItem;
3621 if (cObjectsToSort != 0)
3623 // Perform a qsort on the array
3625 FastList_SortFunction (0, 0);
3626 qsort (fg.aObjects, cObjectsToSort, sizeof(HLISTITEM), FastList_SortFunction);
3628 // Walk the array, adjusting objects' next/previous pointers.
3632 HLISTITEM hTreePrevious = NULL;
3633 for (size_t iObject = 0; iObject < cObjectsToSort; ++iObject)
3635 fg.aObjects[ iObject ]->hTreePrevious = hTreePrevious;
3636 fg.aObjects[ iObject ]->hTreeNext = (iObject < cObjectsToSort-1) ? fg.aObjects[ iObject+1 ] : NULL;
3637 hTreePrevious = fg.aObjects[ iObject ];
3639 if (hParent == NULL)
3640 pfl->hTreeFirst = fg.aObjects[0];
3642 hParent->hTreeChild = fg.aObjects[0];
3644 else // (!(pfl->dwStyle & FLS_VIEW_TREE))
3646 HLISTITEM hListPrevious = NULL;
3647 for (size_t iObject = 0; iObject < cObjectsToSort; ++iObject)
3649 fg.aObjects[ iObject ]->hListPrevious = hListPrevious;
3650 fg.aObjects[ iObject ]->hListNext = (iObject < cObjectsToSort-1) ? fg.aObjects[ iObject+1 ] : NULL;
3651 hListPrevious = fg.aObjects[ iObject ];
3653 pfl->hListFirst = fg.aObjects[0];
3656 // If this is to be a treesort, walk the chain ascending children
3657 // recursively as we come to them.
3661 for (HLISTITEM hWalk = fg.aObjects[0]; hWalk; hWalk = hWalk->hTreeNext)
3663 if (hWalk && hWalk->hTreeChild)
3664 FastList_PerformSortLevel (pfl, hWalk, fTreeSort);
3671 int __cdecl FastList_SortFunction (const void *lp1, const void *lp2)
3673 if (fg.pfl->pfnSort)
3674 return (*(fg.pfl->pfnSort))(fg.pfl->hList, ((lp1) ? (*(HLISTITEM*)lp1) : 0), ((lp1) ? (*(HLISTITEM*)lp1)->lpUser : 0), ((lp2) ? (*(HLISTITEM*)lp2) : 0), ((lp2) ? (*(HLISTITEM*)lp2)->lpUser : 0));
3676 return FastList_SortFunc_AlphaNumeric (fg.pfl->hList, ((lp1) ? (*(HLISTITEM*)lp1) : 0), ((lp1) ? (*(HLISTITEM*)lp1)->lpUser : 0), ((lp2) ? (*(HLISTITEM*)lp2) : 0), ((lp2) ? (*(HLISTITEM*)lp2)->lpUser : 0));
3680 void FastList_RepairOneVisibilityFlag (LPFASTLIST pfl, HLISTITEM hItem)
3682 // There are two reasons to hide an item: because we're in tree mode
3683 // and one of its parent is collapsed, or because we're not in tree mode
3684 // and it has the only-show-me-in-tree-mode flag set.
3686 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE) ? TRUE : FALSE;
3688 hItem->fVisible = TRUE;
3690 if ((hItem->dwFlags & FLIF_TREEVIEW_ONLY) && (!fTreeMode))
3692 hItem->fVisible = FALSE;
3696 for (HLISTITEM hParent = hItem->hTreeParent; hParent; hParent = hParent->hTreeParent)
3698 if ((!hParent->fVisible) || (!hParent->fExpanded))
3700 hItem->fVisible = FALSE;
3708 void FastList_RepairVisibilityFlags (LPFASTLIST pfl, HLISTITEM hParent, BOOL fForceHidden)
3710 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE) ? TRUE : FALSE;
3712 // This routine fixes the {fVisible} flags for all items, based on
3713 // their FLIF_TREEVIEW_ONLY flags and whether their parent items are
3716 // Technically we could acheive this by a normal FindFirst()/FindNext()
3717 // enumeration of the items in the hashlist; on each item, we'd check
3718 // its parents and flags. But we can be a smidgen faster by walking
3719 // the list in tree order--that way, when we hit a collapsed tree, we
3720 // can mark all its children as hidden without any additional work.
3722 // Naturally, since we're a FASTlist, we'll take any little smidgen of
3723 // speed we can get. Find the first item in the chain that we're going
3726 for (HLISTITEM hItem = (hParent) ? hParent->hTreeChild : pfl->hTreeFirst; hItem; hItem = hItem->hTreeNext)
3728 // If we were passed {fForceHidden==TRUE}, we know that we're in tree
3729 // mode and one of our parents is collapsed--that's great, because it
3730 // means we can set fVisible=FALSE without thinking. If we weren't passed
3731 // that flag, we know that we're either not in treeview mode or none
3732 // of our parents are collapsed--so we don't have to walk up the
3733 // list of parents to check that.
3736 hItem->fVisible = FALSE;
3738 hItem->fVisible = fTreeMode || !(hItem->dwFlags & FLIF_TREEVIEW_ONLY);
3740 // We've fixed this item. If it has any children, fix them too.
3741 // Remember that we may be able to blindly tell children to be hidden.
3743 if (hItem->hTreeChild)
3745 BOOL fChildrenHidden = fForceHidden;
3746 if (fTreeMode && (!hItem->fExpanded || !hItem->fVisible))
3747 fChildrenHidden = TRUE;
3749 FastList_RepairVisibilityFlags (pfl, hItem, fChildrenHidden);
3755 void FastList_RepairVisibilityIndices (LPFASTLIST pfl, HLISTITEM hParent)
3757 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE) ? TRUE : FALSE;
3759 if (hParent == NULL) // Starting a new repair? Initialize pfl->cVisible.
3762 pfl->fSyncIndicesBeforePaint = FALSE;
3765 // This routine fixes the {index} settings for all items, by walking
3766 // the list/tree in (presumably already-sorted) order and making
3767 // sure all items with {fVisible} set have smoothly increasing indices.
3768 // It rebuilds the Visible heap as it goes along.
3770 for (HLISTITEM hItem = (!fTreeMode) ? (pfl->hListFirst) : (hParent) ? (hParent->hTreeChild) : (pfl->hTreeFirst);
3772 hItem = (!fTreeMode) ? (hItem->hListNext) : (hItem->hTreeNext))
3774 if (hItem->fVisible)
3776 hItem->index = pfl->cVisible;
3778 // Update the aVisibleHeap to match the new item.
3780 REALLOC (pfl->aVisibleHeap, pfl->cVisibleHeap, 1+ hItem->index, cREALLOC_VISIBLEHEAP(pfl));
3781 pfl->aVisibleHeap[ hItem->index ] = hItem;
3785 if (fTreeMode && hItem->hTreeChild)
3787 FastList_RepairVisibilityIndices (pfl, hItem);
3793 void FastList_ScrollHeader (LPFASTLIST pfl)
3798 GetWindowRect (pfl->hHeader, &rHeader);
3800 LONG cx = rHeader.right + pfl->dxPixel;
3802 SetWindowPos (pfl->hHeader, 0,
3803 0 - pfl->dxPixel, 0, cx, cyRECT(rHeader),
3804 SWP_NOZORDER | SWP_NOACTIVATE);
3809 void FastList_PerformSelectTest (LPFASTLIST pfl, HLISTITEM hItem)
3811 if (pfl->hSelectFirst && !hItem->fSelected)
3813 BOOL fMultiple = (pfl->dwStyle & FLS_SELECTION_MULTIPLE);
3814 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE);
3815 BOOL fLevel = (pfl->dwStyle & (FLS_SELECTION_LEVEL & ~FLS_SELECTION_MULTIPLE));
3816 BOOL fSibling = (pfl->dwStyle & (FLS_SELECTION_SIBLING & ~FLS_SELECTION_MULTIPLE));
3818 BOOL fClearSelection = FALSE;
3822 fClearSelection = TRUE;
3828 size_t iLevelItem = 0;
3829 for (HLISTITEM hParent = hItem->hTreeParent; hParent; hParent = hParent->hTreeParent)
3832 size_t iLevelSelected = 0;
3833 for (hParent = pfl->hSelectFirst->hTreeParent; hParent; hParent = hParent->hTreeParent)
3836 if (iLevelItem != iLevelSelected)
3837 fClearSelection = TRUE;
3842 BOOL fFound = FALSE;
3843 for (HLISTITEM hSearch = hItem->hTreePrevious; !fFound && hSearch; hSearch = hSearch->hTreePrevious)
3845 if (hSearch == pfl->hSelectFirst)
3848 for (hSearch = hItem->hTreeNext; !fFound && hSearch; hSearch = hSearch->hTreeNext)
3850 if (hSearch == pfl->hSelectFirst)
3854 fClearSelection = TRUE;
3858 if (fClearSelection)
3860 FastList_OnCommand_SelectItem (pfl->hList, NULL, FALSE);
3866 void FastList_PerformSelectItem (LPFASTLIST pfl, HLISTITEM hItem, BOOL fSelect)
3868 if (hItem->fSelected != fSelect)
3870 if ((hItem->fSelected = fSelect) == FALSE)
3872 if (hItem->hSelectPrevious)
3873 hItem->hSelectPrevious->hSelectNext = hItem->hSelectNext;
3874 if (hItem->hSelectNext)
3875 hItem->hSelectNext->hSelectPrevious = hItem->hSelectPrevious;
3876 if (pfl->hSelectFirst == hItem)
3877 pfl->hSelectFirst = hItem->hSelectNext;
3878 if (pfl->hAnchor == hItem)
3879 pfl->hAnchor = NULL;
3880 hItem->hSelectPrevious = NULL;
3881 hItem->hSelectNext = NULL;
3883 else // (hItem->fSelected == TRUE)
3885 if ((hItem->hSelectNext = pfl->hSelectFirst) != NULL)
3886 hItem->hSelectNext->hSelectPrevious = hItem;
3887 pfl->hSelectFirst = hItem;
3888 if (hItem->hSelectNext == NULL)
3889 pfl->hAnchor = hItem;
3892 FastList_Notify_ItemChanged (pfl, hItem);
3893 FastList_Repaint (pfl);
3898 void FastList_PerformSelectRange (LPFASTLIST pfl, HLISTITEM hItem1, HLISTITEM hItem2)
3900 if (hItem1->fVisible && hItem2->fVisible)
3902 FastList_Begin (pfl->hList);
3904 int iIndex1 = min (hItem1->index, hItem2->index);
3905 int iIndex2 = max (hItem1->index, hItem2->index);
3906 for (int iIndex = iIndex1; iIndex <= iIndex2; ++iIndex)
3907 FastList_SelectItem (pfl->hList, pfl->aVisibleHeap[ iIndex ], TRUE);
3909 FastList_Repaint (pfl);
3910 FastList_End (pfl->hList);
3915 void FastList_PerformEnsureVisible (LPFASTLIST pfl)
3917 if (pfl->hEnsureVisible && pfl->lItems->fIsInList (pfl->hEnsureVisible))
3920 GetClientRect (pfl->hList, &rClient);
3922 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
3924 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
3926 rClient.top += FastList_GetHeaderHeight (pfl);
3929 FastList_CalcItemRect (pfl, pfl->hEnsureVisible->index, &rItem, !!pfl->hScrollH, !!pfl->hScrollV);
3931 if (rItem.right > (cxRECT(rClient) + pfl->dxPixel))
3932 pfl->dxPixel = rItem.right - cxRECT(rClient);
3933 if (rItem.left < pfl->dxPixel)
3934 pfl->dxPixel = rItem.left;
3935 if (rItem.bottom > (pfl->dyPixel + rClient.bottom))
3936 pfl->dyPixel = rItem.bottom - rClient.bottom;
3937 if (rItem.top < (pfl->dyPixel + rClient.top))
3938 pfl->dyPixel = rItem.top - rClient.top;
3940 pfl->hEnsureVisible = NULL;
3941 FastList_SyncScrollPos (pfl);
3946 void FastList_ButtonDown (HWND hList, BOOL fRightButton, BOOL fActivate)
3948 if (GetParent (hList))
3949 PostMessage (GetParent(hList), WM_NEXTDLGCTL, (WPARAM)hList, TRUE);
3954 if ((pfl = GetFastList (hList)) != NULL)
3957 // The rules for selection are somewhat complex; they follow the
3958 // conventions used by the Windows shell:
3960 // * if the user button-downs on the open/close box of a treeview item,
3961 // expand or collapse that item, and perform no further processing.
3963 // * if the user button-downs on an item,
3964 // and if that item is not selected, then:
3965 // - if the Control is not down, deselect all items
3966 // - if the Shift key is down, select all items between the Anchor
3967 // and the clicked-on item
3968 // - if the Shift key is not down, select (and anchor on) the item
3970 // * if the user button-downs and subsequently moves the mouse enough to
3971 // indicate a drag operation prior to the next button-up,
3972 // notify the parent window.
3974 // * if the user double-clicked, treat it as a button-down followed
3975 // immediately thereafter by a button-up
3977 // * if the user button-ups without having triggered a drag operation,
3978 // - if the user had button-downed on an already-selected item,
3979 // de-select that item
3981 // * if the user button-ups after having triggered a drag operation,
3982 // notify the parent window.
3984 // Here, the user has just button-downed, either as part of a single-click
3985 // or a double-click. We therefore will attempt the initial selection
3986 // process, store the screen coordinates at which the user clicked, and
3987 // set capture onto this list window that we may look for drag operations.
3989 // First find out where the user button-downed.
3991 DWORD dwPos = GetMessagePos();
3994 ptScreen.x = LOWORD(dwPos);
3995 ptScreen.y = HIWORD(dwPos);
3997 POINT ptClient = ptScreen;
3998 ScreenToClient (hList, &ptClient);
4000 // Determine what item is underneath the given point; also determine
4001 // the region of the item which was clicked.
4003 HLISTITEM hStrict = NULL;
4004 HLISTITEM hNonStrict = NULL;
4005 FASTLISTITEMREGIONS regNonStrict;
4006 if ((hStrict = FastList_ItemFromPoint (hList, &ptClient, TRUE)) == NULL)
4008 if ((hNonStrict = FastList_ItemFromPoint (hList, &ptClient, FALSE)) != NULL)
4009 FastList_GetItemRegions (hList, hNonStrict, ®NonStrict);
4012 // If the user has clicked on the open/close button of an item, expand
4013 // or collapse that item.
4015 FastList_Begin (hList);
4017 if ( (!hStrict) && (hNonStrict) && (PtInRect (®NonStrict.rButton, ptClient)) )
4019 FastList_OnCommand_Expand (hList, hNonStrict, !hNonStrict->fExpanded);
4020 FastList_Notify_ItemExpand (pfl, hNonStrict);
4021 FastList_End (hList);
4025 // If the user failed to click on any item at all, and if the control
4026 // key is not down, de-select all items. Regardless, return thereafter.
4030 if (!fIsControlDown())
4031 FastList_SelectNone (hList);
4032 FastList_SetFocus (hList,NULL);
4033 FastList_End (hList);
4034 FastList_Notify_ItemSelect (pfl);
4038 // If the user has double-clicked on an item, and that item is a parent
4039 // of other item, and if the tree is showing, expand or collapse that item.
4041 if (fActivate && hStrict->hTreeChild && (pfl->dwStyle & FLS_VIEW_TREE))
4043 FastList_OnCommand_Expand (hList, hStrict, !hStrict->fExpanded);
4044 FastList_End (hList);
4048 // The user has clicked on an item. Record what we know about what
4049 // the user has done, and apply message capturing to the list.
4051 pfl->fButtonDown = TRUE;
4052 pfl->fRightDrag = fRightButton;
4053 pfl->fDragging = FALSE;
4054 pfl->fTriedToDrag = FALSE;
4055 pfl->ptScreenDown = ptScreen;
4056 pfl->hHitOnDown = hStrict;
4057 pfl->fSelectedOnDown = hStrict->fSelected;
4060 // There are eight states about which we need to concern ourselves:
4062 // Control: Down (C) or Not Down (c)
4063 // Shift: Down (S) or Not Down (s)
4064 // Item: Selected (I) or Not Selected (i)
4066 // csi: de-select all items, anchor and select the specified item
4067 // csI: de-select all items, anchor and select the specified item
4068 // cSi: de-select all items, select from the anchor to the specified item
4069 // cSI: de-select all items, select from the anchor to the specified item
4070 // Csi: anchor and select the specified item
4071 // CsI: anchor and select the specified item
4072 // CSi: select from the anchor to the specified item
4073 // CSI: select from the anchor to the specified item
4075 // From this we can deduce the following rules:
4077 // if Control is not down, begin by de-selecting all items
4078 // if Shift is not down, anchor and select the specified item
4079 // if Shift is down, select from the anchor to the specified item
4081 HLISTITEM hAnchor = pfl->hAnchor;
4082 if (!fIsControlDown())
4084 FastList_SelectNone (hList);
4086 if (!fIsShiftDown() || !hAnchor)
4088 FastList_SelectItem (hList, hStrict, TRUE);
4089 pfl->hAnchor = hStrict;
4091 if (fIsShiftDown() && hAnchor)
4093 FastList_PerformSelectRange (pfl, hAnchor, hStrict);
4094 if (hAnchor->fSelected)
4095 pfl->hAnchor = hAnchor;
4098 // Finally, place the focus on the clicked-on item, and return.
4099 // We will complete the selection/dragging operation on mouseup.
4101 FastList_SetFocus (hList, hStrict);
4102 FastList_End (hList);
4103 FastList_Notify_ItemSelect (pfl);
4108 void FastList_MouseMove (HWND hList)
4111 if ((pfl = GetFastList (hList)) != NULL)
4113 // If there is no possibility that the user may be dragging something,
4114 // ignore the message.
4116 if (!pfl->fButtonDown)
4119 // If the user has triggered a drag operation, notify the parent.
4121 if ((!pfl->fTriedToDrag) || (pfl->fDragging))
4123 DWORD dwCode = (pfl->fDragging) ? FLN_DRAG : FLN_BEGINDRAG;
4124 DWORD dwPos = GetMessagePos();
4127 ptScreenTo.x = LOWORD(dwPos);
4128 ptScreenTo.y = HIWORD(dwPos);
4130 if (!pfl->fTriedToDrag)
4132 if ( (abs(ptScreenTo.x - pfl->ptScreenDown.x) >= GetSystemMetrics(SM_CXDRAG)) ||
4133 (abs(ptScreenTo.y - pfl->ptScreenDown.y) >= GetSystemMetrics(SM_CYDRAG)) )
4135 pfl->fTriedToDrag = TRUE;
4138 if (pfl->fTriedToDrag)
4140 FLN_DRAG_PARAMS fln;
4141 fln.hFirst = pfl->hSelectFirst;
4142 fln.ptScreenFrom = pfl->ptScreenDown;
4143 fln.ptScreenTo = ptScreenTo;
4144 fln.fRightButton = pfl->fRightDrag;
4145 fln.fShift = fIsShiftDown();
4146 fln.fControl = fIsControlDown();
4147 if ( (FastList_Notify_Drag (pfl, dwCode, &fln)) && (dwCode == FLN_BEGINDRAG) )
4148 pfl->fDragging = TRUE;
4155 void FastList_ButtonUp (HWND hList, BOOL fRightButton, BOOL fActivate)
4158 if ((pfl = GetFastList (hList)) != NULL)
4160 // First, our caller may have just notified us that a double-click
4161 // took place; if so, we may have already handled it (in the ButtonDown)
4162 // routine. Or, moreover, if we never got a button-down at all,
4163 // there's nothing for us to do here.
4165 if (!pfl->fButtonDown)
4167 if (pfl->fRightDrag != fRightButton)
4170 // Release capture; we no longer need it.
4172 pfl->fButtonDown = FALSE;
4175 // If the user right-button-ups without having triggered a drag operation,
4176 // send a WM_CONTEXTMENU message.
4178 if ( (!pfl->fTriedToDrag) && (fRightButton) )
4180 if (GetParent (hList))
4182 PostMessage (GetParent (hList), WM_CONTEXTMENU, (WPARAM)hList, (LPARAM)GetMessagePos());
4186 // If the user button-ups without having triggered a drag operation,
4187 // and if the user had button-downed on an already-selected item,
4188 // de-select that item.
4190 if ( (!pfl->fTriedToDrag) && (pfl->hHitOnDown) && (pfl->fSelectedOnDown) && (fIsControlDown()) )
4192 FastList_SelectItem (hList, pfl->hHitOnDown, FALSE);
4193 FastList_Notify_ItemSelect (pfl);
4197 // If the user button-ups after triggering a drag operation, notify
4202 DWORD dwPos = GetMessagePos();
4205 ptScreenTo.x = LOWORD(dwPos);
4206 ptScreenTo.y = HIWORD(dwPos);
4208 FLN_DRAG_PARAMS fln;
4209 fln.hFirst = pfl->hSelectFirst;
4210 fln.ptScreenFrom = pfl->ptScreenDown;
4211 fln.ptScreenTo = ptScreenTo;
4212 fln.fRightButton = pfl->fRightDrag;
4213 fln.fShift = fIsShiftDown();
4214 fln.fControl = fIsControlDown();
4215 FastList_Notify_Drag (pfl, FLN_ENDDRAG, &fln);
4222 * UTILITY FUNCTIONS __________________________________________________________
4226 LPFASTLIST GetFastList (HWND hList)
4230 if (!GetWindowLong (hList, 0))
4232 if ((pfl = (LPFASTLIST)GetWindowLong (hList, 0))->dwSig != dwSigFASTLIST)
4234 else if (pfl->hList != hList)
4243 BOOL fIsFastList (HWND hList)
4245 return (GetFastList (hList)) ? TRUE : FALSE;
4249 void FastList_Enter (HWND hList)
4252 if ((pfl = GetFastList (hList)) != NULL)
4254 EnterCriticalSection (&pfl->cs);
4259 void FastList_Leave (HWND hList)
4262 if ((pfl = GetFastList (hList)) != NULL)
4264 LeaveCriticalSection (&pfl->cs);
4269 int CALLBACK FastList_SortFunc_AlphaNumeric (HWND hList, HLISTITEM hItem1, LPARAM lpItem1, HLISTITEM hItem2, LPARAM lpItem2)
4272 if ((pfl = GetFastList (hList)) == NULL)
4275 if (!hItem1 || !hItem2)
4278 LPTSTR pszText1 = FastList_GetColumnText (pfl, hItem1, pfl->iColSort, FALSE);
4279 LPTSTR pszText2 = FastList_GetColumnText (pfl, hItem2, pfl->iColSort, TRUE);
4281 if ( (pfl->iColSort < (int)pfl->cColumns) &&
4282 (pfl->aColumns[ pfl->iColSort ].pszText != NULL) &&
4283 ((pfl->aColumns[ pfl->iColSort ].fmt & HDF_JUSTIFYMASK) == HDF_RIGHT) )
4285 double dItem1 = atof (pszText1);
4286 double dItem2 = atof (pszText2);
4289 return (dItem1 < dItem2) ? 1 : (dItem1 > dItem2) ? -1 : 0;
4291 return (dItem1 < dItem2) ? -1 : (dItem1 > dItem2) ? 1 : 0;
4293 else // left- or center- justified; use an alphabetic sort
4296 return lstrcmpi (pszText2, pszText1);
4298 return lstrcmpi (pszText1, pszText2);
4303 int CALLBACK FastList_SortFunc_Alphabetic (HWND hList, HLISTITEM hItem1, LPARAM lpItem1, HLISTITEM hItem2, LPARAM lpItem2)
4306 if ((pfl = GetFastList (hList)) == NULL)
4309 if (!hItem1 || !hItem2)
4312 LPTSTR pszText1 = FastList_GetColumnText (pfl, hItem1, pfl->iColSort, FALSE);
4313 LPTSTR pszText2 = FastList_GetColumnText (pfl, hItem2, pfl->iColSort, TRUE);
4316 return lstrcmpi (pszText2, pszText1);
4318 return lstrcmpi (pszText1, pszText2);
4322 int CALLBACK FastList_SortFunc_Numeric (HWND hList, HLISTITEM hItem1, LPARAM lpItem1, HLISTITEM hItem2, LPARAM lpItem2)
4325 if ((pfl = GetFastList (hList)) == NULL)
4328 if (!hItem1 || !hItem2)
4331 LPTSTR pszText1 = FastList_GetColumnText (pfl, hItem1, pfl->iColSort, FALSE);
4332 LPTSTR pszText2 = FastList_GetColumnText (pfl, hItem2, pfl->iColSort, TRUE);
4334 double dItem1 = atof (pszText1);
4335 double dItem2 = atof (pszText2);
4338 return (dItem1 < dItem2) ? 1 : (dItem1 > dItem2) ? -1 : 0;
4340 return (dItem1 < dItem2) ? -1 : (dItem1 > dItem2) ? 1 : 0;
4345 * HASHLIST KEYS ______________________________________________________________
4349 BOOL CALLBACK FastList_KeyUserParam_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData)
4351 return (((HLISTITEM)pObject)->lpUser == *(LPARAM*)pData) ? TRUE : FALSE;
4354 HASHVALUE CALLBACK FastList_KeyUserParam_HashObject (LPHASHLISTKEY pKey, PVOID pObject)
4356 return FastList_KeyUserParam_HashData (pKey, &((HLISTITEM)pObject)->lpUser);
4359 HASHVALUE CALLBACK FastList_KeyUserParam_HashData (LPHASHLISTKEY pKey, PVOID pData)
4361 return (HASHVALUE)*(LPARAM*)pData;