6 #define NO_DEBUG_ALLOC // Turn off memory-allocation instrumentation for this
12 #include <WINNT/fastlist.h>
13 #include <WINNT/subclass.h>
14 #include <WINNT/hashlist.h>
15 #include <WINNT/TaLocale.h>
19 * DEFINITIONS ________________________________________________________________
23 #define clrTRANSPARENT PALETTERGB(255,0,255)
25 typedef struct _FASTLISTITEM
33 HLISTITEM hTreeParent;
35 HLISTITEM hTreePrevious;
37 HLISTITEM hListPrevious;
39 HLISTITEM hSelectPrevious;
40 HLISTITEM hSelectNext;
50 } FASTLISTITEM, *LPFASTLISTITEM, LISTITEM, *LPLISTITEM;
53 // We over-allocate the aVisibleHeap[] array whenever it fills up,
54 // in order to perform fewer allocations. The allocation size
55 // defined by the macros below causes the following progression
58 // 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 24576, 32768, ...
60 #define cREALLOC_VISIBLEHEAP_MIN 128
61 #define cREALLOC_VISIBLEHEAP_MAX 4096
62 #define cREALLOC_VISIBLEHEAP(pfl) min(max(pfl->cVisibleHeap, cREALLOC_VISIBLEHEAP_MIN),cREALLOC_VISIBLEHEAP_MAX)
64 #define dwSigFASTLIST TEXT('FAST')
66 typedef struct FASTLIST
78 BOOL fSortBeforePaint;
79 BOOL fSyncScrollBeforePaint;
80 BOOL fSyncIndicesBeforePaint;
81 BOOL fRepaintRequired;
82 BOOL fSyncHeaderRequired;
86 LPFASTLISTTEXTCALLBACK pfnText;
88 LPFASTLISTSORTFUNC pfnSort;
91 HLISTITEM hEnsureVisible;
94 LPHASHLISTKEY lkUserParam;
97 HLISTITEM hSelectFirst;
106 HLISTITEM hHitOnDown;
107 BOOL fSelectedOnDown;
112 HLISTITEM *aVisibleHeap;
115 } FASTLIST, *LPFASTLIST;
119 * GLOBAL TO FASTLIST _________________________________________________________
123 static struct FASTLIST_GLOBAL
134 #define cREALLOC_OBJECTHEAP 512
138 * DISPLAY CONSTANTS __________________________________________________________
143 #define cxRECT(_r) ((_r).right - (_r).left)
147 #define cyRECT(_r) ((_r).bottom - (_r).top)
151 #define limit(_a,_x,_b) min(max((_x),(_a)),(_b))
155 #define DivRoundUp(_a,_b) (((_a) + (_b) -1) / (_b))
158 #define cyABOVE_LARGE_ICON 2
159 #define cyBELOW_LARGE_ICON 1
160 #define cyABOVE_LARGE_TEXT 1
161 #define cyBELOW_LARGE_TEXT 1
162 #define cxBEFORE_LARGE_TEXT 1
163 #define cxAFTER_LARGE_TEXT 2
165 #define cyABOVE_SMALL_TEXT 1
166 #define cyBELOW_SMALL_TEXT 1
167 #define cxBEFORE_SMALL_ICON 2
168 #define cxAFTER_SMALL_ICON 2
169 #define cxBEFORE_SMALL_TEXT 1
170 #define cxAFTER_SMALL_TEXT 2
172 #define cxBEFORE_LIST_ICON 2
173 #define cxAFTER_LIST_ICON 2
174 #define cyABOVE_LIST_TEXT 1
175 #define cyBELOW_LIST_TEXT 1
176 #define cxBETWEEN_LIST_ICONS 2
177 #define cxBEFORE_LIST_TEXT 1
178 #define cxAFTER_LIST_TEXT 4
179 #define cxBEFORE_COLUMN_TEXT 5
181 #define cxSPACE_TREELINE 2
182 #define cySPACE_TREELINE 2
186 #define TREELINE_HORIZONTAL 0x00000001
187 #define TREELINE_BOX 0x00000002
188 #define TREELINE_BOXOPEN (TREELINE_BOX)
189 #define TREELINE_BOXCLOSED (0x00000004 | TREELINE_BOX)
190 #define TREELINE_UP 0x00000008
191 #define TREELINE_DOWN 0x00000010
195 * VARIABLES __________________________________________________________________
201 * PROTOTYPES _________________________________________________________________
205 #define fIsShiftDown() (GetKeyState(VK_SHIFT) < 0)
206 #define fIsControlDown() (GetKeyState(VK_CONTROL) < 0)
208 BOOL OpenGlobalBitmap (HDC hdc, RECT *prClient);
209 void CloseGlobalBitmap (void);
211 BOOL OpenGlobalArray (size_t cObjects);
212 void CloseGlobalArray (void);
214 BOOL CALLBACK FastList_ControlProc (HWND hList, UINT msg, WPARAM wp, LPARAM lp);
215 BOOL CALLBACK FastList_ParentProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp);
217 void FastList_OnCreate (HWND hList);
218 void FastList_OnDestroy (HWND hList);
219 void FastList_OnStyleChange (HWND hList);
220 void FastList_OnSize (HWND hList);
221 void FastList_OnPaint (HWND hList);
222 void FastList_OnPaintItem (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi);
223 void FastList_OnPaintItem_DrawImage (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, int iImage, LONG xImage, LONG yImage, BOOL fHLines);
224 void FastList_OnPaintItem_GetItemColors (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, COLORREF *pclrFore, COLORREF *pclrBack);
225 void FastList_OnPaintItem_TreeLines (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, DWORD dwLines, RECT *prLines);
226 void FastList_OnPaintItem_Large (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi);
227 void FastList_OnPaintItem_Small (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi);
228 void FastList_OnPaintItem_Tree (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, HLISTITEM hItem, RECT *prThisColumn);
229 void FastList_OnPaintItem_List (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi);
230 void FastList_OnScroll (HWND hList, UINT msg, WPARAM wp, LPARAM lp);
231 void FastList_OnRightButtonDown (HWND hList);
232 void FastList_OnLeftButtonDown (HWND hList);
233 void FastList_OnLeftButtonDouble (HWND hList);
234 void FastList_OnKeyPress (HWND hList, TCHAR ch);
235 BOOL FastList_OnKeyPress_EnsureSelection (LPFASTLIST pfl);
236 void FastList_OnKeyPress_ChangeSelection (LPFASTLIST pfl, HLISTITEM hSelect);
238 void FastList_OnCommand_Begin (HWND hList);
239 void FastList_OnCommand_End (HWND hList, BOOL fForce);
240 HLISTITEM FastList_OnCommand_AddItem (HWND hList, LPFASTLISTADDITEM pai);
241 void FastList_OnCommand_RemoveItem (HWND hList, HLISTITEM hItem);
242 LPCTSTR FastList_OnCommand_GetItemText (HWND hList, HLISTITEM hItem, int iColumn);
243 void FastList_OnCommand_SetItemText (HWND hList, LPFASTLISTITEMCOLUMN pflic, LPCTSTR pszText);
244 LPARAM FastList_OnCommand_GetItemParam (HWND hList, HLISTITEM hItem);
245 void FastList_OnCommand_SetItemParam (HWND hList, HLISTITEM hItem, LPARAM lpUser);
246 DWORD FastList_OnCommand_GetItemFlags (HWND hList, HLISTITEM hItem);
247 void FastList_OnCommand_SetItemFlags (HWND hList, HLISTITEM hItem, DWORD dwFlags);
248 int FastList_OnCommand_GetItemImage (HWND hList, HLISTITEM hItem, int iImage);
249 void FastList_OnCommand_SetItemImage (HWND hList, LPFASTLISTITEMIMAGE pflii, int iImage);
250 void FastList_OnCommand_GetImageLists (HWND hList, HIMAGELIST *phiSmall, HIMAGELIST *phiLarge);
251 void FastList_OnCommand_SetImageLists (HWND hList, HIMAGELIST hiSmall, HIMAGELIST hiLarge);
252 HIMAGELIST FastList_OnCommand_CreateDragImage (HWND hList, HLISTITEM hItem);
253 LPFASTLISTSORTFUNC FastList_OnCommand_GetSortFunc (HWND hList);
254 void FastList_OnCommand_SetSortFunc (HWND hList, LPFASTLISTSORTFUNC pfn);
255 void FastList_OnCommand_GetSortStyle (HWND hList, int *piColSort, BOOL *pfRevSort);
256 void FastList_OnCommand_SetSortStyle (HWND hList, int iColSort, BOOL fRevSort);
257 void FastList_OnCommand_Sort (HWND hList);
258 int FastList_OnCommand_GetColumnCount (HWND hList);
259 BOOL FastList_OnCommand_GetColumn (HWND hList, int iColumn, LPFASTLISTCOLUMN pcol);
260 void FastList_OnCommand_SetColumn (HWND hList, int iColumn, LPFASTLISTCOLUMN pcol);
261 BOOL FastList_OnCommand_IsSelected (HWND hList, HLISTITEM hItem);
262 void FastList_OnCommand_SelectItem (HWND hList, HLISTITEM hItem, BOOL fSelect);
263 HLISTITEM FastList_OnCommand_FindList (HWND hList, HLISTITEM hItem, DWORD dwCode);
264 HLISTITEM FastList_OnCommand_FindTree (HWND hList, HLISTITEM hItem, DWORD dwCode);
265 HLISTITEM FastList_OnCommand_FindSelected (HWND hList, HLISTITEM hItem);
266 HLISTITEM FastList_OnCommand_FindItem (HWND hList, LPENUM *ppEnum, LPARAM lpUser);
267 HLISTITEM FastList_OnCommand_FindNextItem (HWND hList, LPENUM *ppEnum);
268 HLISTITEM FastList_OnCommand_FindVisible (HWND hList, HLISTITEM hItem, DWORD dwCode);
269 void FastList_OnCommand_FindClose (HWND hList, LPENUM *ppEnum);
270 int FastList_OnCommand_GetItemCount (HWND hList, BOOL fVisibleOnly);
271 BOOL FastList_OnCommand_IsExpanded (HWND hList, HLISTITEM hItem);
272 void FastList_OnCommand_Expand (HWND hList, HLISTITEM hItem, BOOL fExpand);
273 BOOL FastList_OnCommand_ItemVisible (HWND hList, HLISTITEM hItem, BOOL fSet);
274 HLISTITEM FastList_OnCommand_ItemFocus (HWND hList, HLISTITEM hItem, BOOL fSet);
275 HLISTITEM FastList_OnCommand_ItemFromPoint (HWND hList, POINT *pptClient, BOOL fStrict);
276 void FastList_OnCommand_GetItemRegions (HWND hList, HLISTITEM hItem, LPFASTLISTITEMREGIONS pReg, POINT *pptTest = NULL, BOOL *pfHit = NULL);
277 LPFASTLISTTEXTCALLBACK FastList_OnCommand_GetTextCallback (HWND hList);
278 void FastList_OnCommand_SetTextCallback (HWND hList, LPFASTLISTTEXTCALLBACK pfn, DWORD dwCookie);
280 BOOL FastList_Notify_GetItemText (LPFASTLIST pfl, HLISTITEM hItem, int icol, LPTSTR pszText, size_t cchText, size_t *pcchRequired);
281 BOOL FastList_Notify_ItemChanged (LPFASTLIST pfl, HLISTITEM hItem);
282 BOOL FastList_Notify_AddItem (LPFASTLIST pfl, HLISTITEM hItem);
283 BOOL FastList_Notify_RemoveItem (LPFASTLIST pfl, HLISTITEM hItem);
284 BOOL FastList_Notify_ColumnClick (LPFASTLIST pfl, int icol, BOOL fDouble);
285 BOOL FastList_Notify_ColumnResize (LPFASTLIST pfl, int icol, LONG cxWidth);
286 BOOL FastList_Notify_ItemSelect (LPFASTLIST pfl);
287 BOOL FastList_Notify_ItemExpand (LPFASTLIST pfl, HLISTITEM hItem);
288 BOOL FastList_Notify_Generic (LPFASTLIST pfl, DWORD dwCode);
289 BOOL FastList_Notify_Drag (LPFASTLIST pfl, DWORD dwCode, LPFLN_DRAG_PARAMS pfln);
291 void FastList_Repaint (LPFASTLIST pfl);
292 HLISTITEM FastList_CreateItem (LPFASTLIST pfl);
293 void FastList_DeleteItem (LPFASTLIST pfl, HLISTITEM hItem);
294 int FastList_GetListHeight (LPFASTLIST pfl);
295 int FastList_GetListWidth (LPFASTLIST pfl);
296 void FastList_CalcItemRect (LPFASTLIST pfl, int index, RECT *prItem, BOOL fScrollH, BOOL fScrollV);
297 void FastList_CalcFieldSize (LPFASTLIST pfl, LONG *pcxField, LONG *pcyField, BOOL fScrollH, BOOL fScrollV);
298 void FastList_GetHeaderRect (LPFASTLIST pfl, RECT *prHeader);
299 LONG FastList_GetHeaderHeight (LPFASTLIST pfl);
300 void FastList_UpdateColumn (LPFASTLIST pfl, int iColumn);
301 void FastList_SyncHeader (LPFASTLIST pfl);
302 void FastList_SyncScroll (LPFASTLIST pfl);
303 void FastList_SyncScrollPos (LPFASTLIST pfl);
304 void FastList_CallPaintItem (LPFASTLIST pfl, HDC hdc, BOOL fDraw, BOOL fDragImage, int iItem, RECT *prItem, LPFASTLISTITEMREGIONS pReg, POINT *pptTest, BOOL *pfHit);
305 LPTSTR FastList_GetColumnText (LPFASTLIST pfl, HLISTITEM hItem, int icol, BOOL fAlternateBuffer = FALSE);
306 void FastList_PerformSort (LPFASTLIST pfl);
307 void FastList_PerformSortLevel (LPFASTLIST pfl, HLISTITEM hParent, BOOL fTreeSort);
308 int __cdecl FastList_SortFunction (const void *lp1, const void *lp2);
309 void FastList_RepairOneVisibilityFlag (LPFASTLIST pfl, HLISTITEM hItem);
310 void FastList_RepairVisibilityFlags (LPFASTLIST pfl, HLISTITEM hParent = NULL, BOOL fForceHidden = FALSE);
311 void FastList_RepairVisibilityIndices (LPFASTLIST pfl, HLISTITEM hParent = NULL);
312 void FastList_ScrollHeader (LPFASTLIST pfl);
313 void FastList_PerformSelectTest (LPFASTLIST pfl, HLISTITEM hItem);
314 void FastList_PerformSelectItem (LPFASTLIST pfl, HLISTITEM hItem, BOOL fSelect);
315 void FastList_PerformSelectRange (LPFASTLIST pfl, HLISTITEM hItem1, HLISTITEM hItem2);
316 void FastList_PerformEnsureVisible (LPFASTLIST pfl);
317 void FastList_ButtonDown (HWND hList, BOOL fRightButton, BOOL fActivate);
318 void FastList_MouseMove (HWND hList);
319 void FastList_ButtonUp (HWND hList, BOOL fRightButton, BOOL fActivate);
321 LPFASTLIST GetFastList (HWND hList);
323 BOOL CALLBACK FastList_KeyUserParam_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData);
324 HASHVALUE CALLBACK FastList_KeyUserParam_HashObject (LPHASHLISTKEY pKey, PVOID pObject);
325 HASHVALUE CALLBACK FastList_KeyUserParam_HashData (LPHASHLISTKEY pKey, PVOID pData);
329 * REALLOC ____________________________________________________________________
336 #define REALLOC(_a,_c,_r,_i) FastList_ReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
337 BOOL FastList_ReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
342 if (cReq <= *pcTarget)
345 if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
348 if ((pNew = (LPVOID)Allocate (cbElement * cNew)) == NULL)
350 memset (pNew, 0x00, cbElement * cNew);
354 memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
365 * WINDOW CLASS SUPPORT _______________________________________________________
369 BOOL RegisterFastListClass (void)
371 static BOOL fRegistered = FALSE;
375 memset (&fg, 0x00, sizeof(fg));
376 InitializeCriticalSection (&fg.cs);
379 GetClassInfo (THIS_HINST, TEXT("LISTBOX"), &wc);
380 wc.style = CS_GLOBALCLASS | CS_DBLCLKS;
382 wc.lpfnWndProc = (WNDPROC)FastList_ControlProc;
383 wc.hInstance = THIS_HINST;
384 wc.hCursor = LoadCursor (NULL, MAKEINTRESOURCE (IDC_ARROW));
385 wc.hbrBackground = NULL;
386 wc.lpszClassName = WC_FASTLIST;
388 if (RegisterClass (&wc))
396 BOOL OpenGlobalBitmap (HDC hdc, RECT *prClient)
398 EnterCriticalSection (&fg.cs);
400 if ((!fg.bmp) || (fg.cxBmp < prClient->right) || (fg.cyBmp < prClient->bottom))
403 DeleteObject (fg.bmp);
405 fg.cxBmp = 128 * DivRoundUp (prClient->right, 128);
406 fg.cyBmp = 64 * DivRoundUp (prClient->bottom, 64);
407 fg.bmp = CreateCompatibleBitmap (hdc, fg.cxBmp, fg.cyBmp);
412 LeaveCriticalSection (&fg.cs);
420 void CloseGlobalBitmap (void)
422 LeaveCriticalSection (&fg.cs);
426 BOOL OpenGlobalArray (size_t cObjects)
428 EnterCriticalSection (&fg.cs);
429 REALLOC (fg.aObjects, fg.cObjects, cObjects, cREALLOC_OBJECTHEAP);
430 memset (fg.aObjects, 0x00, sizeof(HLISTITEM) * fg.cObjects);
435 void CloseGlobalArray (void)
437 LeaveCriticalSection (&fg.cs);
441 BOOL CALLBACK FastList_ControlProc (HWND hList, UINT msg, WPARAM wp, LPARAM lp)
446 FastList_OnCreate (hList);
447 if (GetParent (hList))
448 Subclass_AddHook (GetParent (hList), FastList_ParentProc);
452 if (GetParent (hList))
453 Subclass_RemoveHook (GetParent (hList), FastList_ParentProc);
454 FastList_OnDestroy (hList);
458 return DLGC_WANTARROWS;
460 case WM_STYLECHANGED:
461 FastList_OnStyleChange (hList);
465 FastList_Repaint (GetFastList (hList));
469 FastList_OnSize (hList);
473 FastList_OnPaint (hList);
477 FastList_OnLeftButtonDown (hList);
481 FastList_OnRightButtonDown (hList);
485 FastList_ButtonUp (hList, FALSE, FALSE);
489 FastList_ButtonUp (hList, TRUE, FALSE);
493 FastList_MouseMove (hList);
496 case WM_LBUTTONDBLCLK:
497 FastList_OnLeftButtonDouble (hList);
501 FastList_OnKeyPress (hList, (TCHAR)wp);
505 switch (((NMHDR*)lp)->code)
508 FastList_Notify_ColumnClick (GetFastList (hList), ((HD_NOTIFY*)lp)->iItem, FALSE);
511 case HDN_ITEMDBLCLICK:
512 FastList_Notify_ColumnClick (GetFastList (hList), ((HD_NOTIFY*)lp)->iItem, TRUE);
515 case HDN_ITEMCHANGED:
518 FastList_UpdateColumn (GetFastList (hList), ((HD_NOTIFY*)lp)->iItem);
525 FastList_OnScroll (hList, msg, wp, lp);
529 FastList_OnCommand_Begin (hList);
533 FastList_OnCommand_End (hList, (BOOL)wp);
537 return (BOOL)FastList_OnCommand_AddItem (hList, (LPFASTLISTADDITEM)lp);
540 FastList_OnCommand_RemoveItem (hList, (HLISTITEM)wp);
543 case FLM_GETITEMTEXT:
544 return (BOOL)FastList_OnCommand_GetItemText (hList, (HLISTITEM)wp, (int)lp);
546 case FLM_SETITEMTEXT:
547 FastList_OnCommand_SetItemText (hList, (LPFASTLISTITEMCOLUMN)wp, (LPCTSTR)lp);
550 case FLM_GETITEMPARAM:
551 return (BOOL)FastList_OnCommand_GetItemParam (hList, (HLISTITEM)wp);
553 case FLM_SETITEMPARAM:
554 FastList_OnCommand_SetItemParam (hList, (HLISTITEM)wp, lp);
557 case FLM_GETITEMFLAGS:
558 return (BOOL)FastList_OnCommand_GetItemFlags (hList, (HLISTITEM)wp);
560 case FLM_SETITEMFLAGS:
561 FastList_OnCommand_SetItemFlags (hList, (HLISTITEM)wp, (DWORD)lp);
564 case FLM_GETITEMIMAGE:
565 return (BOOL)FastList_OnCommand_GetItemImage (hList, (HLISTITEM)wp, (int)lp);
567 case FLM_SETITEMIMAGE:
568 FastList_OnCommand_SetItemImage (hList, (LPFASTLISTITEMIMAGE)wp, (int)lp);
572 return (BOOL)FastList_OnCommand_IsExpanded (hList, (HLISTITEM)wp);
575 FastList_OnCommand_Expand (hList, (HLISTITEM)wp, (BOOL)lp);
578 case FLM_ITEMVISIBLE:
579 return (BOOL)FastList_OnCommand_ItemVisible (hList, (HLISTITEM)wp, (BOOL)lp);
582 return (BOOL)FastList_OnCommand_ItemFocus (hList, (HLISTITEM)wp, (BOOL)lp);
584 case FLM_GETIMAGELISTS:
585 FastList_OnCommand_GetImageLists (hList, (HIMAGELIST*)wp, (HIMAGELIST*)lp);
588 case FLM_SETIMAGELISTS:
589 FastList_OnCommand_SetImageLists (hList, (HIMAGELIST)wp, (HIMAGELIST)lp);
592 case FLM_CREATEDRAGIMAGE:
593 return (BOOL)FastList_OnCommand_CreateDragImage (hList, (HLISTITEM)wp);
595 case FLM_GETSORTFUNC:
596 return (BOOL)FastList_OnCommand_GetSortFunc (hList);
598 case FLM_SETSORTFUNC:
599 FastList_OnCommand_SetSortFunc (hList, (LPFASTLISTSORTFUNC)lp);
602 case FLM_GETSORTSTYLE:
603 FastList_OnCommand_GetSortStyle (hList, (int*)wp, (BOOL*)lp);
606 case FLM_SETSORTSTYLE:
607 FastList_OnCommand_SetSortStyle (hList, (int)wp, (BOOL)lp);
611 FastList_OnCommand_Sort (hList);
614 case FLM_GETCOLUMNCOUNT:
615 return (BOOL)FastList_OnCommand_GetColumnCount (hList);
618 return FastList_OnCommand_GetColumn (hList, (int)wp, (LPFASTLISTCOLUMN)lp);
621 FastList_OnCommand_SetColumn (hList, (int)wp, (LPFASTLISTCOLUMN)lp);
625 return (BOOL)FastList_OnCommand_IsSelected (hList, (HLISTITEM)wp);
628 FastList_OnCommand_SelectItem (hList, (HLISTITEM)wp, (BOOL)lp);
632 return (BOOL)FastList_OnCommand_FindList (hList, (HLISTITEM)wp, (DWORD)lp);
635 return (BOOL)FastList_OnCommand_FindTree (hList, (HLISTITEM)wp, (DWORD)lp);
637 case FLM_FINDSELECTED:
638 return (BOOL)FastList_OnCommand_FindSelected (hList, (HLISTITEM)wp);
641 return (BOOL)FastList_OnCommand_FindItem (hList, (LPENUM*)wp, lp);
643 case FLM_FINDNEXTITEM:
644 return (BOOL)FastList_OnCommand_FindNextItem (hList, (LPENUM*)wp);
647 FastList_OnCommand_FindClose (hList, (LPENUM*)wp);
650 case FLM_FINDVISIBLE:
651 return (BOOL)FastList_OnCommand_FindVisible (hList, (HLISTITEM)wp, (DWORD)lp);
653 case FLM_GETITEMCOUNT:
654 return (BOOL)FastList_OnCommand_GetItemCount (hList, (BOOL)wp);
656 case FLM_ITEMFROMPOINT:
657 return (BOOL)FastList_OnCommand_ItemFromPoint (hList, (POINT*)wp, (BOOL)lp);
659 case FLM_GETITEMREGIONS:
660 FastList_OnCommand_GetItemRegions (hList, (HLISTITEM)wp, (LPFASTLISTITEMREGIONS)lp);
663 case FLM_GETTEXTCALLBACK:
664 return (BOOL)FastList_OnCommand_GetTextCallback (hList);
666 case FLM_SETTEXTCALLBACK:
667 FastList_OnCommand_SetTextCallback (hList, (LPFASTLISTTEXTCALLBACK)wp, (DWORD)lp);
671 return DefWindowProc (hList, msg, wp, lp);
675 BOOL CALLBACK FastList_ParentProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
677 PVOID oldProc = Subclass_FindNextHook (hDlg, FastList_ParentProc);
683 if ((pfl = GetFastList (GetDlgItem (hDlg, wp))) != NULL)
685 FastList_OnPaintItem (pfl, (LPFASTLISTDRAWITEM)lp);
691 if ((pfl = GetFastList (GetDlgItem (hDlg, wp))) != NULL)
693 switch (((NMHDR*)lp)->code)
695 case FLN_COLUMNCLICK:
696 if (pfl->dwStyle & FLS_AUTOSORTHEADER)
698 LPFLN_COLUMNCLICK_PARAMS pp = (LPFLN_COLUMNCLICK_PARAMS)lp;
700 if (pfl->iColSort == pp->icol)
701 FastList_SetSortStyle (pfl->hList, pp->icol, !pfl->fRevSort);
703 FastList_SetSortStyle (pfl->hList, pp->icol, FALSE);
711 return CallWindowProc ((WNDPROC)oldProc, hDlg, msg, wp, lp);
716 * MESSAGE HANDLING ___________________________________________________________
720 void FastList_OnCreate (HWND hList)
722 LPFASTLIST pfl = New (FASTLIST);
723 memset (pfl, 0x00, sizeof(FASTLIST));
724 SetWindowLong (hList, 0, (LONG)pfl);
727 pfl->dwCookieText = 0;
729 InitializeCriticalSection (&pfl->cs);
730 pfl->dwSig = dwSigFASTLIST;
732 pfl->dwStyle = GetWindowLong (hList, GWL_STYLE);
733 pfl->hf = (HFONT)GetStockObject (DEFAULT_GUI_FONT);
735 pfl->lItems = New (HASHLIST);
736 pfl->lItems->SetCriticalSection (&pfl->cs);
737 pfl->lkUserParam = pfl->lItems->CreateKey ("User Param", FastList_KeyUserParam_Compare, FastList_KeyUserParam_HashObject, FastList_KeyUserParam_HashData);
739 FastList_Begin (pfl->hList);
741 if (!(pfl->dwStyle & WS_CLIPCHILDREN))
742 SetWindowLong (pfl->hList, GWL_STYLE, pfl->dwStyle | WS_CLIPCHILDREN);
744 FastList_SyncHeader (pfl);
745 FastList_Repaint (pfl);
746 FastList_End (pfl->hList);
750 void FastList_OnDestroy (HWND hList)
753 if ((pfl = GetFastList (hList)) != NULL)
756 DestroyWindow (pfl->hHeader);
758 DestroyWindow (pfl->hScrollH);
760 DestroyWindow (pfl->hScrollV);
761 if (pfl->aVisibleHeap)
762 Free (pfl->aVisibleHeap);
765 for (size_t iColumn = 0; iColumn < pfl->cColumns; ++iColumn)
766 if (pfl->aColumns[ iColumn ].pszText)
767 Free (pfl->aColumns[ iColumn ].pszText);
768 Free (pfl->aColumns);
770 DeleteObject (pfl->hf);
771 Delete (pfl->lItems);
772 DeleteCriticalSection (&pfl->cs);
773 SetWindowLong (hList, 0, 0);
779 void FastList_OnStyleChange (HWND hList)
782 if ((pfl = GetFastList (hList)) != NULL)
784 BOOL fWasTree = ((pfl->dwStyle & FLS_VIEW_TREE) == FLS_VIEW_TREE) ? TRUE : FALSE;
786 pfl->dwStyle = GetWindowLong (hList, GWL_STYLE);
788 BOOL fIsTree = ((pfl->dwStyle & FLS_VIEW_TREE) == FLS_VIEW_TREE) ? TRUE : FALSE;
789 if (fWasTree != fIsTree)
791 FastList_RepairVisibilityFlags (pfl);
792 pfl->fSortBeforePaint = TRUE;
795 FastList_SyncHeader (pfl);
796 FastList_Repaint (pfl);
801 void FastList_OnSize (HWND hList)
804 if ((pfl = GetFastList (hList)) != NULL)
806 FastList_SyncHeader (pfl);
807 FastList_Repaint (pfl);
812 void FastList_OnPaint (HWND hList)
815 if ((pfl = GetFastList (hList)) != NULL)
819 pfl->fRepaintRequired = TRUE;
821 else // (!pfl->nBegin)
823 if (pfl->fSortBeforePaint)
824 FastList_PerformSort (pfl);
825 if (pfl->fSyncIndicesBeforePaint)
826 FastList_RepairVisibilityIndices (pfl);
827 if (pfl->fSyncScrollBeforePaint)
828 FastList_SyncScroll (pfl);
829 if (pfl->hEnsureVisible)
830 FastList_PerformEnsureVisible (pfl);
834 HDC hdc = BeginPaint (hList, &ps);
836 // If we're showing both scrollbars, grey-wash the rectangle
837 // in the bottom-right where they meet.
839 if ((pfl->hScrollH) && (pfl->hScrollV))
842 GetClientRect (pfl->hList, &rBox);
843 rBox.left = rBox.right - GetSystemMetrics(SM_CXVSCROLL);
844 rBox.top = rBox.bottom - GetSystemMetrics(SM_CYHSCROLL);
846 HBRUSH hbr = CreateSolidBrush (GetSysColor (COLOR_BTNFACE));
847 FillRect (hdc, &rBox, hbr);
851 // Just what client area is left, after we skip the scrollbar and
855 GetClientRect (pfl->hList, &rClient);
857 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
859 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
861 rClient.top += FastList_GetHeaderHeight (pfl);
863 // If possible, we want to draw onto an off-screen bitmap then blit
864 // the relevant sections onto the client area; this eliminates flicker
865 // as items are erased and redrawn.
868 HBITMAP bmpTargetOld = NULL;
871 if ((fDoubleBuffer = OpenGlobalBitmap (hdc, &rClient)) == TRUE)
873 hdcTarget = CreateCompatibleDC (hdc);
874 bmpTargetOld = (HBITMAP)SelectObject (hdcTarget, fg.bmp);
877 HFONT hfOld = (HFONT)SelectObject (hdcTarget, pfl->hf);
879 // Determine which objects we can display on the screen, and paint
880 // each in turn. If there is no object at a particular location,
881 // just white- or grey-fill the background.
884 FastList_CalcItemRect (pfl, 0, &rTemplate, !!pfl->hScrollH, !!pfl->hScrollV);
886 HBRUSH hbrBackground = CreateSolidBrush (GetSysColor( (IsWindowEnabled(pfl->hList)) ? COLOR_WINDOW : COLOR_BTNFACE ));
887 FillRect (hdcTarget, &rClient, hbrBackground);
891 switch (pfl->dwStyle & FLS_VIEW_MASK)
895 // In Large mode, icons are stacked left-to-right, top-to-bottom.
896 // Find the top index, and for each vertical index thereafter,
897 // find and paint the relevant horizontal indices.
899 LONG cxItems = cxRECT(rClient) / cxRECT(rTemplate);
901 LONG iyTopItem = pfl->dyPixel / cyRECT(rTemplate);
902 LONG iyBottomItem = iyTopItem + DivRoundUp (cyRECT(rClient), cyRECT(rTemplate));
904 for (LONG iyItem = iyTopItem; iyItem <= iyBottomItem; ++iyItem)
906 for (LONG ixItem = 0; ixItem < cxItems; ++ixItem)
908 int iItem = (int)( ixItem + cxItems * iyItem );
909 if (iItem < (int)pfl->cVisible)
912 rItem.top = rClient.top + iyItem * cyRECT(rTemplate) - pfl->dyPixel;
913 rItem.bottom = rItem.top + cyRECT(rTemplate);
914 rItem.left = rClient.left + ixItem * cxRECT(rTemplate) - pfl->dxPixel;
915 rItem.right = rItem.left + cxRECT(rTemplate);
917 FastList_CallPaintItem (pfl, hdcTarget, TRUE, FALSE, iItem, &rItem, NULL, NULL, NULL);
926 // In Small mode, icons are stacked top-to-bottom, left-to-right.
927 // Find the left index, and for each horizontal index thereafter,
928 // find and paint the relevant vertical indices.
930 LONG cyItems = cyRECT(rClient) / cyRECT(rTemplate);
932 LONG ixLeftItem = pfl->dxPixel / cxRECT(rTemplate);
933 LONG ixRightItem = ixLeftItem + DivRoundUp (cxRECT(rClient), cxRECT(rTemplate));
935 for (LONG ixItem = ixLeftItem; ixItem <= ixRightItem; ++ixItem)
937 for (LONG iyItem = 0; iyItem < cyItems; ++iyItem)
939 int iItem = (int)( iyItem + cyItems * ixItem );
940 if (iItem < (int)pfl->cVisible)
943 rItem.top = rClient.top + iyItem * cyRECT(rTemplate) - pfl->dyPixel;
944 rItem.bottom = rItem.top + cyRECT(rTemplate);
945 rItem.left = rClient.left + ixItem * cxRECT(rTemplate) - pfl->dxPixel;
946 rItem.right = rItem.left + cxRECT(rTemplate);
948 FastList_CallPaintItem (pfl, hdcTarget, TRUE, FALSE, iItem, &rItem, NULL, NULL, NULL);
957 case FLS_VIEW_TREELIST:
959 // In these modes, icons are stacked top-to-bottom; each takes
960 // the entire width we can give it. Find the top index, and
961 // paint all indices which fit on the screen.
963 LONG iTopItem = pfl->dyPixel / cyRECT(rTemplate);
964 LONG iBottomItem = iTopItem + DivRoundUp (cyRECT(rClient), cyRECT(rTemplate));
966 for (LONG iItem = iTopItem; iItem <= iBottomItem; ++iItem)
968 if (iItem < (int)pfl->cVisible)
971 rItem.top = rClient.top + iItem * cyRECT(rTemplate) - pfl->dyPixel;
972 rItem.bottom = rItem.top + cyRECT(rTemplate);
973 rItem.left = rClient.left - pfl->dxPixel;
974 rItem.right = rItem.left + cxRECT(rTemplate);
976 FastList_CallPaintItem (pfl, hdcTarget, TRUE, FALSE, iItem, &rItem, NULL, NULL, NULL);
986 BitBlt (hdc, rClient.left, rClient.top, cxRECT(rClient), cyRECT(rClient),
987 hdcTarget, rClient.left, rClient.top, SRCCOPY);
988 SelectObject (hdcTarget, bmpTargetOld);
989 DeleteDC (hdcTarget);
993 DeleteObject (hbrBackground);
994 SelectObject (hdcTarget, hfOld);
995 EndPaint (hList, &ps);
1000 void FastList_OnPaintItem (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi)
1002 // Initialize the output FASTLISTITEMREGIONS structure.
1003 // We were given the object's overall rectangle, and will
1004 // calculate each of the other regions as we go along.
1006 memset (&pdi->reg, 0x00, sizeof(pdi->reg));
1007 pdi->reg.rItem = pdi->rItem;
1008 pdi->fTextTestHit = FALSE;
1010 // The actual paint routine we'll use depends on the current view.
1012 switch (pfl->dwStyle & FLS_VIEW_MASK)
1014 case FLS_VIEW_LARGE:
1015 FastList_OnPaintItem_Large (pfl, pdi);
1018 case FLS_VIEW_SMALL:
1019 FastList_OnPaintItem_Small (pfl, pdi);
1024 case FLS_VIEW_TREELIST:
1025 FastList_OnPaintItem_List (pfl, pdi);
1029 UnionRect (&pdi->reg.rSelect, &pdi->reg.rHighlight, &pdi->reg.rImage);
1033 void FastList_OnPaintItem_TreeLines (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, DWORD dwLines, RECT *prThisColumn)
1035 if (prThisColumn->left >= prThisColumn->right)
1039 rLines.left = prThisColumn->left;
1040 rLines.right = rLines.left +GetSystemMetrics(SM_CXSMICON) +cxAFTER_LIST_ICON;
1041 rLines.top = prThisColumn->top;
1042 rLines.bottom = prThisColumn->bottom;
1043 prThisColumn->left = rLines.right;
1045 LONG xBox = rLines.left + (GetSystemMetrics(SM_CXSMICON) - cxTREE_BOX)/2;
1046 LONG xLine = xBox + cxTREE_BOX/2;
1048 LONG yLine = rLines.top + cyRECT(rLines)/2;
1049 LONG yBox = yLine - cyTREE_BOX/2;
1051 if (dwLines & TREELINE_BOX)
1053 pdi->reg.rButton.left = xBox;
1054 pdi->reg.rButton.right = xBox +cxTREE_BOX +1;
1055 pdi->reg.rButton.top = yBox;
1056 pdi->reg.rButton.bottom = yBox +cyTREE_BOX +1;
1061 COLORREF clrBG = GetSysColor (COLOR_WINDOW);
1062 COLORREF clrFG = GetSysColor (COLOR_BTNSHADOW);
1063 if (!IsWindowEnabled (pfl->hList))
1064 clrBG = GetSysColor (COLOR_BTNFACE);
1066 if (dwLines & TREELINE_HORIZONTAL)
1068 for (LONG xx = (dwLines & TREELINE_BOX) ? (xBox +cxTREE_BOX) : (dwLines & TREELINE_UP) ? xLine : (rLines.left+1); xx <= rLines.right+1; xx += cxSPACE_TREELINE)
1069 SetPixel (pdi->hdc, xx, yLine, clrFG);
1072 if (dwLines & TREELINE_UP)
1074 for (LONG yy = (dwLines & TREELINE_BOX) ? yBox : yLine; yy >= rLines.top; yy -= cySPACE_TREELINE)
1075 SetPixel (pdi->hdc, xLine, yy, clrFG);
1078 if (dwLines & TREELINE_DOWN)
1080 for (LONG yy = (dwLines & TREELINE_BOX) ? (yBox +cyTREE_BOX) : yLine; yy <= rLines.bottom; yy += cySPACE_TREELINE)
1081 SetPixel (pdi->hdc, xLine, yy, clrFG);
1084 if (dwLines & TREELINE_BOX)
1086 HPEN hpNew = CreatePen (PS_SOLID, 1, clrFG);
1087 HPEN hpOld = (HPEN)SelectObject (pdi->hdc, hpNew);
1089 MoveToEx (pdi->hdc, xBox, yBox, NULL);
1090 LineTo (pdi->hdc, xBox +cxTREE_BOX, yBox);
1091 LineTo (pdi->hdc, xBox +cxTREE_BOX, yBox +cyTREE_BOX);
1092 LineTo (pdi->hdc, xBox, yBox +cyTREE_BOX);
1093 LineTo (pdi->hdc, xBox, yBox);
1095 SelectObject (pdi->hdc, GetStockObject (BLACK_PEN));
1097 MoveToEx (pdi->hdc, xBox +2, yLine, NULL);
1098 LineTo (pdi->hdc, xBox +cxTREE_BOX -1, yLine);
1100 if ((dwLines & TREELINE_BOXCLOSED) == TREELINE_BOXCLOSED)
1102 MoveToEx (pdi->hdc, xLine, yBox +2, NULL);
1103 LineTo (pdi->hdc, xLine, yBox +cyTREE_BOX -1);
1106 SelectObject (pdi->hdc, hpOld);
1107 DeleteObject (hpNew);
1113 BOOL FastList_OnPaintItem_DrawImage (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, HIMAGELIST hil, int iImage, LONG xImage, LONG yImage, BOOL fHLines)
1117 if (iImage == IMAGE_NOIMAGE)
1121 rImage.left = xImage;
1122 rImage.right = rImage.left + GetSystemMetrics ((hil == pfl->hilLarge) ? SM_CXICON : SM_CXSMICON);
1123 rImage.top = yImage;
1124 rImage.bottom = rImage.top + GetSystemMetrics ((hil == pfl->hilLarge) ? SM_CYICON : SM_CYSMICON);
1128 if (iImage == IMAGE_BLANKIMAGE)
1130 if (fHLines && ((pfl->dwStyle & FLS_VIEW_TREE) == FLS_VIEW_TREE))
1133 rLine.left = xImage;
1134 rLine.right = rLine.left + GetSystemMetrics(SM_CXSMICON);
1136 rLine.bottom = rLine.top + GetSystemMetrics(SM_CYSMICON);
1137 FastList_OnPaintItem_TreeLines (pfl, pdi, TREELINE_HORIZONTAL, &rLine);
1140 else // An actual image was specified to be drawn.
1142 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))
1147 if (IsRectEmpty (&pdi->reg.rImage))
1148 pdi->reg.rImage = rImage;
1150 UnionRect (&pdi->reg.rImage, &pdi->reg.rImage, &rImage);
1156 void FastList_OnPaintItem_GetItemColors (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, COLORREF *pclrFore, COLORREF *pclrBack)
1158 if (pdi->fDragImage)
1160 *pclrFore = GetSysColor (COLOR_WINDOWTEXT);
1161 *pclrBack = clrTRANSPARENT;
1163 else if (!IsWindowEnabled (pfl->hList))
1165 *pclrFore = GetSysColor (COLOR_GRAYTEXT);
1166 *pclrBack = GetSysColor (COLOR_BTNFACE);
1168 else if ( (pdi->hItem->fSelected) || (pdi->hItem->dwFlags & FLIF_DROPHIGHLIGHT) )
1170 *pclrFore = GetSysColor (COLOR_HIGHLIGHTTEXT);
1171 *pclrBack = GetSysColor (COLOR_HIGHLIGHT);
1173 else // normal colors
1175 *pclrFore = GetSysColor (COLOR_WINDOWTEXT);
1176 *pclrBack = GetSysColor (COLOR_WINDOW);
1181 void FastList_OnPaintItem_Large (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi)
1183 // If there is an image associated with this item, draw it. Remember
1184 // that if there are *two* images, draw the second one--it's the primary
1185 // image, or the user wouldn't have bothered adding it.
1187 int iImage = pdi->hItem->iFirstImage;
1188 if (pdi->hItem->iSecondImage != IMAGE_NOIMAGE)
1189 iImage = pdi->hItem->iSecondImage;
1190 if (iImage != IMAGE_NOIMAGE)
1192 LONG xImage = pdi->rItem.left + (cxRECT(pdi->rItem) - GetSystemMetrics(SM_CXICON))/2;
1193 LONG yImage = pdi->rItem.top + cyABOVE_LARGE_ICON;
1194 FastList_OnPaintItem_DrawImage (pfl, pdi, pfl->hilLarge, iImage, xImage, yImage, FALSE);
1197 // If there is any column-0 text supplied for this item, draw that below
1200 LPTSTR pszColumnText = FastList_GetColumnText (pfl, pdi->hItem, 0);
1201 if (pszColumnText && *pszColumnText)
1204 SetRectEmpty (&rTextSize);
1205 rTextSize.right = cxRECT(pdi->rItem) - cxBEFORE_LARGE_TEXT - cxAFTER_LARGE_TEXT -2;
1207 if (!DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText), &rTextSize, DT_CENTER | DT_CALCRECT | DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX, 0))
1208 rTextSize.right = rTextSize.left;
1210 RECT rText = pdi->rItem;
1211 rText.left += (cxRECT(pdi->rItem)-cxRECT(rTextSize))/2;
1212 rText.right -= (cxRECT(pdi->rItem)-cxRECT(rTextSize))/2;
1213 rText.top += cyABOVE_LARGE_ICON + GetSystemMetrics(SM_CYICON) + cyBELOW_LARGE_ICON + cyABOVE_LARGE_TEXT;
1214 rText.bottom = min( pdi->rItem.bottom - cyBELOW_LARGE_TEXT, (rText.top + cyRECT(rTextSize)) );
1216 pdi->reg.rHighlight = rText;
1217 pdi->reg.rHighlight.left -= cxBEFORE_LARGE_TEXT;
1218 pdi->reg.rHighlight.right += cxAFTER_LARGE_TEXT;
1219 pdi->reg.rHighlight.top -= cyABOVE_LARGE_TEXT;
1220 pdi->reg.rHighlight.bottom += cyBELOW_LARGE_TEXT;
1222 pdi->reg.rLabel = pdi->reg.rHighlight;
1223 if (PtInRect (&rText, pdi->ptTextTest))
1224 pdi->fTextTestHit = TRUE;
1230 FastList_OnPaintItem_GetItemColors (pfl, pdi, &clrFore, &clrBack);
1232 if (pdi->hItem->fSelected)
1234 HBRUSH hbr = CreateSolidBrush (clrBack);
1235 FillRect (pdi->hdc, &pdi->reg.rHighlight, hbr);
1239 COLORREF clrBackOld = SetBkColor (pdi->hdc, clrBack);
1240 COLORREF clrForeOld = SetTextColor (pdi->hdc, clrFore);
1242 DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText),
1243 &rText, DT_CENTER | DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX, 0);
1245 SetTextColor (pdi->hdc, clrForeOld);
1246 SetBkColor (pdi->hdc, clrBackOld);
1248 if (pdi->hItem->fFocused && IsWindowEnabled (pfl->hList))
1249 DrawFocusRect (pdi->hdc, &pdi->reg.rHighlight);
1255 void FastList_OnPaintItem_Small (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi)
1257 // If there is an image associated with this item, draw it. Remember
1258 // that if there are *two* images, draw the second one--it's the primary
1259 // image, or the user wouldn't have bothered adding it.
1261 BOOL fImage = FALSE;
1263 int iImage = pdi->hItem->iFirstImage;
1264 if (pdi->hItem->iSecondImage != IMAGE_NOIMAGE)
1265 iImage = pdi->hItem->iSecondImage;
1266 if (iImage != IMAGE_NOIMAGE)
1268 LONG xImage = pdi->rItem.left + cxBEFORE_SMALL_ICON;
1269 LONG yImage = pdi->rItem.top + (cyRECT(pdi->rItem) - GetSystemMetrics(SM_CYSMICON))/2;
1270 fImage = FastList_OnPaintItem_DrawImage (pfl, pdi, pfl->hilSmall, iImage, xImage, yImage, FALSE);
1273 // If there is any column-0 text supplied for this item, draw that to the
1274 // right of the item's icon.
1276 LPTSTR pszColumnText = FastList_GetColumnText (pfl, pdi->hItem, 0);
1277 if (pszColumnText && *pszColumnText)
1279 RECT rTextSize = pdi->rItem;
1280 if (!DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText), &rTextSize, DT_CALCRECT | DT_END_ELLIPSIS | DT_NOPREFIX, 0))
1281 rTextSize.right = rTextSize.left;
1283 RECT rText = pdi->rItem;
1284 rText.left += cxBEFORE_SMALL_TEXT + fImage * (GetSystemMetrics(SM_CXSMICON) + cxBEFORE_SMALL_ICON + cxAFTER_SMALL_ICON);
1285 rText.right = min( pdi->rItem.right - cxAFTER_SMALL_TEXT, (rText.left + cxRECT(rTextSize)) );
1286 rText.top += cyABOVE_SMALL_TEXT;
1287 rText.bottom -= cyBELOW_SMALL_TEXT;
1289 pdi->reg.rHighlight = rText;
1290 pdi->reg.rHighlight.left -= cxBEFORE_SMALL_TEXT;
1291 pdi->reg.rHighlight.right += cxAFTER_SMALL_TEXT;
1292 pdi->reg.rHighlight.top -= cyABOVE_SMALL_TEXT;
1293 pdi->reg.rHighlight.bottom += cyBELOW_SMALL_TEXT;
1295 pdi->reg.rLabel = pdi->reg.rHighlight;
1296 if (PtInRect (&rText, pdi->ptTextTest))
1297 pdi->fTextTestHit = TRUE;
1303 FastList_OnPaintItem_GetItemColors (pfl, pdi, &clrFore, &clrBack);
1305 if (pdi->hItem->fSelected)
1307 HBRUSH hbr = CreateSolidBrush (clrBack);
1308 FillRect (pdi->hdc, &pdi->reg.rHighlight, hbr);
1312 COLORREF clrBackOld = SetBkColor (pdi->hdc, clrBack);
1313 COLORREF clrForeOld = SetTextColor (pdi->hdc, clrFore);
1315 DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText),
1316 &rText, DT_END_ELLIPSIS | DT_NOPREFIX, 0);
1318 SetTextColor (pdi->hdc, clrForeOld);
1319 SetBkColor (pdi->hdc, clrBackOld);
1321 if (pdi->hItem->fFocused && IsWindowEnabled (pfl->hList))
1322 DrawFocusRect (pdi->hdc, &pdi->reg.rHighlight);
1328 void FastList_OnPaintItem_Tree (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi, HLISTITEM hItem, RECT *prThisColumn)
1330 // This routine is supposed to draw the tree structure off to the left
1331 // of an item. To do that, it calls itself recursively to draw the
1332 // icon areas of each of its parents.
1334 if (hItem->hTreeParent != NULL)
1336 FastList_OnPaintItem_Tree (pfl, pdi, hItem->hTreeParent, prThisColumn);
1339 // For any given item, the first thing to determine is how many icons
1342 int iLeftImage = hItem->iFirstImage;
1343 int iRightImage = IMAGE_NOIMAGE;
1345 if (hItem->iSecondImage != IMAGE_NOIMAGE)
1347 iLeftImage = hItem->iSecondImage;
1348 iRightImage = hItem->iFirstImage;
1351 // What lines/boxes should we draw?
1353 BOOL fHLines = FALSE;
1355 if ((hItem->hTreeParent) || (pfl->dwStyle & FLS_LINESATROOT))
1360 if (hItem == pdi->hItem)
1361 dwLines |= TREELINE_HORIZONTAL;
1362 if ((hItem == pdi->hItem) && (hItem->hTreeChild))
1363 dwLines |= (hItem->fExpanded) ? TREELINE_BOXOPEN : TREELINE_BOXCLOSED;
1364 if (hItem->hTreeNext)
1365 dwLines |= TREELINE_DOWN;
1366 if ((dwLines != 0) && !((!hItem->hTreeParent && !hItem->hTreePrevious) && (hItem == pdi->hItem)))
1367 dwLines |= TREELINE_UP;
1369 FastList_OnPaintItem_TreeLines (pfl, pdi, dwLines, prThisColumn);
1372 // The lines we (maybe) just drew took the place of an icon for this
1373 // item. Maybe draw blank space, to pad for the second icon
1375 if ( (hItem != pdi->hItem) && (iLeftImage != IMAGE_NOIMAGE) && (iRightImage != IMAGE_NOIMAGE) )
1377 FastList_OnPaintItem_TreeLines (pfl, pdi, 0, prThisColumn);
1382 void FastList_OnPaintItem_List (LPFASTLIST pfl, LPFASTLISTDRAWITEM pdi)
1384 // Painting a tree or list is done column by column. Remember
1385 // We may have a "long column"--that's a column that doesn't
1386 // necessarily respect the header column boundaries.
1388 RECT rItemRemaining = pdi->rItem;
1389 pdi->reg.rHighlight = pdi->rItem;
1392 if (pdi->fDragImage)
1396 else if ((pfl->dwStyle & FLS_VIEW_TREELIST) == FLS_VIEW_TREE)
1400 else if (pfl->dwStyle & FLS_LONGCOLUMNS)
1402 for (size_t icol = 0; icol < pfl->cColumns; ++icol)
1404 if (!pfl->aColumns[ icol ].pszText)
1407 LPTSTR pszColumnText = FastList_GetColumnText (pfl, pdi->hItem, icol);
1411 if ((pfl->aColumns[ icol ].fmt & HDF_JUSTIFYMASK) != HDF_LEFT)
1412 icolLong = -1; // this can't be the long column
1417 // Select appropriate text colors. Since FastLists always draw highlights
1418 // all the way across the item, we won't change colors from column to
1423 FastList_OnPaintItem_GetItemColors (pfl, pdi, &clrFore, &clrBack);
1425 COLORREF clrBackOld = SetBkColor (pdi->hdc, clrBack);
1426 COLORREF clrForeOld = SetTextColor (pdi->hdc, clrFore);
1428 // Now that we know where the long column is, we're ready to start
1429 // painting columns.
1431 for (int icol = 0; (icolLong == -1) || (icol <= icolLong); ++icol)
1433 if (icol && !pfl->cColumns)
1435 else if ((pfl->cColumns) && ((icol >= (int)pfl->cColumns) || (!pfl->aColumns[ icol ].pszText)))
1438 // The rules for the long column are slightly different than the
1439 // rules for all other columns.
1441 LONG cxColumn = pdi->rItem.right - rItemRemaining.left;
1442 int fmtColumn = HDF_LEFT;
1444 if ((icol != icolLong) && (pfl->cColumns) && (icol < (int)pfl->cColumns))
1446 cxColumn = pfl->aColumns[ icol ].cxy;
1447 fmtColumn = pfl->aColumns[ icol ].fmt & HDF_JUSTIFYMASK;
1450 // Remember where this column ends and the next column begins.
1452 RECT rThisColumn = rItemRemaining;
1453 rThisColumn.right = rThisColumn.left + cxColumn;
1455 // Get the text for this column, and figure out how big it will be.
1457 LPTSTR pszColumnText = FastList_GetColumnText (pfl, pdi->hItem, icol);
1459 RECT rTextSize = rThisColumn;
1460 if (!DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText), &rTextSize, DT_CALCRECT | DT_END_ELLIPSIS | DT_NOPREFIX, 0))
1461 rTextSize.right = rTextSize.left;
1463 // Draw the icons and/or lines for the column. The behavior here
1464 // depends on whether we're drawing a tree or a list, or both.
1466 BOOL fHLines = FALSE;
1467 if ((icol == 0) && ((pfl->dwStyle & FLS_VIEW_TREE) == FLS_VIEW_TREE) && (!pdi->fDragImage))
1469 FastList_OnPaintItem_Tree (pfl, pdi, pdi->hItem, &rThisColumn);
1475 int iLeftImage = pdi->hItem->iFirstImage;
1476 int iRightImage = IMAGE_NOIMAGE;
1478 if ((pdi->hItem->iSecondImage != IMAGE_NOIMAGE) &&
1479 (rThisColumn.left < rThisColumn.right) &&
1482 iLeftImage = pdi->hItem->iSecondImage;
1483 iRightImage = pdi->hItem->iFirstImage;
1486 if ((iLeftImage != IMAGE_NOIMAGE) &&
1487 (rThisColumn.left < rThisColumn.right))
1489 rThisColumn.left += cxBEFORE_LIST_ICON;
1490 pdi->reg.rImage = rThisColumn;
1492 LONG xImage = rThisColumn.left;
1493 LONG yImage = rThisColumn.top + (cyRECT(pdi->rItem) - GetSystemMetrics(SM_CYSMICON))/2;
1494 if (FastList_OnPaintItem_DrawImage (pfl, pdi, pfl->hilSmall, iLeftImage, xImage, yImage, fHLines))
1496 rThisColumn.left += GetSystemMetrics (SM_CXSMICON);
1497 if (iRightImage != IMAGE_NOIMAGE)
1499 rThisColumn.left += cxBETWEEN_LIST_ICONS;
1500 xImage = rThisColumn.left;
1501 yImage = rThisColumn.top + (cyRECT(pdi->rItem) - GetSystemMetrics(SM_CYSMICON))/2;
1502 if (FastList_OnPaintItem_DrawImage (pfl, pdi, pfl->hilSmall, iRightImage, xImage, yImage, fHLines))
1503 rThisColumn.left += GetSystemMetrics (SM_CXSMICON);
1507 pdi->reg.rImage.right = rThisColumn.left;
1508 rThisColumn.left += cxAFTER_LIST_ICON;
1512 // Determine where the text will go in this column. We have to pass
1513 // that information back (for column 0) as reg.rLabel; we also have
1514 // to test the text's position against {pdi->ptTextTest} to see if the
1515 // user just clicked on the text.
1517 RECT rText = rThisColumn;
1518 rText.left += cxBEFORE_LIST_TEXT;
1519 rText.right -= cxAFTER_LIST_TEXT;
1520 rText.top += cyABOVE_LIST_TEXT;
1521 rText.bottom -= cyBELOW_LIST_TEXT;
1524 rText.left += cxBEFORE_COLUMN_TEXT;
1526 RECT rTextJustified = rText;
1527 rTextJustified.right = min( rText.right, rText.left + cxRECT(rTextSize) );
1530 if (fmtColumn == HDF_CENTER)
1531 dxJustify = (cxRECT(rText) - cxRECT(rTextJustified))/2;
1532 else if (fmtColumn == HDF_RIGHT)
1533 dxJustify = cxRECT(rText) - cxRECT(rTextJustified);
1534 rTextJustified.left += dxJustify;
1535 rTextJustified.right += dxJustify;
1538 pdi->reg.rLabel = rTextJustified;
1540 if (PtInRect (&rTextJustified, pdi->ptTextTest))
1541 pdi->fTextTestHit = TRUE;
1543 // Having determined where the text will go, we should record
1544 // where the highlight will be drawn.
1548 pdi->reg.rHighlight.left = rThisColumn.left;
1550 if (icol == icolLong)
1552 pdi->reg.rHighlight.right = min( pdi->reg.rHighlight.right, rTextJustified.right + cxAFTER_LIST_TEXT );
1555 // Okay, it's time to actually draw the text. Didn't think we'd
1556 // ever get here, did you? :)
1560 if ((!pdi->fDragImage) && ((pdi->hItem->fSelected) || (pdi->hItem->dwFlags & FLIF_DROPHIGHLIGHT)))
1562 RECT rHighlightInColumn;
1563 IntersectRect (&rHighlightInColumn, &pdi->reg.rHighlight, &rThisColumn);
1565 HBRUSH hbr = CreateSolidBrush (clrBack);
1566 FillRect (pdi->hdc, &rHighlightInColumn, hbr);
1570 DrawTextEx (pdi->hdc, pszColumnText, lstrlen(pszColumnText),
1571 &rTextJustified, DT_END_ELLIPSIS | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER, 0);
1574 rItemRemaining.left = rThisColumn.right;
1577 // Finally, draw the focus rectangle and restore the original text colors.
1579 if (pdi->hItem->fFocused && pdi->fDraw && IsWindowEnabled (pfl->hList) && (!pdi->fDragImage))
1580 DrawFocusRect (pdi->hdc, &pdi->reg.rHighlight);
1582 SetTextColor (pdi->hdc, clrForeOld);
1583 SetBkColor (pdi->hdc, clrBackOld);
1587 void FastList_OnScroll (HWND hList, UINT msg, WPARAM wp, LPARAM lp)
1590 if ((pfl = GetFastList (hList)) != NULL)
1592 HWND hScroll = (msg == WM_VSCROLL) ? pfl->hScrollV : pfl->hScrollH;
1595 memset (&si, 0x00, sizeof(si));
1596 si.cbSize = sizeof(si);
1597 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
1598 GetScrollInfo (hScroll, SB_CTL, &si);
1600 LONG posNew = si.nPos;
1601 BOOL fRepaint = TRUE;
1610 posNew = si.nMax - si.nPage;
1622 posNew -= FastList_GetListHeight (pfl);
1626 posNew += FastList_GetListHeight (pfl);
1630 posNew = si.nTrackPos;
1635 posNew = limit( 0, posNew, (LONG)(si.nMax - si.nPage) );
1636 SetScrollPos (hScroll, SB_CTL, posNew, fRepaint);
1638 // If we just scrolled vertically, repaint. If we just scrolled
1639 // horizontally, we'll have to sync the header first.
1641 if (msg == WM_HSCROLL)
1642 pfl->dxPixel = posNew;
1644 pfl->dyPixel = posNew;
1646 FastList_Repaint (pfl);
1647 if (msg == WM_HSCROLL)
1648 FastList_ScrollHeader (pfl);
1653 void FastList_OnRightButtonDown (HWND hList)
1655 FastList_ButtonDown (hList, TRUE, FALSE);
1656 FastList_Notify_Generic (GetFastList(hList), FLN_RCLICK);
1660 void FastList_OnLeftButtonDown (HWND hList)
1662 FastList_ButtonDown (hList, FALSE, FALSE);
1663 FastList_Notify_Generic (GetFastList(hList), FLN_LCLICK);
1667 void FastList_OnLeftButtonDouble (HWND hList)
1669 FastList_ButtonDown (hList, FALSE, TRUE);
1670 FastList_ButtonUp (hList, FALSE, TRUE);
1671 FastList_Notify_Generic (GetFastList(hList), FLN_LDBLCLICK);
1675 void FastList_OnKeyPress (HWND hList, TCHAR ch)
1678 if ((pfl = GetFastList (hList)) != NULL)
1683 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1685 if ((pfl->hFocused->hTreeChild) && (pfl->hFocused->fExpanded) && (!(pfl->hFocused->dwFlags & FLIF_DISALLOW_COLLAPSE)) && (pfl->dwStyle & FLS_VIEW_TREE))
1687 FastList_Collapse (hList, pfl->hFocused);
1690 if (pfl->hFocused->index != 0)
1691 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[ pfl->hFocused->index -1 ]);
1695 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1697 if (pfl->hFocused->index != 0)
1698 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[ pfl->hFocused->index -1 ]);
1702 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1704 if ((pfl->hFocused->hTreeChild) && (!pfl->hFocused->fExpanded) && (pfl->dwStyle & FLS_VIEW_TREE))
1706 FastList_Expand (hList, pfl->hFocused);
1707 FastList_Notify_ItemExpand (pfl, pfl->hFocused);
1710 if (pfl->hFocused->index < (int)(pfl->cVisible-1))
1711 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[ pfl->hFocused->index +1 ]);
1715 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1717 if (pfl->hFocused->index < (int)(pfl->cVisible-1))
1718 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[ pfl->hFocused->index +1 ]);
1722 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1725 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[0]);
1729 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1732 FastList_OnKeyPress_ChangeSelection (pfl, pfl->aVisibleHeap[ pfl->cVisible -1 ]);
1736 if (!FastList_OnKeyPress_EnsureSelection (pfl))
1738 FastList_Begin (pfl->hList);
1739 if (pfl->hFocused->fSelected && fIsControlDown())
1740 FastList_SelectItem (pfl->hList, pfl->hFocused, FALSE);
1741 else if (!pfl->hFocused->fSelected && !fIsShiftDown())
1742 FastList_SelectItem (pfl->hList, pfl->hFocused, TRUE);
1743 else if (!pfl->hFocused->fSelected)
1744 FastList_OnKeyPress_ChangeSelection (pfl, pfl->hFocused);
1745 FastList_End (pfl->hList);
1752 BOOL FastList_OnKeyPress_EnsureSelection (LPFASTLIST pfl)
1754 if (pfl->fSortBeforePaint)
1755 FastList_PerformSort (pfl);
1756 if (pfl->fSyncIndicesBeforePaint)
1757 FastList_RepairVisibilityIndices (pfl);
1758 if (pfl->hFocused && pfl->hFocused->fVisible)
1761 // Find the item at the top of the list.
1764 GetClientRect (pfl->hList, &rClient);
1766 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
1768 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
1770 rClient.top += FastList_GetHeaderHeight (pfl);
1773 FastList_CalcItemRect (pfl, 0, &rTemplate, !!pfl->hScrollH, !!pfl->hScrollV);
1775 int indexTopLeft = -1;
1777 switch (pfl->dwStyle & FLS_VIEW_MASK)
1779 case FLS_VIEW_LARGE:
1781 LONG cxItems = cxRECT(rClient) / cxRECT(rTemplate);
1782 indexTopLeft = pfl->dyPixel / cyRECT(rTemplate);
1786 case FLS_VIEW_SMALL:
1788 LONG cyItems = cyRECT(rClient) / cyRECT(rTemplate);
1789 indexTopLeft = pfl->dxPixel / cxRECT(rTemplate);
1795 case FLS_VIEW_TREELIST:
1796 indexTopLeft = pfl->dyPixel / cyRECT(rTemplate);
1800 if ((indexTopLeft >= 0) && (indexTopLeft < (int)pfl->cVisible))
1802 FastList_SetFocus (pfl->hList, pfl->aVisibleHeap[ indexTopLeft ]);
1809 void FastList_OnKeyPress_ChangeSelection (LPFASTLIST pfl, HLISTITEM hSelect)
1811 FastList_Begin (pfl->hList);
1812 FastList_SetFocus (pfl->hList, hSelect);
1813 FastList_EnsureVisible (pfl->hList, hSelect);
1815 // If Control is not down, begin by de-selecting all items
1816 // If Shift is not down, anchor and select the specified item
1817 // If Shift is down, select from the anchor to the specified item
1819 HLISTITEM hAnchor = pfl->hAnchor;
1820 if (!fIsControlDown())
1822 FastList_SelectNone (pfl->hList);
1824 if ((!fIsShiftDown() || !hAnchor) && (!fIsControlDown()))
1826 FastList_SelectItem (pfl->hList, hSelect, TRUE);
1827 pfl->hAnchor = hSelect;
1829 if (fIsShiftDown() && hAnchor)
1831 FastList_PerformSelectRange (pfl, hAnchor, hSelect);
1832 if (hAnchor->fSelected)
1833 pfl->hAnchor = hAnchor;
1836 FastList_End (pfl->hList);
1837 FastList_Notify_ItemSelect (pfl);
1842 * EXPORTED ROUTINES __________________________________________________________
1846 void FastList_OnCommand_Begin (HWND hList)
1849 if ((pfl = GetFastList (hList)) != NULL)
1856 void FastList_OnCommand_End (HWND hList, BOOL fForce)
1859 if ((pfl = GetFastList (hList)) != NULL)
1863 else if (pfl->nBegin)
1866 if (pfl->nBegin == 0)
1868 if (pfl->fSyncHeaderRequired)
1869 FastList_SyncHeader (pfl);
1870 if (pfl->fSortBeforePaint)
1871 pfl->fRepaintRequired = TRUE;
1872 if (pfl->fSyncScrollBeforePaint)
1873 pfl->fRepaintRequired = TRUE;
1874 if (pfl->fRepaintRequired)
1875 FastList_Repaint (pfl);
1881 HLISTITEM FastList_OnCommand_AddItem (HWND hList, LPFASTLISTADDITEM pai)
1883 HLISTITEM hItem = NULL;
1886 if ((pfl = GetFastList (hList)) != NULL)
1888 hItem = FastList_CreateItem (pfl);
1890 // Add this item to the hList chain
1892 if ((hItem->hListNext = pfl->hListFirst) != NULL)
1893 hItem->hListNext->hListPrevious = hItem;
1894 pfl->hListFirst = hItem;
1896 // Add this item to the hTree chain
1898 if ((hItem->hTreeParent = pai->hParent) != NULL)
1900 if ((hItem->hTreeNext = hItem->hTreeParent->hTreeChild) != NULL)
1901 hItem->hTreeNext->hTreePrevious = hItem;
1902 hItem->hTreeParent->hTreeChild = hItem;
1904 else // (hItem->hTreeParent == NULL)
1906 if ((hItem->hTreeNext = pfl->hTreeFirst) != NULL)
1907 hItem->hTreeNext->hTreePrevious = hItem;
1908 pfl->hTreeFirst = hItem;
1911 hItem->iFirstImage = pai->iFirstImage;
1912 hItem->iSecondImage = pai->iSecondImage;
1913 hItem->dwFlags = pai->dwFlags;
1914 hItem->lpUser = pai->lParam;
1918 REALLOC (hItem->apszText, hItem->cpszText, 1, max(1,pfl->cColumns));
1919 hItem->apszText[0] = (LPTSTR)Allocate (sizeof(TCHAR)*(1+lstrlen(pai->pszText)));
1920 lstrcpy (hItem->apszText[0], pai->pszText);
1923 hItem->fVisible = FALSE;
1924 FastList_RepairOneVisibilityFlag (pfl, hItem);
1926 pfl->lItems->Add (hItem);
1927 pfl->fSortBeforePaint = TRUE;
1928 pfl->fSyncScrollBeforePaint = TRUE;
1929 FastList_Notify_AddItem (pfl, hItem);
1930 FastList_Repaint (pfl);
1937 void FastList_OnCommand_RemoveItem (HWND hList, HLISTITEM hItem)
1940 if ((pfl = GetFastList (hList)) != NULL)
1944 FastList_DeleteItem (pfl, hItem);
1948 FastList_Begin (pfl->hList);
1950 while ((hItem = (HLISTITEM)(pfl->lItems->GetFirstObject())) != NULL)
1951 FastList_DeleteItem (pfl, hItem);
1953 FastList_End (pfl->hList);
1956 FastList_Repaint (pfl);
1957 FastList_Notify_ItemSelect (pfl);
1962 LPCTSTR FastList_OnCommand_GetItemText (HWND hList, HLISTITEM hItem, int iColumn)
1966 if ((iColumn < 0) || (iColumn >= (int)(hItem->cpszText)))
1968 return hItem->apszText[ iColumn ];
1972 void FastList_OnCommand_SetItemText (HWND hList, LPFASTLISTITEMCOLUMN pflic, LPCTSTR pszText)
1975 if ((pfl = GetFastList (hList)) != NULL)
1977 if ((pflic) && (pflic->hItem) && (pflic->icol >= 0))
1979 if (REALLOC (pflic->hItem->apszText, pflic->hItem->cpszText, pflic->icol+1, 1))
1981 if (pflic->hItem->apszText[ pflic->icol ] != NULL)
1983 Free (pflic->hItem->apszText[ pflic->icol ]);
1984 pflic->hItem->apszText[ pflic->icol ] = NULL;
1986 if (pszText != NULL)
1988 pflic->hItem->apszText[ pflic->icol ] = (LPTSTR)Allocate (sizeof(TCHAR)*(1+lstrlen(pszText)));
1989 lstrcpy (pflic->hItem->apszText[ pflic->icol ], pszText);
1991 pfl->fSortBeforePaint = TRUE;
1992 FastList_Notify_ItemChanged (pfl, pflic->hItem);
1993 FastList_Repaint (pfl);
2000 LPARAM FastList_OnCommand_GetItemParam (HWND hList, HLISTITEM hItem)
2002 return (hItem == NULL) ? 0 : (hItem->lpUser);
2006 void FastList_OnCommand_SetItemParam (HWND hList, HLISTITEM hItem, LPARAM lpUser)
2009 if ((pfl = GetFastList (hList)) != NULL)
2013 hItem->lpUser = lpUser;
2014 pfl->lItems->Update (hItem);
2016 pfl->fSortBeforePaint = TRUE;
2017 FastList_Notify_ItemChanged (pfl, hItem);
2018 FastList_Repaint (pfl);
2024 DWORD FastList_OnCommand_GetItemFlags (HWND hList, HLISTITEM hItem)
2026 return (hItem == NULL) ? 0 : (hItem->dwFlags);
2030 void FastList_OnCommand_SetItemFlags (HWND hList, HLISTITEM hItem, DWORD dwFlagsNew)
2033 if ((pfl = GetFastList (hList)) != NULL)
2037 FastList_Begin (hList);
2039 DWORD dwFlagsOld = hItem->dwFlags;
2040 hItem->dwFlags = dwFlagsNew;
2042 if ( (dwFlagsOld & FLIF_TREEVIEW_ONLY) != (dwFlagsNew & FLIF_TREEVIEW_ONLY) )
2044 FastList_RepairOneVisibilityFlag (pfl, hItem);
2045 FastList_Repaint (pfl);
2048 if ( (dwFlagsNew & FLIF_DISALLOW_SELECT) && (hItem->fSelected) )
2050 FastList_PerformSelectItem (pfl, hItem, FALSE);
2051 FastList_Repaint (pfl);
2054 if ( (dwFlagsNew & FLIF_DISALLOW_COLLAPSE) && !(hItem->fExpanded) )
2056 FastList_OnCommand_Expand (hList, hItem, TRUE);
2057 FastList_Repaint (pfl);
2060 if ( (dwFlagsOld & FLIF_DROPHIGHLIGHT) != (dwFlagsNew & FLIF_DROPHIGHLIGHT) )
2061 FastList_Repaint (pfl);
2063 FastList_Notify_ItemChanged (pfl, hItem);
2064 FastList_End (hList);
2070 int FastList_OnCommand_GetItemImage (HWND hList, HLISTITEM hItem, int iImage)
2072 if (hItem && (iImage==0 || iImage==1))
2073 return (iImage == 0) ? (hItem->iFirstImage) : (hItem->iSecondImage);
2075 return IMAGE_NOIMAGE;
2079 void FastList_OnCommand_SetItemImage (HWND hList, LPFASTLISTITEMIMAGE pflii, int iImage)
2082 if ((pfl = GetFastList (hList)) != NULL)
2084 if (pflii && pflii->hItem && (pflii->iImage==0 || pflii->iImage==1))
2086 if (pflii->iImage == 0)
2087 pflii->hItem->iFirstImage = iImage;
2088 else // (pflii->iImage == 1)
2089 pflii->hItem->iSecondImage = iImage;
2091 FastList_Notify_ItemChanged (pfl, pflii->hItem);
2092 FastList_Repaint (pfl);
2098 BOOL FastList_OnCommand_IsExpanded (HWND hList, HLISTITEM hItem)
2100 return (hItem) ? (hItem->fExpanded) : FALSE;
2104 void FastList_OnCommand_Expand (HWND hList, HLISTITEM hItem, BOOL fExpand)
2107 if ((pfl = GetFastList (hList)) != NULL)
2109 if (hItem && (hItem->fExpanded != fExpand) && (fExpand || !(hItem->dwFlags & FLIF_DISALLOW_COLLAPSE)))
2111 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE) ? TRUE : FALSE;
2113 hItem->fExpanded = fExpand;
2114 pfl->fSyncScrollBeforePaint = TRUE;
2115 pfl->fSyncIndicesBeforePaint = TRUE;
2116 FastList_RepairVisibilityFlags (pfl, hItem, (!hItem->fExpanded || !hItem->fVisible) && (fTreeMode));
2117 FastList_Notify_ItemChanged (pfl, hItem);
2118 FastList_Repaint (pfl);
2124 BOOL FastList_OnCommand_ItemVisible (HWND hList, HLISTITEM hItem, BOOL fSet)
2127 return (hItem) ? (hItem->fVisible) : FALSE;
2130 if ((pfl = GetFastList (hList)) != NULL)
2132 if (hItem && hItem->fVisible)
2134 pfl->hEnsureVisible = hItem;
2135 FastList_Repaint (pfl);
2142 HLISTITEM FastList_OnCommand_ItemFocus (HWND hList, HLISTITEM hItem, BOOL fSet)
2145 if ((pfl = GetFastList (hList)) != NULL)
2148 return (hItem) ? (HLISTITEM)(hItem->fFocused) : pfl->hFocused;
2150 if (pfl->hFocused != hItem)
2152 if (pfl->hFocused != NULL)
2154 pfl->hFocused->fFocused = FALSE;
2155 FastList_Notify_ItemChanged (pfl, pfl->hFocused);
2157 if ((pfl->hFocused = hItem) != NULL)
2159 pfl->hFocused->fFocused = TRUE;
2160 FastList_Notify_ItemChanged (pfl, pfl->hFocused);
2162 FastList_Repaint (pfl);
2170 void FastList_OnCommand_GetImageLists (HWND hList, HIMAGELIST *phiSmall, HIMAGELIST *phiLarge)
2173 if ((pfl = GetFastList (hList)) != NULL)
2176 *phiSmall = pfl->hilSmall;
2178 *phiLarge = pfl->hilLarge;
2183 void FastList_OnCommand_SetImageLists (HWND hList, HIMAGELIST hiSmall, HIMAGELIST hiLarge)
2186 if ((pfl = GetFastList (hList)) != NULL)
2188 pfl->hilSmall = hiSmall;
2189 pfl->hilLarge = hiLarge;
2190 FastList_Repaint (pfl);
2195 HIMAGELIST FastList_OnCommand_CreateDragImage (HWND hList, HLISTITEM hItem)
2197 HIMAGELIST hil = NULL;
2200 if ((pfl = GetFastList (hList)) != NULL)
2205 // First find out how big this item is. Note that we'll ask
2206 // for the item regions, while specifying the fDragImage flag
2207 // in the paintitem request--that will make it draw only the
2210 HDC hdc = CreateCompatibleDC (NULL);
2211 HFONT hfOld = (HFONT)SelectObject (hdc, pfl->hf);
2214 FastList_CalcItemRect (pfl, 0, &rItem, !!pfl->hScrollH, !!pfl->hScrollV);
2216 FASTLISTITEMREGIONS reg;
2217 FastList_CallPaintItem (pfl, hdc, FALSE, TRUE, hItem->index, &rItem, ®, NULL, NULL);
2219 SelectObject (hdc, hfOld);
2222 RECT rDragImage = reg.rSelect;
2224 rDragImage.left -= reg.rSelect.left;
2225 rDragImage.right -= reg.rSelect.left;
2226 rDragImage.top -= reg.rSelect.top;
2227 rDragImage.bottom -= reg.rSelect.top;
2229 rItem.left -= reg.rSelect.left;
2230 rItem.right -= reg.rSelect.left;
2231 rItem.top -= reg.rSelect.top;
2232 rItem.bottom -= reg.rSelect.top;
2234 // Okay, now we know how big the item will be. Create a bitmap,
2235 // draw onto it, and stuff it into an imagelist.
2238 HDC hdcBitmap = CreateCompatibleDC (hdc);
2239 HBITMAP bmp = CreateCompatibleBitmap (hdc, cxRECT(rDragImage), cyRECT(rDragImage));
2240 HBITMAP bmpOld = (HBITMAP)SelectObject (hdcBitmap, bmp);
2241 hfOld = (HFONT)SelectObject (hdcBitmap, pfl->hf);
2243 HBRUSH hbr = CreateSolidBrush (clrTRANSPARENT);
2244 FillRect (hdcBitmap, &rDragImage, hbr);
2247 FastList_CallPaintItem (pfl, hdcBitmap, TRUE, TRUE, hItem->index, &rItem, NULL, NULL, NULL);
2249 SelectObject (hdcBitmap, hfOld);
2250 SelectObject (hdcBitmap, bmpOld);
2251 DeleteDC (hdcBitmap);
2252 ReleaseDC (NULL, hdc);
2254 if ((hil = ImageList_Create (cxRECT(rDragImage), cyRECT(rDragImage), ILC_MASK, 1, 1)) != NULL)
2256 ImageList_AddMasked (hil, bmp, clrTRANSPARENT);
2267 LPFASTLISTSORTFUNC FastList_OnCommand_GetSortFunc (HWND hList)
2270 if ((pfl = GetFastList (hList)) != NULL)
2272 return pfl->pfnSort;
2279 void FastList_OnCommand_SetSortFunc (HWND hList, LPFASTLISTSORTFUNC pfn)
2282 if ((pfl = GetFastList (hList)) != NULL)
2285 pfl->fSortBeforePaint = TRUE;
2290 void FastList_OnCommand_GetSortStyle (HWND hList, int *piColSort, BOOL *pfRevSort)
2293 if ((pfl = GetFastList (hList)) != NULL)
2296 *piColSort = pfl->iColSort;
2298 *pfRevSort = pfl->fRevSort;
2303 void FastList_OnCommand_SetSortStyle (HWND hList, int iColSort, BOOL fRevSort)
2306 if ((pfl = GetFastList (hList)) != NULL)
2308 pfl->iColSort = iColSort;
2309 pfl->fRevSort = fRevSort;
2310 pfl->fSortBeforePaint = TRUE;
2311 FastList_Repaint (pfl);
2316 void FastList_OnCommand_Sort (HWND hList)
2319 if ((pfl = GetFastList (hList)) != NULL)
2321 pfl->fSortBeforePaint = FALSE;
2322 FastList_Repaint (pfl);
2327 int FastList_OnCommand_GetColumnCount (HWND hList)
2332 if ((pfl = GetFastList (hList)) != NULL)
2334 for (cColumns = 0; cColumns < (int)pfl->cColumns; ++cColumns)
2336 if (pfl->aColumns[ cColumns ].pszText == NULL)
2345 BOOL FastList_OnCommand_GetColumn (HWND hList, int iColumn, LPFASTLISTCOLUMN pcol)
2348 if ((pfl = GetFastList (hList)) == NULL)
2351 if ((iColumn < 0) || (iColumn >= (int)pfl->cColumns) || (!pfl->aColumns[ iColumn ].pszText))
2356 pcol->dwFlags = FLCF_JUSTIFY_LEFT;
2357 if ((pfl->aColumns[ iColumn ].fmt & HDF_JUSTIFYMASK) == HDF_RIGHT)
2358 pcol->dwFlags = FLCF_JUSTIFY_RIGHT;
2359 else if ((pfl->aColumns[ iColumn ].fmt & HDF_JUSTIFYMASK) == HDF_CENTER)
2360 pcol->dwFlags = FLCF_JUSTIFY_CENTER;
2361 pcol->cxWidth = pfl->aColumns[ iColumn ].cxy;
2362 lstrcpy (pcol->szText, pfl->aColumns[ iColumn ].pszText);
2369 void FastList_OnCommand_SetColumn (HWND hList, int iColumn, LPFASTLISTCOLUMN pcol)
2372 if ((pfl = GetFastList (hList)) != NULL)
2374 iColumn = limit (0, iColumn, (int)pfl->cColumns);
2376 if (REALLOC (pfl->aColumns, pfl->cColumns, 1+iColumn, 1))
2378 if (pfl->aColumns[ iColumn ].pszText)
2379 Free (pfl->aColumns[ iColumn ].pszText);
2380 memset (&pfl->aColumns[ iColumn ], 0x00, sizeof(HD_ITEM));
2384 if ((pcol->dwFlags & FLCF_JUSTIFY_MASK) == FLCF_JUSTIFY_RIGHT)
2385 pfl->aColumns[ iColumn ].fmt |= HDF_RIGHT;
2386 else if ((pcol->dwFlags & FLCF_JUSTIFY_MASK) == FLCF_JUSTIFY_CENTER)
2387 pfl->aColumns[ iColumn ].fmt |= HDF_CENTER;
2389 pfl->aColumns[ iColumn ].fmt |= HDF_LEFT;
2391 pfl->aColumns[ iColumn ].cxy = pcol->cxWidth;
2392 pfl->aColumns[ iColumn ].pszText = (LPTSTR)Allocate (sizeof(TCHAR)*(1+lstrlen(pcol->szText)));
2393 lstrcpy (pfl->aColumns[ iColumn ].pszText, pcol->szText);
2395 pfl->aColumns[ iColumn ].mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT;
2398 FastList_SyncHeader (pfl);
2404 BOOL FastList_OnCommand_IsSelected (HWND hList, HLISTITEM hItem)
2406 return hItem->fSelected;
2410 void FastList_OnCommand_SelectItem (HWND hList, HLISTITEM hItem, BOOL fSelect)
2413 if ((pfl = GetFastList (hList)) != NULL)
2417 if (!fSelect || !(hItem->dwFlags & FLIF_DISALLOW_SELECT))
2420 FastList_PerformSelectTest (pfl, hItem);
2421 FastList_PerformSelectItem (pfl, hItem, fSelect);
2426 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE);
2427 BOOL fMultiple = (pfl->dwStyle & FLS_SELECTION_MULTIPLE);
2428 BOOL fLevel = (pfl->dwStyle & (FLS_SELECTION_LEVEL & ~FLS_SELECTION_MULTIPLE));
2429 BOOL fSibling = (pfl->dwStyle & (FLS_SELECTION_SIBLING & ~FLS_SELECTION_MULTIPLE));
2432 (fMultiple && (!fTreeMode || (!fLevel && !fSibling))) )
2434 FastList_Begin (hList);
2436 for (LPENUM pEnum = pfl->lItems->FindFirst(); pEnum; pEnum = pEnum->FindNext())
2438 hItem = (HLISTITEM)(pEnum->GetObject());
2439 if (!fSelect || !(hItem->dwFlags & FLIF_DISALLOW_SELECT))
2440 FastList_PerformSelectItem (pfl, hItem, fSelect);
2443 FastList_End (hList);
2450 HLISTITEM FastList_OnCommand_FindList (HWND hList, HLISTITEM hItem, DWORD dwCode)
2453 if ((pfl = GetFastList (hList)) != NULL)
2457 case FLM_FINDLIST_FIRST:
2458 return pfl->hListFirst;
2460 case FLM_FINDLIST_PREVIOUS:
2461 return (hItem) ? (hItem->hListPrevious) : NULL;
2463 case FLM_FINDLIST_NEXT:
2464 return (hItem) ? (hItem->hListNext) : (pfl->hListFirst);
2472 HLISTITEM FastList_OnCommand_FindTree (HWND hList, HLISTITEM hItem, DWORD dwCode)
2475 if ((pfl = GetFastList (hList)) != NULL)
2479 case FLM_FINDTREE_PARENT:
2480 return (hItem) ? (hItem->hTreeParent) : NULL;
2482 case FLM_FINDTREE_CHILD:
2483 return (hItem) ? (hItem->hTreeChild) : (pfl->hTreeFirst);
2485 case FLM_FINDTREE_PREVIOUS:
2486 return (hItem) ? (hItem->hTreePrevious) : NULL;
2488 case FLM_FINDTREE_NEXT:
2489 return (hItem) ? (hItem->hTreeNext) : NULL;
2496 HLISTITEM FastList_OnCommand_FindSelected (HWND hList, HLISTITEM hItem)
2500 return hItem->hSelectNext;
2504 if ((pfl = GetFastList (hList)) != NULL)
2506 return pfl->hSelectFirst;
2513 HLISTITEM FastList_OnCommand_FindItem (HWND hList, LPENUM *ppEnum, LPARAM lpUser)
2516 if ((pfl = GetFastList (hList)) != NULL)
2519 return (HLISTITEM)(pfl->lkUserParam->GetFirstObject (&lpUser));
2520 else if (ppEnum && (((*ppEnum) = pfl->lkUserParam->FindFirst (&lpUser)) != NULL))
2521 return (HLISTITEM)((*ppEnum)->GetObject());
2527 HLISTITEM FastList_OnCommand_FindNextItem (HWND hList, LPENUM *ppEnum)
2529 if (ppEnum && (((*ppEnum) = (*ppEnum)->FindNext()) != NULL))
2530 return (HLISTITEM)((*ppEnum)->GetObject());
2535 void FastList_OnCommand_FindClose (HWND hList, LPENUM *ppEnum)
2537 if (ppEnum && (*ppEnum))
2545 HLISTITEM FastList_OnCommand_FindVisible (HWND hList, HLISTITEM hItem, DWORD dwCode)
2548 if ((pfl = GetFastList (hList)) != NULL)
2550 if (pfl->fSortBeforePaint)
2551 FastList_PerformSort (pfl);
2552 if (pfl->fSyncIndicesBeforePaint)
2553 FastList_RepairVisibilityIndices (pfl);
2557 case FLM_FINDVISIBLE_FIRST:
2558 return (pfl->cVisible) ? pfl->aVisibleHeap[0] : NULL;
2560 case FLM_FINDVISIBLE_NEXT:
2561 if (!hItem->fVisible)
2563 if (hItem->index == (int)(pfl->cVisible-1))
2565 return pfl->aVisibleHeap[ hItem->index +1 ];
2573 int FastList_OnCommand_GetItemCount (HWND hList, BOOL fVisibleOnly)
2576 if ((pfl = GetFastList (hList)) == NULL)
2579 return (fVisibleOnly) ? pfl->cVisible : pfl->lItems->GetCount();
2583 HLISTITEM FastList_OnCommand_ItemFromPoint (HWND hList, POINT *pptClient, BOOL fStrict)
2585 HLISTITEM hItem = NULL;
2588 if ((pfl = GetFastList (hList)) != NULL)
2590 if (pfl->fSortBeforePaint)
2591 FastList_PerformSort (pfl);
2592 if (pfl->fSyncIndicesBeforePaint)
2593 FastList_RepairVisibilityIndices (pfl);
2595 // Adjust the client coordinates we were given based on the current
2596 // position of the scrollbars.
2598 LONG xField = pptClient->x + pfl->dxPixel;
2599 LONG yField = pptClient->y + pfl->dyPixel;
2601 // Every item's overall RECT is symmetrical, regardless of the
2602 // current view mode. Find out how big those RECTs are.
2605 FastList_CalcItemRect (pfl, 0, &rTemplate, !!pfl->hScrollH, !!pfl->hScrollV);
2607 // How large is the current client area?
2610 GetClientRect (pfl->hList, &rClient);
2612 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
2614 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
2616 rClient.top += FastList_GetHeaderHeight (pfl);
2618 // The specified point exists in exactly one item (or none at all).
2619 // Just which item that is depends on what the current view mode is.
2623 switch (pfl->dwStyle & FLS_VIEW_MASK)
2625 case FLS_VIEW_LARGE:
2627 LONG ixIndex = xField / cxRECT(rTemplate);
2628 LONG iyIndex = yField / cyRECT(rTemplate);
2630 LONG cxArray = cxRECT(rClient) / cxRECT(rTemplate);
2631 cxArray = max( cxArray, 1 );
2633 index = ixIndex + iyIndex * cxArray;
2637 case FLS_VIEW_SMALL:
2639 LONG ixIndex = xField / cxRECT(rTemplate);
2640 LONG iyIndex = yField / cyRECT(rTemplate);
2642 LONG cyArray = cyRECT(rClient) / cyRECT(rTemplate);
2643 cyArray = max( cyArray, 1 );
2645 index = iyIndex + ixIndex * cyArray;
2651 case FLS_VIEW_TREELIST:
2652 index = (yField - rClient.top) / cyRECT(rTemplate);
2656 if ((index >= 0) && (index < (int)pfl->cVisible))
2657 hItem = pfl->aVisibleHeap[ index ];
2659 // If there is indeed an item underneath that point, test the item's
2660 // regions--and our window styles--to see if a click on the specified
2661 // point actually *changes* that item.
2663 if (hItem && fStrict)
2667 FASTLISTITEMREGIONS reg;
2668 FastList_OnCommand_GetItemRegions (hList, hItem, ®, pptClient, &fHit);
2670 if (!PtInRect (®.rSelect, *pptClient))
2672 else if (PtInRect (®.rHighlight, *pptClient) && !fHit && (pfl->dwStyle & FLS_HIT_TEXTONLY))
2681 void FastList_OnCommand_GetItemRegions (HWND hList, HLISTITEM hItem, LPFASTLISTITEMREGIONS pReg, POINT *pptTest, BOOL *pfHit)
2684 if ((pfl = GetFastList (hList)) != NULL)
2686 if (pfl->fSortBeforePaint)
2687 FastList_PerformSort (pfl);
2688 if (pfl->fSyncIndicesBeforePaint)
2689 FastList_RepairVisibilityIndices (pfl);
2691 if (hItem && !hItem->fVisible && pReg)
2693 memset (pReg, 0x00, sizeof(FASTLISTITEMREGIONS));
2695 else if (hItem && hItem->fVisible)
2697 HDC hdc = CreateCompatibleDC (NULL);
2698 HFONT hfOld = (HFONT)SelectObject (hdc, pfl->hf);
2701 FastList_CalcItemRect (pfl, hItem->index, &rItem, !!pfl->hScrollH, !!pfl->hScrollV);
2702 rItem.left -= pfl->dxPixel;
2703 rItem.right -= pfl->dxPixel;
2704 rItem.top -= pfl->dyPixel;
2705 rItem.bottom -= pfl->dyPixel;
2707 FastList_CallPaintItem (pfl, hdc, FALSE, FALSE, hItem->index, &rItem, pReg, pptTest, pfHit);
2709 SelectObject (hdc, hfOld);
2716 LPFASTLISTTEXTCALLBACK FastList_OnCommand_GetTextCallback (HWND hList)
2719 if ((pfl = GetFastList (hList)) != NULL)
2720 return pfl->pfnText;
2726 void FastList_OnCommand_SetTextCallback (HWND hList, LPFASTLISTTEXTCALLBACK pfn, DWORD dwCookie)
2729 if ((pfl = GetFastList (hList)) != NULL)
2732 pfl->dwCookieText = dwCookie;
2738 * NOTIFICATION ROUTINES ______________________________________________________
2742 BOOL FastList_Notify_GetItemText (LPFASTLIST pfl, HLISTITEM hItem, int icol, LPTSTR pszText, size_t cchText, size_t *pcchRequired)
2744 FLN_GETITEMTEXT_PARAMS fln;
2745 fln.hdr.hwndFrom = pfl->hList;
2746 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2747 fln.hdr.code = FLN_GETITEMTEXT;
2748 fln.item.hItem = hItem;
2749 fln.item.icol = icol;
2750 fln.item.lParam = hItem->lpUser;
2751 fln.item.pszText = pszText;
2752 fln.item.cchTextMax = cchText;
2756 if (!(*pfl->pfnText)( pfl->hList, &fln, pfl->dwCookieText ))
2761 if (!GetParent (pfl->hList))
2763 if (!SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln))
2767 *pcchRequired = fln.item.cchTextMax;
2772 BOOL FastList_Notify_ItemChanged (LPFASTLIST pfl, HLISTITEM hItem)
2774 if (!GetParent (pfl->hList))
2777 FLN_ITEMCHANGED_PARAMS fln;
2778 fln.hdr.hwndFrom = pfl->hList;
2779 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2780 fln.hdr.code = FLN_ITEMCHANGED;
2782 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2786 BOOL FastList_Notify_AddItem (LPFASTLIST pfl, HLISTITEM hItem)
2788 if (!GetParent (pfl->hList))
2791 FLN_ADDITEM_PARAMS fln;
2792 fln.hdr.hwndFrom = pfl->hList;
2793 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2794 fln.hdr.code = FLN_ADDITEM;
2796 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2800 BOOL FastList_Notify_RemoveItem (LPFASTLIST pfl, HLISTITEM hItem)
2802 if (!GetParent (pfl->hList))
2805 FLN_REMOVEITEM_PARAMS fln;
2806 fln.hdr.hwndFrom = pfl->hList;
2807 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2808 fln.hdr.code = FLN_REMOVEITEM;
2810 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2814 BOOL FastList_Notify_ColumnClick (LPFASTLIST pfl, int icol, BOOL fDouble)
2816 if (!GetParent (pfl->hList))
2819 FLN_COLUMNCLICK_PARAMS fln;
2820 fln.hdr.hwndFrom = pfl->hList;
2821 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2822 fln.hdr.code = FLN_COLUMNCLICK;
2824 fln.fDouble = fDouble;
2825 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2829 BOOL FastList_Notify_ColumnResize (LPFASTLIST pfl, int icol, LONG cxWidth)
2831 if (!GetParent (pfl->hList))
2834 FLN_COLUMNRESIZE_PARAMS fln;
2835 fln.hdr.hwndFrom = pfl->hList;
2836 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2837 fln.hdr.code = FLN_COLUMNRESIZE;
2839 fln.cxWidth = cxWidth;
2840 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2844 BOOL FastList_Notify_ItemSelect (LPFASTLIST pfl)
2846 if (!GetParent (pfl->hList))
2849 FLN_ITEMSELECT_PARAMS fln;
2850 fln.hdr.hwndFrom = pfl->hList;
2851 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2852 fln.hdr.code = FLN_ITEMSELECT;
2853 fln.hItem = pfl->hSelectFirst;
2854 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2858 BOOL FastList_Notify_ItemExpand (LPFASTLIST pfl, HLISTITEM hItem)
2860 if (!GetParent (pfl->hList))
2863 FLN_ITEMEXPAND_PARAMS fln;
2864 fln.hdr.hwndFrom = pfl->hList;
2865 fln.hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2866 fln.hdr.code = FLN_ITEMEXPAND;
2868 fln.fExpanded = hItem->fExpanded;
2869 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)fln.hdr.idFrom, (LPARAM)&fln);
2873 BOOL FastList_Notify_Generic (LPFASTLIST pfl, DWORD dwCode)
2875 if (!GetParent (pfl->hList))
2879 hdr.hwndFrom = pfl->hList;
2880 hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2882 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)hdr.idFrom, (LPARAM)&hdr);
2886 BOOL FastList_Notify_Drag (LPFASTLIST pfl, DWORD dwCode, LPFLN_DRAG_PARAMS pfln)
2888 if (!GetParent (pfl->hList))
2891 pfln->hdr.hwndFrom = pfl->hList;
2892 pfln->hdr.idFrom = GetWindowLong (pfl->hList, GWL_ID);
2893 pfln->hdr.code = dwCode;
2894 return (BOOL)SendMessage (GetParent (pfl->hList), WM_NOTIFY, (WPARAM)pfln->hdr.idFrom, (LPARAM)pfln);
2899 * SUPPORT ROUTINES ___________________________________________________________
2903 void FastList_Repaint (LPFASTLIST pfl)
2905 if ((pfl->fRepaintRequired = (pfl->nBegin) ? TRUE : FALSE) == FALSE)
2908 GetClientRect (pfl->hList, &rClient);
2909 InvalidateRect (pfl->hList, &rClient, TRUE);
2910 UpdateWindow (pfl->hList);
2915 HLISTITEM FastList_CreateItem (LPFASTLIST pfl)
2917 HLISTITEM hItem = New (LISTITEM);
2918 memset (hItem, 0x00, sizeof(LISTITEM));
2919 hItem->fExpanded = TRUE;
2924 void FastList_DeleteItem (LPFASTLIST pfl, HLISTITEM hItem)
2928 // Remove any children of this item, even if we're not in
2929 // treeview mode now.
2931 while (hItem->hTreeChild)
2933 FastList_DeleteItem (pfl, hItem->hTreeChild);
2936 FastList_Notify_RemoveItem (pfl, hItem); // notify *before* delete
2938 if (pfl->hFocused == hItem)
2939 pfl->hFocused = FALSE;
2941 // Unlink this item from the List chain
2943 if (pfl->hListFirst == hItem)
2944 pfl->hListFirst = hItem->hListNext;
2945 if (hItem->hListPrevious)
2946 hItem->hListPrevious->hListNext = hItem->hListNext;
2947 if (hItem->hListNext)
2948 hItem->hListNext->hListPrevious = hItem->hListPrevious;
2950 // Unlink this item from the Tree chain
2952 if (pfl->hTreeFirst == hItem)
2953 pfl->hTreeFirst = hItem->hTreeNext;
2954 if (hItem->hTreePrevious)
2955 hItem->hTreePrevious->hTreeNext = hItem->hTreeNext;
2956 if (hItem->hTreeNext)
2957 hItem->hTreeNext->hTreePrevious = hItem->hTreePrevious;
2958 if (hItem->hTreeParent && (hItem->hTreeParent->hTreeChild == hItem))
2959 hItem->hTreeParent->hTreeChild = hItem->hTreeNext;
2961 // Unlink this item from the Selection chain
2963 if (hItem->hSelectPrevious)
2964 hItem->hSelectPrevious->hSelectNext = hItem->hSelectNext;
2965 if (hItem->hSelectNext)
2966 hItem->hSelectNext->hSelectPrevious = hItem->hSelectPrevious;
2967 if (pfl->hSelectFirst == hItem)
2968 pfl->hSelectFirst = hItem->hSelectNext;
2969 if (pfl->hAnchor == hItem)
2970 pfl->hAnchor = NULL;
2971 hItem->hSelectPrevious = NULL;
2972 hItem->hSelectNext = NULL;
2974 // If we're holding onto this item as the next guy who we should
2975 // ensure is visible, forget about it there too.
2977 if (pfl->hEnsureVisible == hItem)
2978 pfl->hEnsureVisible = NULL;
2980 // Remove this item from the hashlist, and deallocate any memory
2981 // associated with it.
2983 pfl->lItems->Remove (hItem);
2985 if (hItem->apszText)
2987 for (size_t iCol = 0; iCol < hItem->cpszText; ++iCol)
2989 if (hItem->apszText[ iCol ] != NULL)
2990 Free (hItem->apszText[ iCol ]);
2992 Free (hItem->apszText);
2996 memset (hItem, 0xFE, sizeof(_FASTLISTITEM));
3000 pfl->fSyncScrollBeforePaint = TRUE;
3001 pfl->fSyncIndicesBeforePaint = TRUE;
3006 int FastList_GetListHeight (LPFASTLIST pfl)
3008 static HFONT hfLast = NULL;
3009 static int cyLast = 0;
3011 if (!cyLast || (pfl->hf != hfLast))
3016 HDC hdc = CreateCompatibleDC (NULL);
3017 HFONT hfOld = (HFONT)SelectObject (hdc, pfl->hf);
3018 GetTextMetrics (hdc, &tm);
3019 SelectObject (hdc, hfOld);
3022 cyLast = tm.tmHeight + cyABOVE_LIST_TEXT + cyBELOW_LIST_TEXT;
3023 cyLast = max( cyLast, GetSystemMetrics(SM_CYSMICON) );
3025 cyLast ++; // make the height even (for vertical dotted lines)
3032 int FastList_GetListWidth (LPFASTLIST pfl)
3036 for (size_t iColumn = 0; iColumn < pfl->cColumns; ++iColumn)
3037 if (pfl->aColumns[ iColumn ].pszText)
3038 cxWidth += pfl->aColumns[ iColumn ].cxy;
3040 if (cxWidth == 0) // no columns specified? pretend there's just one.
3043 GetClientRect (pfl->hList, &rClient);
3045 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
3046 cxWidth = cxRECT(rClient);
3053 LONG FastList_GetHeaderHeight (LPFASTLIST pfl)
3056 HDC hdc = CreateCompatibleDC (NULL);
3057 HFONT hfOld = (HFONT)SelectObject (hdc, pfl->hf);
3058 GetTextMetrics (hdc, &tm);
3059 SelectObject (hdc, hfOld);
3061 return 4*GetSystemMetrics(SM_CYBORDER) + tm.tmHeight;
3065 void FastList_GetHeaderRect (LPFASTLIST pfl, RECT *prHeader)
3067 GetClientRect (pfl->hList, prHeader);
3068 prHeader->bottom = prHeader->top + FastList_GetHeaderHeight (pfl);
3072 void FastList_UpdateColumn (LPFASTLIST pfl, int iColumn)
3074 if ((iColumn >= 0) && (iColumn < (int)pfl->cColumns) && (pfl->aColumns[ iColumn ].pszText))
3077 memset (&col, 0x00, sizeof(col));
3078 col.mask |= HDI_WIDTH;
3079 Header_GetItem (pfl->hHeader, iColumn, &col);
3081 if (pfl->aColumns[ iColumn ].cxy != col.cxy)
3083 pfl->aColumns[ iColumn ].cxy = col.cxy;
3084 pfl->fSyncScrollBeforePaint = TRUE;
3085 FastList_Notify_ColumnResize (pfl, iColumn, col.cxy);
3086 FastList_Repaint (pfl);
3092 void FastList_SyncHeader (LPFASTLIST pfl)
3094 if ((pfl->fSyncHeaderRequired = (pfl->nBegin) ? TRUE : FALSE) == FALSE)
3096 BOOL fNeedsHeader = ((pfl->dwStyle & FLS_VIEW_LIST) == FLS_VIEW_LIST);
3097 BOOL fNoSortHeader = (pfl->dwStyle & FLS_NOSORTHEADER);
3099 if (pfl->cColumns == 0)
3100 fNeedsHeader = FALSE;
3104 FastList_GetHeaderRect (pfl, &rHeader);
3106 if (fNeedsHeader && !pfl->hHeader)
3108 pfl->hHeader = CreateWindow (WC_HEADER, TEXT(""),
3109 0x80 | WS_CHILD | WS_VISIBLE | ((fNoSortHeader) ? 0 : HDS_BUTTONS),
3110 rHeader.left, rHeader.top,
3111 cxRECT(rHeader), cyRECT(rHeader),
3117 SendMessage (pfl->hHeader, WM_SETFONT, (WPARAM)(pfl->hf), 0);
3119 else if (fNeedsHeader && pfl->hHeader)
3121 DWORD dwStyle = GetWindowLong (pfl->hHeader, GWL_STYLE);
3123 dwStyle &= ~HDS_BUTTONS;
3125 dwStyle |= HDS_BUTTONS;
3126 SetWindowLong (pfl->hHeader, GWL_STYLE, dwStyle);
3128 SetWindowPos (pfl->hHeader, 0,
3129 rHeader.left, rHeader.top, cxRECT(rHeader), cyRECT(rHeader),
3130 SWP_NOACTIVATE | SWP_NOZORDER);
3132 else if (!fNeedsHeader && pfl->hHeader)
3134 DestroyWindow (pfl->hHeader);
3135 pfl->hHeader = NULL;
3138 // If we ended up with a header window, update its columns.
3142 while (Header_DeleteItem (pfl->hHeader, 0))
3144 for (size_t iCol = 0; iCol < pfl->cColumns; ++iCol)
3145 Header_InsertItem (pfl->hHeader, iCol, &pfl->aColumns[ iCol ]);
3148 pfl->fSyncScrollBeforePaint = TRUE;
3153 void FastList_SyncScroll (LPFASTLIST pfl)
3155 pfl->fSyncScrollBeforePaint = FALSE;
3158 GetClientRect (pfl->hList, &rClient);
3160 rClient.top += FastList_GetHeaderHeight (pfl);
3165 // First find out how much space we'd need, horizontally and vertically,
3166 // to display all the items we can. Remember that the number of items
3167 // we can display changes depending on whether the scrollbars appear or
3170 BOOL fAllowHScroll = ((pfl->dwStyle & FLS_VIEW_MASK) != FLS_VIEW_LARGE);
3171 BOOL fAllowVScroll = ((pfl->dwStyle & FLS_VIEW_MASK) != FLS_VIEW_SMALL);
3173 BOOL fNeedHScroll = FALSE;
3174 BOOL fNeedVScroll = FALSE;
3176 FastList_CalcFieldSize (pfl, &cxField, &cyField, fNeedHScroll, fNeedVScroll);
3178 if ( (cxField > cxRECT(rClient)) && (fAllowHScroll) )
3179 fNeedHScroll = TRUE;
3180 if ( (cyField > cyRECT(rClient)) && (fAllowVScroll) )
3181 fNeedVScroll = TRUE;
3183 FastList_CalcFieldSize (pfl, &cxField, &cyField, fNeedHScroll, fNeedVScroll);
3185 RECT rTest = rClient;
3187 rTest.right -= GetSystemMetrics(SM_CXVSCROLL);
3189 rTest.bottom -= GetSystemMetrics(SM_CYHSCROLL);
3191 if ( (cxField > cxRECT(rTest)) && (fAllowHScroll) )
3192 fNeedHScroll = TRUE;
3193 if ( (cyField > cyRECT(rTest)) && (fAllowVScroll) )
3194 fNeedVScroll = TRUE;
3196 // Now that we know the field size, create, remove or position
3199 if (pfl->hScrollV && !fNeedVScroll)
3201 DestroyWindow (pfl->hScrollV);
3202 pfl->hScrollV = NULL;
3205 else if (fNeedVScroll)
3207 RECT rScroll = rClient;
3208 rScroll.left = rScroll.right - GetSystemMetrics (SM_CXVSCROLL);
3210 rScroll.bottom -= GetSystemMetrics (SM_CYHSCROLL);
3214 pfl->hScrollV = CreateWindow ("ScrollBar", TEXT(""),
3215 WS_CHILD | WS_VISIBLE | SBS_VERT,
3216 rScroll.left, rScroll.top,
3217 cxRECT(rScroll), cyRECT(rScroll),
3225 SetWindowPos (pfl->hScrollV, 0,
3226 rScroll.left, rScroll.top, cxRECT(rScroll), cyRECT(rScroll),
3227 SWP_NOZORDER | SWP_NOACTIVATE);
3230 else // (!fNeedVScroll)
3235 if (pfl->hScrollH && !fNeedHScroll)
3237 DestroyWindow (pfl->hScrollH);
3238 pfl->hScrollH = NULL;
3241 else if (fNeedHScroll)
3243 RECT rScroll = rClient;
3244 rScroll.top = rScroll.bottom - GetSystemMetrics (SM_CYHSCROLL);
3246 rScroll.right -= GetSystemMetrics (SM_CXVSCROLL);
3250 pfl->hScrollH = CreateWindow ("ScrollBar", TEXT(""),
3251 WS_CHILD | WS_VISIBLE | SBS_HORZ,
3252 rScroll.left, rScroll.top,
3253 cxRECT(rScroll), cyRECT(rScroll),
3261 SetWindowPos (pfl->hScrollH, 0,
3262 rScroll.left, rScroll.top, cxRECT(rScroll), cyRECT(rScroll),
3263 SWP_NOZORDER | SWP_NOACTIVATE);
3266 else // (!fNeedHScroll)
3271 FastList_SyncScrollPos (pfl);
3275 void FastList_SyncScrollPos (LPFASTLIST pfl)
3278 GetClientRect (pfl->hList, &rClient);
3280 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
3282 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
3284 rClient.top += FastList_GetHeaderHeight (pfl);
3288 FastList_CalcFieldSize (pfl, &cxField, &cyField, !!pfl->hScrollH, !!pfl->hScrollV);
3291 pfl->dxPixel = limit( 0, pfl->dxPixel, (cxField-cxRECT(rClient)) );
3293 pfl->dyPixel = limit( 0, pfl->dyPixel, (cyField-cyRECT(rClient)) );
3298 memset (&si, 0x00, sizeof(SCROLLINFO));
3299 si.cbSize = sizeof(si);
3300 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
3303 si.nPage = cxRECT(rClient);
3304 si.nPos = pfl->dxPixel;
3305 SetScrollInfo (pfl->hScrollH, SB_CTL, &si, TRUE);
3310 memset (&si, 0x00, sizeof(SCROLLINFO));
3311 si.cbSize = sizeof(si);
3312 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
3315 si.nPage = cyRECT(rClient);
3316 si.nPos = pfl->dyPixel;
3317 SetScrollInfo (pfl->hScrollV, SB_CTL, &si, TRUE);
3320 FastList_ScrollHeader (pfl);
3324 void FastList_CalcFieldSize (LPFASTLIST pfl, LONG *pcxField, LONG *pcyField, BOOL fScrollH, BOOL fScrollV)
3327 GetClientRect (pfl->hList, &rClient);
3329 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
3331 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
3333 rClient.top += FastList_GetHeaderHeight (pfl);
3339 FastList_CalcItemRect (pfl, 0, &rItem, fScrollH, fScrollV);
3344 switch (pfl->dwStyle & FLS_VIEW_MASK)
3346 case FLS_VIEW_LARGE:
3347 cxArray = cxRECT(rClient) / cxRECT(rItem);
3348 cxArray = max (cxArray, 1);
3350 cyArray = DivRoundUp (pfl->cVisible, cxArray);
3353 case FLS_VIEW_SMALL:
3354 cyArray = cyRECT(rClient) / cyRECT(rItem);
3355 cyArray = max (cyArray, 1);
3357 cxArray = DivRoundUp (pfl->cVisible, cyArray);
3362 case FLS_VIEW_TREELIST:
3364 cyArray = pfl->cVisible;
3368 *pcxField = cxArray * cxRECT(rItem);
3369 *pcyField = cyArray * cyRECT(rItem);
3373 void FastList_CalcItemRect (LPFASTLIST pfl, int index, RECT *prItem, BOOL fScrollH, BOOL fScrollV)
3375 SetRectEmpty (prItem);
3378 GetClientRect (pfl->hList, &rClient);
3380 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
3382 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
3384 rClient.top += FastList_GetHeaderHeight (pfl);
3386 switch (pfl->dwStyle & FLS_VIEW_MASK)
3388 case FLS_VIEW_LARGE:
3390 // Large layout shows a two-dimensional list of 32x32 icons,
3391 // each followed beneath by text. The layout of the grid is
3392 // determined by well-known system metrics. There will be no
3393 // horizontal scrollbar; just a vertical one (if necessary).
3394 // Slots are filled in left-to-right, top-to-bottom.
3396 LONG cxRect = GetSystemMetrics (SM_CXICONSPACING);
3397 LONG cyRect = GetSystemMetrics (SM_CYICONSPACING);
3398 int cxLayout = cxRECT(rClient) / cxRect;
3399 cxLayout = max (cxLayout, 1);
3401 int vIndex = index / cxLayout; // 0 = top row
3402 int hIndex = index % cxLayout; // 0 = left row
3404 prItem->left = hIndex * cxRect;
3405 prItem->right = prItem->left + cxRect;
3406 prItem->top = vIndex * cyRect;
3407 prItem->bottom = prItem->top + cyRect;
3411 case FLS_VIEW_SMALL:
3413 // Small layout is similar: it shows a two-dimensional list of
3414 // 16x16 icons, each followed to the right by text. The vertical
3415 // layout of the grid is the same as the list default vertical
3416 // size; the horizontal layout is twice the default system metric.
3417 // Another difference: Small mode uses only a horizontal scrollbar,
3418 // not a vertical one. Slots are filled in top-to-bottom,
3421 LONG cxRect = GetSystemMetrics (SM_CXICONSPACING) * 2;
3422 LONG cyRect = FastList_GetListHeight (pfl);
3423 int cyLayout = cyRECT(rClient) / cyRect;
3424 cyLayout = max (cyLayout, 1);
3426 int hIndex = index / cyLayout; // 0 = left row
3427 int vIndex = index % cyLayout; // 0 = top row
3429 prItem->left = hIndex * cxRect;
3430 prItem->right = prItem->left + cxRect;
3431 prItem->top = vIndex * cyRect;
3432 prItem->bottom = prItem->top + cyRect;
3438 case FLS_VIEW_TREELIST:
3440 // List and Tree layouts are fairly straight-forward: they each show
3441 // a one-dimensional array of items, each of which runs horizontally
3442 // from edge to edge. The vertical layout of the grid is the default
3443 // vertical size (see FastList_GetListHeight()). A vertical scrollbar
3444 // is applied if necessary; a horizontal scrollbar is added for the
3447 LONG cyRect = FastList_GetListHeight (pfl);
3450 prItem->right = FastList_GetListWidth (pfl);
3451 prItem->top = rClient.top + index * cyRect;
3452 prItem->bottom = prItem->top + cyRect;
3459 void FastList_CallPaintItem (LPFASTLIST pfl, HDC hdc, BOOL fDraw, BOOL fDragImage, int iItem, RECT *prItem, LPFASTLISTITEMREGIONS pReg, POINT *pptTest, BOOL *pfHit)
3461 FASTLISTDRAWITEM di;
3462 memset (&di, 0x00, sizeof(di));
3465 di.fDragImage = fDragImage;
3466 di.hWnd = pfl->hList;
3467 di.hItem = pfl->aVisibleHeap[ iItem ];
3468 di.lParam = di.hItem->lpUser;
3472 di.ptTextTest = *pptTest;
3476 FastList_OnPaintItem (pfl, &di);
3477 // if (GetParent (pfl->hList))
3478 // SendMessage (GetParent (pfl->hList), WM_DRAWITEM, (WPARAM)GetWindowLong (pfl->hList, GWL_ID), (LPARAM)&di);
3480 // FastList_OnPaintItem (pfl, &di);
3483 *pfHit = di.fTextTestHit;
3485 memcpy (pReg, &di.reg, sizeof(FASTLISTITEMREGIONS));
3489 LPTSTR FastList_GetColumnText (LPFASTLIST pfl, HLISTITEM hItem, int icol, BOOL fAlternateBuffer)
3491 if ((icol < (int)hItem->cpszText) && (hItem->apszText[ icol ] != NULL))
3492 return hItem->apszText[ icol ];
3494 if (!GetParent (pfl->hList))
3497 // We'll have to send a message to the parent window, and hope the user
3498 // catches it to tell us what the text should be. We have two dynamically-
3499 // allocated buffers we use for storing text.
3501 static LPTSTR pszTextA = NULL;
3502 static size_t cchTextA = 0;
3504 static LPTSTR pszTextB = NULL;
3505 static size_t cchTextB = 0;
3507 LPTSTR *ppszText = (fAlternateBuffer) ? &pszTextB : &pszTextA;
3508 size_t *pcchText = (fAlternateBuffer) ? &cchTextB : &cchTextA;
3510 for (size_t cchRequired = 256; ; )
3512 if (!*pcchText || (*pcchText < cchRequired))
3516 if ((*ppszText = (LPTSTR)Allocate (sizeof(TCHAR)*(1+cchRequired))) == NULL)
3519 *pcchText = cchRequired;
3524 *(*ppszText) = TEXT('\0');
3525 if (!FastList_Notify_GetItemText (pfl, hItem, icol, *ppszText, *pcchText, &cchRequired))
3527 if (cchRequired <= *pcchText)
3531 return (*ppszText) ? (*ppszText) : TEXT("");
3535 void FastList_PerformSort (LPFASTLIST pfl)
3537 pfl->fSortBeforePaint = FALSE;
3539 // Sorting would be easy, except that we have to handle the tree case.
3540 // For a tree, "sorting" means ordering *sibling* items--we make no
3541 // attempt to order cousins, but all the children under a given parent
3542 // must be sorted. We don't sort the Visible heap directly--instead,
3543 // we sort the hashlist of items, and correct the Visible heap to match.
3544 // That way, the user can later expand/collapse items in the tree
3545 // without our having to re-sort.
3547 // In sorting the hashlist items, we're not so much interested in their
3548 // order of enumeration as we're interested in pointing each object's
3549 // {hPrevious} and {hNext} pointers to the right objects. (When sorting
3550 // a tree, this is even more clear; hPrevious and hNext point only to
3551 // siblings.) To perform a sort on these items, we must generate an
3552 // array of objects, qsort the array, then update the items' pointers.
3553 // That array of objects is in {fg}, the fastlist global structure.
3555 // The flow of sorting a list is:
3556 // 1- fill an array with HLISTITEM pointers for all items in the list
3557 // 2- qsort the array, using the {pfl->fnSort} comparison function
3558 // 3- update the HLISTITEMs' {hPrevious}, {hNext}, and {index} members
3559 // 4- call FastList_Update to fix the hash on the revised {index} members
3561 // The flow for sorting a tree is more complex:
3562 // 1- set indexNext = 0
3563 // 2- call SortLevel(NULL), to specify that we're sorting root items)
3564 // SortLevel(hParent):
3565 // 3- fill an array with HLISTITEM pointers for this item and siblings
3566 // 4- qsort the array, using the {pfl->fnSort} comparison function
3567 // 5- update the HLISTITEMs' {hPrevious}, {hNext} members
3568 // 6- use {indexNext++} to assign index values to all visible items
3569 // 7- if hParent->hTreeChild, call SortLevel(hParent->hTreeChild)
3570 // 8- call FastList_Update to fix the hash on the revised {index} members
3572 FastList_Begin (pfl->hList);
3575 if ((cItems = pfl->lItems->GetCount()) != 0)
3577 if (OpenGlobalArray (cItems))
3580 FastList_PerformSortLevel (pfl, NULL, ((pfl->dwStyle & FLS_VIEW_TREE) == FLS_VIEW_TREE));
3586 pfl->fSyncIndicesBeforePaint = TRUE;
3587 FastList_End (pfl->hList);
3591 void FastList_PerformSortLevel (LPFASTLIST pfl, HLISTITEM hParent, BOOL fTreeSort)
3593 // Find the first item in the chain that we're going to sort.
3594 // Then walk that chain, filling in the global array of HLISTITEMs
3595 // If we're sorting the thing as a tree, only add {hItem}'s siblings
3596 // to the fg.aObjects[] array; if we're sorting as a list, add
3597 // all items. Add items regardless of whether they're invisible.
3599 size_t cObjectsToSort = 0;
3603 for (HLISTITEM hItem = (hParent) ? hParent->hTreeChild : pfl->hTreeFirst; hItem; hItem = hItem->hTreeNext)
3604 fg.aObjects[ cObjectsToSort++ ] = hItem;
3606 else // Viewing by list, so sort items as if there were no tree structure
3608 for (HLISTITEM hItem = pfl->hListFirst; hItem; hItem = hItem->hListNext)
3609 fg.aObjects[ cObjectsToSort++ ] = hItem;
3612 if (cObjectsToSort != 0)
3614 // Perform a qsort on the array
3616 FastList_SortFunction (0, 0);
3617 qsort (fg.aObjects, cObjectsToSort, sizeof(HLISTITEM), FastList_SortFunction);
3619 // Walk the array, adjusting objects' next/previous pointers.
3623 HLISTITEM hTreePrevious = NULL;
3624 for (size_t iObject = 0; iObject < cObjectsToSort; ++iObject)
3626 fg.aObjects[ iObject ]->hTreePrevious = hTreePrevious;
3627 fg.aObjects[ iObject ]->hTreeNext = (iObject < cObjectsToSort-1) ? fg.aObjects[ iObject+1 ] : NULL;
3628 hTreePrevious = fg.aObjects[ iObject ];
3630 if (hParent == NULL)
3631 pfl->hTreeFirst = fg.aObjects[0];
3633 hParent->hTreeChild = fg.aObjects[0];
3635 else // (!(pfl->dwStyle & FLS_VIEW_TREE))
3637 HLISTITEM hListPrevious = NULL;
3638 for (size_t iObject = 0; iObject < cObjectsToSort; ++iObject)
3640 fg.aObjects[ iObject ]->hListPrevious = hListPrevious;
3641 fg.aObjects[ iObject ]->hListNext = (iObject < cObjectsToSort-1) ? fg.aObjects[ iObject+1 ] : NULL;
3642 hListPrevious = fg.aObjects[ iObject ];
3644 pfl->hListFirst = fg.aObjects[0];
3647 // If this is to be a treesort, walk the chain ascending children
3648 // recursively as we come to them.
3652 for (HLISTITEM hWalk = fg.aObjects[0]; hWalk; hWalk = hWalk->hTreeNext)
3654 if (hWalk && hWalk->hTreeChild)
3655 FastList_PerformSortLevel (pfl, hWalk, fTreeSort);
3662 int __cdecl FastList_SortFunction (const void *lp1, const void *lp2)
3664 if (fg.pfl->pfnSort)
3665 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));
3667 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));
3671 void FastList_RepairOneVisibilityFlag (LPFASTLIST pfl, HLISTITEM hItem)
3673 // There are two reasons to hide an item: because we're in tree mode
3674 // and one of its parent is collapsed, or because we're not in tree mode
3675 // and it has the only-show-me-in-tree-mode flag set.
3677 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE) ? TRUE : FALSE;
3679 hItem->fVisible = TRUE;
3681 if ((hItem->dwFlags & FLIF_TREEVIEW_ONLY) && (!fTreeMode))
3683 hItem->fVisible = FALSE;
3687 for (HLISTITEM hParent = hItem->hTreeParent; hParent; hParent = hParent->hTreeParent)
3689 if ((!hParent->fVisible) || (!hParent->fExpanded))
3691 hItem->fVisible = FALSE;
3699 void FastList_RepairVisibilityFlags (LPFASTLIST pfl, HLISTITEM hParent, BOOL fForceHidden)
3701 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE) ? TRUE : FALSE;
3703 // This routine fixes the {fVisible} flags for all items, based on
3704 // their FLIF_TREEVIEW_ONLY flags and whether their parent items are
3707 // Technically we could acheive this by a normal FindFirst()/FindNext()
3708 // enumeration of the items in the hashlist; on each item, we'd check
3709 // its parents and flags. But we can be a smidgen faster by walking
3710 // the list in tree order--that way, when we hit a collapsed tree, we
3711 // can mark all its children as hidden without any additional work.
3713 // Naturally, since we're a FASTlist, we'll take any little smidgen of
3714 // speed we can get. Find the first item in the chain that we're going
3717 for (HLISTITEM hItem = (hParent) ? hParent->hTreeChild : pfl->hTreeFirst; hItem; hItem = hItem->hTreeNext)
3719 // If we were passed {fForceHidden==TRUE}, we know that we're in tree
3720 // mode and one of our parents is collapsed--that's great, because it
3721 // means we can set fVisible=FALSE without thinking. If we weren't passed
3722 // that flag, we know that we're either not in treeview mode or none
3723 // of our parents are collapsed--so we don't have to walk up the
3724 // list of parents to check that.
3727 hItem->fVisible = FALSE;
3729 hItem->fVisible = fTreeMode || !(hItem->dwFlags & FLIF_TREEVIEW_ONLY);
3731 // We've fixed this item. If it has any children, fix them too.
3732 // Remember that we may be able to blindly tell children to be hidden.
3734 if (hItem->hTreeChild)
3736 BOOL fChildrenHidden = fForceHidden;
3737 if (fTreeMode && (!hItem->fExpanded || !hItem->fVisible))
3738 fChildrenHidden = TRUE;
3740 FastList_RepairVisibilityFlags (pfl, hItem, fChildrenHidden);
3746 void FastList_RepairVisibilityIndices (LPFASTLIST pfl, HLISTITEM hParent)
3748 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE) ? TRUE : FALSE;
3750 if (hParent == NULL) // Starting a new repair? Initialize pfl->cVisible.
3753 pfl->fSyncIndicesBeforePaint = FALSE;
3756 // This routine fixes the {index} settings for all items, by walking
3757 // the list/tree in (presumably already-sorted) order and making
3758 // sure all items with {fVisible} set have smoothly increasing indices.
3759 // It rebuilds the Visible heap as it goes along.
3761 for (HLISTITEM hItem = (!fTreeMode) ? (pfl->hListFirst) : (hParent) ? (hParent->hTreeChild) : (pfl->hTreeFirst);
3763 hItem = (!fTreeMode) ? (hItem->hListNext) : (hItem->hTreeNext))
3765 if (hItem->fVisible)
3767 hItem->index = pfl->cVisible;
3769 // Update the aVisibleHeap to match the new item.
3771 REALLOC (pfl->aVisibleHeap, pfl->cVisibleHeap, 1+ hItem->index, cREALLOC_VISIBLEHEAP(pfl));
3772 pfl->aVisibleHeap[ hItem->index ] = hItem;
3776 if (fTreeMode && hItem->hTreeChild)
3778 FastList_RepairVisibilityIndices (pfl, hItem);
3784 void FastList_ScrollHeader (LPFASTLIST pfl)
3789 GetWindowRect (pfl->hHeader, &rHeader);
3791 LONG cx = rHeader.right + pfl->dxPixel;
3793 SetWindowPos (pfl->hHeader, 0,
3794 0 - pfl->dxPixel, 0, cx, cyRECT(rHeader),
3795 SWP_NOZORDER | SWP_NOACTIVATE);
3800 void FastList_PerformSelectTest (LPFASTLIST pfl, HLISTITEM hItem)
3802 if (pfl->hSelectFirst && !hItem->fSelected)
3804 BOOL fMultiple = (pfl->dwStyle & FLS_SELECTION_MULTIPLE);
3805 BOOL fTreeMode = (pfl->dwStyle & FLS_VIEW_TREE);
3806 BOOL fLevel = (pfl->dwStyle & (FLS_SELECTION_LEVEL & ~FLS_SELECTION_MULTIPLE));
3807 BOOL fSibling = (pfl->dwStyle & (FLS_SELECTION_SIBLING & ~FLS_SELECTION_MULTIPLE));
3809 BOOL fClearSelection = FALSE;
3813 fClearSelection = TRUE;
3819 size_t iLevelItem = 0;
3820 for (HLISTITEM hParent = hItem->hTreeParent; hParent; hParent = hParent->hTreeParent)
3823 size_t iLevelSelected = 0;
3824 for (hParent = pfl->hSelectFirst->hTreeParent; hParent; hParent = hParent->hTreeParent)
3827 if (iLevelItem != iLevelSelected)
3828 fClearSelection = TRUE;
3833 BOOL fFound = FALSE;
3834 for (HLISTITEM hSearch = hItem->hTreePrevious; !fFound && hSearch; hSearch = hSearch->hTreePrevious)
3836 if (hSearch == pfl->hSelectFirst)
3839 for (hSearch = hItem->hTreeNext; !fFound && hSearch; hSearch = hSearch->hTreeNext)
3841 if (hSearch == pfl->hSelectFirst)
3845 fClearSelection = TRUE;
3849 if (fClearSelection)
3851 FastList_OnCommand_SelectItem (pfl->hList, NULL, FALSE);
3857 void FastList_PerformSelectItem (LPFASTLIST pfl, HLISTITEM hItem, BOOL fSelect)
3859 if (hItem->fSelected != fSelect)
3861 if ((hItem->fSelected = fSelect) == FALSE)
3863 if (hItem->hSelectPrevious)
3864 hItem->hSelectPrevious->hSelectNext = hItem->hSelectNext;
3865 if (hItem->hSelectNext)
3866 hItem->hSelectNext->hSelectPrevious = hItem->hSelectPrevious;
3867 if (pfl->hSelectFirst == hItem)
3868 pfl->hSelectFirst = hItem->hSelectNext;
3869 if (pfl->hAnchor == hItem)
3870 pfl->hAnchor = NULL;
3871 hItem->hSelectPrevious = NULL;
3872 hItem->hSelectNext = NULL;
3874 else // (hItem->fSelected == TRUE)
3876 if ((hItem->hSelectNext = pfl->hSelectFirst) != NULL)
3877 hItem->hSelectNext->hSelectPrevious = hItem;
3878 pfl->hSelectFirst = hItem;
3879 if (hItem->hSelectNext == NULL)
3880 pfl->hAnchor = hItem;
3883 FastList_Notify_ItemChanged (pfl, hItem);
3884 FastList_Repaint (pfl);
3889 void FastList_PerformSelectRange (LPFASTLIST pfl, HLISTITEM hItem1, HLISTITEM hItem2)
3891 if (hItem1->fVisible && hItem2->fVisible)
3893 FastList_Begin (pfl->hList);
3895 int iIndex1 = min (hItem1->index, hItem2->index);
3896 int iIndex2 = max (hItem1->index, hItem2->index);
3897 for (int iIndex = iIndex1; iIndex <= iIndex2; ++iIndex)
3898 FastList_SelectItem (pfl->hList, pfl->aVisibleHeap[ iIndex ], TRUE);
3900 FastList_Repaint (pfl);
3901 FastList_End (pfl->hList);
3906 void FastList_PerformEnsureVisible (LPFASTLIST pfl)
3908 if (pfl->hEnsureVisible && pfl->lItems->fIsInList (pfl->hEnsureVisible))
3911 GetClientRect (pfl->hList, &rClient);
3913 rClient.right -= GetSystemMetrics(SM_CXVSCROLL);
3915 rClient.bottom -= GetSystemMetrics(SM_CYHSCROLL);
3917 rClient.top += FastList_GetHeaderHeight (pfl);
3920 FastList_CalcItemRect (pfl, pfl->hEnsureVisible->index, &rItem, !!pfl->hScrollH, !!pfl->hScrollV);
3922 if (rItem.right > (cxRECT(rClient) + pfl->dxPixel))
3923 pfl->dxPixel = rItem.right - cxRECT(rClient);
3924 if (rItem.left < pfl->dxPixel)
3925 pfl->dxPixel = rItem.left;
3926 if (rItem.bottom > (pfl->dyPixel + rClient.bottom))
3927 pfl->dyPixel = rItem.bottom - rClient.bottom;
3928 if (rItem.top < (pfl->dyPixel + rClient.top))
3929 pfl->dyPixel = rItem.top - rClient.top;
3931 pfl->hEnsureVisible = NULL;
3932 FastList_SyncScrollPos (pfl);
3937 void FastList_ButtonDown (HWND hList, BOOL fRightButton, BOOL fActivate)
3939 if (GetParent (hList))
3940 PostMessage (GetParent(hList), WM_NEXTDLGCTL, (WPARAM)hList, TRUE);
3945 if ((pfl = GetFastList (hList)) != NULL)
3948 // The rules for selection are somewhat complex; they follow the
3949 // conventions used by the Windows shell:
3951 // * if the user button-downs on the open/close box of a treeview item,
3952 // expand or collapse that item, and perform no further processing.
3954 // * if the user button-downs on an item,
3955 // and if that item is not selected, then:
3956 // - if the Control is not down, deselect all items
3957 // - if the Shift key is down, select all items between the Anchor
3958 // and the clicked-on item
3959 // - if the Shift key is not down, select (and anchor on) the item
3961 // * if the user button-downs and subsequently moves the mouse enough to
3962 // indicate a drag operation prior to the next button-up,
3963 // notify the parent window.
3965 // * if the user double-clicked, treat it as a button-down followed
3966 // immediately thereafter by a button-up
3968 // * if the user button-ups without having triggered a drag operation,
3969 // - if the user had button-downed on an already-selected item,
3970 // de-select that item
3972 // * if the user button-ups after having triggered a drag operation,
3973 // notify the parent window.
3975 // Here, the user has just button-downed, either as part of a single-click
3976 // or a double-click. We therefore will attempt the initial selection
3977 // process, store the screen coordinates at which the user clicked, and
3978 // set capture onto this list window that we may look for drag operations.
3980 // First find out where the user button-downed.
3982 DWORD dwPos = GetMessagePos();
3985 ptScreen.x = LOWORD(dwPos);
3986 ptScreen.y = HIWORD(dwPos);
3988 POINT ptClient = ptScreen;
3989 ScreenToClient (hList, &ptClient);
3991 // Determine what item is underneath the given point; also determine
3992 // the region of the item which was clicked.
3994 HLISTITEM hStrict = NULL;
3995 HLISTITEM hNonStrict = NULL;
3996 FASTLISTITEMREGIONS regNonStrict;
3997 if ((hStrict = FastList_ItemFromPoint (hList, &ptClient, TRUE)) == NULL)
3999 if ((hNonStrict = FastList_ItemFromPoint (hList, &ptClient, FALSE)) != NULL)
4000 FastList_GetItemRegions (hList, hNonStrict, ®NonStrict);
4003 // If the user has clicked on the open/close button of an item, expand
4004 // or collapse that item.
4006 FastList_Begin (hList);
4008 if ( (!hStrict) && (hNonStrict) && (PtInRect (®NonStrict.rButton, ptClient)) )
4010 FastList_OnCommand_Expand (hList, hNonStrict, !hNonStrict->fExpanded);
4011 FastList_Notify_ItemExpand (pfl, hNonStrict);
4012 FastList_End (hList);
4016 // If the user failed to click on any item at all, and if the control
4017 // key is not down, de-select all items. Regardless, return thereafter.
4021 if (!fIsControlDown())
4022 FastList_SelectNone (hList);
4023 FastList_SetFocus (hList,NULL);
4024 FastList_End (hList);
4025 FastList_Notify_ItemSelect (pfl);
4029 // If the user has double-clicked on an item, and that item is a parent
4030 // of other item, and if the tree is showing, expand or collapse that item.
4032 if (fActivate && hStrict->hTreeChild && (pfl->dwStyle & FLS_VIEW_TREE))
4034 FastList_OnCommand_Expand (hList, hStrict, !hStrict->fExpanded);
4035 FastList_End (hList);
4039 // The user has clicked on an item. Record what we know about what
4040 // the user has done, and apply message capturing to the list.
4042 pfl->fButtonDown = TRUE;
4043 pfl->fRightDrag = fRightButton;
4044 pfl->fDragging = FALSE;
4045 pfl->fTriedToDrag = FALSE;
4046 pfl->ptScreenDown = ptScreen;
4047 pfl->hHitOnDown = hStrict;
4048 pfl->fSelectedOnDown = hStrict->fSelected;
4051 // There are eight states about which we need to concern ourselves:
4053 // Control: Down (C) or Not Down (c)
4054 // Shift: Down (S) or Not Down (s)
4055 // Item: Selected (I) or Not Selected (i)
4057 // csi: de-select all items, anchor and select the specified item
4058 // csI: de-select all items, anchor and select the specified item
4059 // cSi: de-select all items, select from the anchor to the specified item
4060 // cSI: de-select all items, select from the anchor to the specified item
4061 // Csi: anchor and select the specified item
4062 // CsI: anchor and select the specified item
4063 // CSi: select from the anchor to the specified item
4064 // CSI: select from the anchor to the specified item
4066 // From this we can deduce the following rules:
4068 // if Control is not down, begin by de-selecting all items
4069 // if Shift is not down, anchor and select the specified item
4070 // if Shift is down, select from the anchor to the specified item
4072 HLISTITEM hAnchor = pfl->hAnchor;
4073 if (!fIsControlDown())
4075 FastList_SelectNone (hList);
4077 if (!fIsShiftDown() || !hAnchor)
4079 FastList_SelectItem (hList, hStrict, TRUE);
4080 pfl->hAnchor = hStrict;
4082 if (fIsShiftDown() && hAnchor)
4084 FastList_PerformSelectRange (pfl, hAnchor, hStrict);
4085 if (hAnchor->fSelected)
4086 pfl->hAnchor = hAnchor;
4089 // Finally, place the focus on the clicked-on item, and return.
4090 // We will complete the selection/dragging operation on mouseup.
4092 FastList_SetFocus (hList, hStrict);
4093 FastList_End (hList);
4094 FastList_Notify_ItemSelect (pfl);
4099 void FastList_MouseMove (HWND hList)
4102 if ((pfl = GetFastList (hList)) != NULL)
4104 // If there is no possibility that the user may be dragging something,
4105 // ignore the message.
4107 if (!pfl->fButtonDown)
4110 // If the user has triggered a drag operation, notify the parent.
4112 if ((!pfl->fTriedToDrag) || (pfl->fDragging))
4114 DWORD dwCode = (pfl->fDragging) ? FLN_DRAG : FLN_BEGINDRAG;
4115 DWORD dwPos = GetMessagePos();
4118 ptScreenTo.x = LOWORD(dwPos);
4119 ptScreenTo.y = HIWORD(dwPos);
4121 if (!pfl->fTriedToDrag)
4123 if ( (abs(ptScreenTo.x - pfl->ptScreenDown.x) >= GetSystemMetrics(SM_CXDRAG)) ||
4124 (abs(ptScreenTo.y - pfl->ptScreenDown.y) >= GetSystemMetrics(SM_CYDRAG)) )
4126 pfl->fTriedToDrag = TRUE;
4129 if (pfl->fTriedToDrag)
4131 FLN_DRAG_PARAMS fln;
4132 fln.hFirst = pfl->hSelectFirst;
4133 fln.ptScreenFrom = pfl->ptScreenDown;
4134 fln.ptScreenTo = ptScreenTo;
4135 fln.fRightButton = pfl->fRightDrag;
4136 fln.fShift = fIsShiftDown();
4137 fln.fControl = fIsControlDown();
4138 if ( (FastList_Notify_Drag (pfl, dwCode, &fln)) && (dwCode == FLN_BEGINDRAG) )
4139 pfl->fDragging = TRUE;
4146 void FastList_ButtonUp (HWND hList, BOOL fRightButton, BOOL fActivate)
4149 if ((pfl = GetFastList (hList)) != NULL)
4151 // First, our caller may have just notified us that a double-click
4152 // took place; if so, we may have already handled it (in the ButtonDown)
4153 // routine. Or, moreover, if we never got a button-down at all,
4154 // there's nothing for us to do here.
4156 if (!pfl->fButtonDown)
4158 if (pfl->fRightDrag != fRightButton)
4161 // Release capture; we no longer need it.
4163 pfl->fButtonDown = FALSE;
4166 // If the user right-button-ups without having triggered a drag operation,
4167 // send a WM_CONTEXTMENU message.
4169 if ( (!pfl->fTriedToDrag) && (fRightButton) )
4171 if (GetParent (hList))
4173 PostMessage (GetParent (hList), WM_CONTEXTMENU, (WPARAM)hList, (LPARAM)GetMessagePos());
4177 // If the user button-ups without having triggered a drag operation,
4178 // and if the user had button-downed on an already-selected item,
4179 // de-select that item.
4181 if ( (!pfl->fTriedToDrag) && (pfl->hHitOnDown) && (pfl->fSelectedOnDown) && (fIsControlDown()) )
4183 FastList_SelectItem (hList, pfl->hHitOnDown, FALSE);
4184 FastList_Notify_ItemSelect (pfl);
4188 // If the user button-ups after triggering a drag operation, notify
4193 DWORD dwPos = GetMessagePos();
4196 ptScreenTo.x = LOWORD(dwPos);
4197 ptScreenTo.y = HIWORD(dwPos);
4199 FLN_DRAG_PARAMS fln;
4200 fln.hFirst = pfl->hSelectFirst;
4201 fln.ptScreenFrom = pfl->ptScreenDown;
4202 fln.ptScreenTo = ptScreenTo;
4203 fln.fRightButton = pfl->fRightDrag;
4204 fln.fShift = fIsShiftDown();
4205 fln.fControl = fIsControlDown();
4206 FastList_Notify_Drag (pfl, FLN_ENDDRAG, &fln);
4213 * UTILITY FUNCTIONS __________________________________________________________
4217 LPFASTLIST GetFastList (HWND hList)
4221 if ((pfl = (LPFASTLIST)GetWindowLong (hList, 0))->dwSig != dwSigFASTLIST)
4223 else if (pfl->hList != hList)
4232 BOOL fIsFastList (HWND hList)
4234 return (GetFastList (hList)) ? TRUE : FALSE;
4238 void FastList_Enter (HWND hList)
4241 if ((pfl = GetFastList (hList)) != NULL)
4243 EnterCriticalSection (&pfl->cs);
4248 void FastList_Leave (HWND hList)
4251 if ((pfl = GetFastList (hList)) != NULL)
4253 LeaveCriticalSection (&pfl->cs);
4258 int CALLBACK FastList_SortFunc_AlphaNumeric (HWND hList, HLISTITEM hItem1, LPARAM lpItem1, HLISTITEM hItem2, LPARAM lpItem2)
4261 if ((pfl = GetFastList (hList)) == NULL)
4264 if (!hItem1 || !hItem2)
4267 LPTSTR pszText1 = FastList_GetColumnText (pfl, hItem1, pfl->iColSort, FALSE);
4268 LPTSTR pszText2 = FastList_GetColumnText (pfl, hItem2, pfl->iColSort, TRUE);
4270 if ( (pfl->iColSort < (int)pfl->cColumns) &&
4271 (pfl->aColumns[ pfl->iColSort ].pszText != NULL) &&
4272 ((pfl->aColumns[ pfl->iColSort ].fmt & HDF_JUSTIFYMASK) == HDF_RIGHT) )
4274 double dItem1 = atof (pszText1);
4275 double dItem2 = atof (pszText2);
4278 return (dItem1 < dItem2) ? 1 : (dItem1 > dItem2) ? -1 : 0;
4280 return (dItem1 < dItem2) ? -1 : (dItem1 > dItem2) ? 1 : 0;
4282 else // left- or center- justified; use an alphabetic sort
4285 return lstrcmpi (pszText2, pszText1);
4287 return lstrcmpi (pszText1, pszText2);
4292 int CALLBACK FastList_SortFunc_Alphabetic (HWND hList, HLISTITEM hItem1, LPARAM lpItem1, HLISTITEM hItem2, LPARAM lpItem2)
4295 if ((pfl = GetFastList (hList)) == NULL)
4298 if (!hItem1 || !hItem2)
4301 LPTSTR pszText1 = FastList_GetColumnText (pfl, hItem1, pfl->iColSort, FALSE);
4302 LPTSTR pszText2 = FastList_GetColumnText (pfl, hItem2, pfl->iColSort, TRUE);
4305 return lstrcmpi (pszText2, pszText1);
4307 return lstrcmpi (pszText1, pszText2);
4311 int CALLBACK FastList_SortFunc_Numeric (HWND hList, HLISTITEM hItem1, LPARAM lpItem1, HLISTITEM hItem2, LPARAM lpItem2)
4314 if ((pfl = GetFastList (hList)) == NULL)
4317 if (!hItem1 || !hItem2)
4320 LPTSTR pszText1 = FastList_GetColumnText (pfl, hItem1, pfl->iColSort, FALSE);
4321 LPTSTR pszText2 = FastList_GetColumnText (pfl, hItem2, pfl->iColSort, TRUE);
4323 double dItem1 = atof (pszText1);
4324 double dItem2 = atof (pszText2);
4327 return (dItem1 < dItem2) ? 1 : (dItem1 > dItem2) ? -1 : 0;
4329 return (dItem1 < dItem2) ? -1 : (dItem1 > dItem2) ? 1 : 0;
4334 * HASHLIST KEYS ______________________________________________________________
4338 BOOL CALLBACK FastList_KeyUserParam_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData)
4340 return (((HLISTITEM)pObject)->lpUser == *(LPARAM*)pData) ? TRUE : FALSE;
4343 HASHVALUE CALLBACK FastList_KeyUserParam_HashObject (LPHASHLISTKEY pKey, PVOID pObject)
4345 return FastList_KeyUserParam_HashData (pKey, &((HLISTITEM)pObject)->lpUser);
4348 HASHVALUE CALLBACK FastList_KeyUserParam_HashData (LPHASHLISTKEY pKey, PVOID pData)
4350 return (HASHVALUE)*(LPARAM*)pData;