ntmakefile-clean-20040401
[openafs.git] / src / WINNT / afsapplib / checklist.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
13 }
14
15 #include <windows.h>
16 #include <windowsx.h>
17 #include <commctrl.h>
18 #include <WINNT/TaLocale.h>
19 #include <WINNT/subclass.h>
20 #include <WINNT/checklist.h>
21
22
23 /*
24  * DEFINITIONS ________________________________________________________________
25  *
26  */
27
28 #define cxCHECKBOX        (2+9+2)
29 #define cyCHECKBOX        (2+9+2)
30
31 #define cxAFTER_CHECKBOX  4
32
33
34 #define LB_GETHIT     (WM_USER+298)
35 #define LB_SETHIT     (WM_USER+299)   // int iItem=wp
36
37 /*
38  * int LB_GetHit (HWND hList)
39  * void LB_SetHit (HWND hList, int iItem)
40  *
41  */
42 #define LB_GetHit(_hList) \
43         SendMessage(_hList,LB_GETHIT,(WPARAM)0,(LPARAM)0)
44 #define LB_SetHit(_hList,_ii) \
45         SendMessage(_hList,LB_SETHIT,(WPARAM)_ii,(LPARAM)0)
46
47
48 /*
49  * VARIABLES __________________________________________________________________
50  *
51  */
52
53 LONG procListbox = 0;
54
55 /*
56  * PROTOTYPES _________________________________________________________________
57  *
58  */
59
60 BOOL CALLBACK CheckListProc (HWND hList, UINT msg, WPARAM wp, LPARAM lp);
61
62 BOOL CALLBACK CheckList_DialogProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp);
63
64 void CheckList_OnDrawItem (HWND hList, int id, LPDRAWITEMSTRUCT lpds);
65 void CheckList_OnDrawCheckbox (HWND hList, int id, LPDRAWITEMSTRUCT lpds);
66 void CheckList_OnDrawText (HWND hList, int id, LPDRAWITEMSTRUCT lpds);
67
68 BOOL CheckList_OnHitTest (HWND hList, int id);
69
70 BOOL CheckList_OnGetHit   (HWND hList, WPARAM wp, LPARAM lp);
71 BOOL CheckList_OnSetHit   (HWND hList, WPARAM wp, LPARAM lp);
72 BOOL CheckList_OnGetCheck (HWND hList, WPARAM wp, LPARAM lp);
73 BOOL CheckList_OnSetCheck (HWND hList, WPARAM wp, LPARAM lp);
74
75 void CheckList_OnButtonDown (HWND hList);
76 void CheckList_OnButtonUp (HWND hList);
77 void CheckList_OnDoubleClick (HWND hList);
78 void CheckList_OnMouseMove (HWND hList);
79
80 void CheckList_OnSetCheck_Selected (HWND hList, BOOL fCheck);
81
82 void CheckList_RedrawCheck (HWND hList, int ii);
83
84
85 /*
86  * ROUTINES ___________________________________________________________________
87  *
88  */
89
90 #ifndef REALLOC
91 #define REALLOC(_a,_c,_r,_i) CheckListReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
92 BOOL CheckListReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
93 {
94    LPVOID pNew;
95    size_t cNew;
96
97    if (cReq <= *pcTarget)
98       return TRUE;
99
100    if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
101       return FALSE;
102
103    if ((pNew = Allocate (cbElement * cNew)) == NULL)
104       return FALSE;
105    memset (pNew, 0x00, cbElement * cNew);
106
107    if (*pcTarget != 0)
108       {
109       memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
110       Free (*ppTarget);
111       }
112
113    *ppTarget = pNew;
114    *pcTarget = cNew;
115    return TRUE;
116 }
117 #endif
118
119
120 BOOL RegisterCheckListClass (void)
121 {
122    static BOOL fRegistered = FALSE;
123
124    if (!fRegistered)
125       {
126       WNDCLASS wc;
127       GetClassInfo (THIS_HINST, TEXT("LISTBOX"), &wc);
128       procListbox = (LONG)wc.lpfnWndProc;
129
130       wc.style = CS_GLOBALCLASS;
131       wc.lpfnWndProc = (WNDPROC)CheckListProc;
132       wc.hInstance = THIS_HINST;
133       wc.hCursor = LoadCursor (NULL, MAKEINTRESOURCE (IDC_ARROW));
134       wc.hbrBackground = CreateSolidBrush (GetSysColor (COLOR_BTNFACE));
135       wc.lpszClassName = WC_CHECKLIST;
136
137       if (RegisterClass (&wc))
138          fRegistered = TRUE;
139       }
140
141    return fRegistered;
142 }
143
144
145 BOOL IsCheckList (HWND hList)
146 {
147    TCHAR szClassName[256];
148    if (!GetClassName (hList, szClassName, 256))
149       return FALSE;
150
151    if (lstrcmp (szClassName, WC_CHECKLIST))
152       return FALSE;
153
154    return TRUE;
155 }
156
157
158 BOOL CALLBACK CheckListProc (HWND hList, UINT msg, WPARAM wp, LPARAM lp)
159 {
160    switch (msg)
161       {
162       case WM_CREATE:
163          Subclass_AddHook (GetParent(hList), CheckList_DialogProc);
164          LB_SetHit (hList, -1);
165          break;
166
167       case WM_DESTROY:
168          Subclass_RemoveHook (GetParent(hList), CheckList_DialogProc);
169          break;
170
171       case WM_ENABLE:
172          RECT rClient;
173          GetClientRect (GetParent(hList), &rClient);
174          InvalidateRect (GetParent(hList), &rClient, FALSE);
175          UpdateWindow (GetParent(hList));
176          break;
177
178       case WM_LBUTTONDOWN:
179          CheckList_OnButtonDown (hList);
180          if (GetCapture() == hList)
181             {
182             if (procListbox)
183                {
184                ReleaseCapture ();
185                CallWindowProc ((WNDPROC)procListbox, hList, WM_LBUTTONDOWN, wp, lp);
186                CallWindowProc ((WNDPROC)procListbox, hList, WM_LBUTTONUP, wp, lp);
187                SetCapture (hList);
188                }
189             return TRUE;
190             }
191          break;
192
193       case WM_LBUTTONUP:
194          CheckList_OnButtonUp (hList);
195          break;
196
197       case WM_LBUTTONDBLCLK:
198          CheckList_OnDoubleClick (hList);
199          break;
200
201       case WM_MOUSEMOVE:
202          CheckList_OnMouseMove (hList);
203          break;
204
205       case LB_GETHIT:
206          return CheckList_OnGetHit (hList, wp, lp);
207
208       case LB_SETHIT:
209          return CheckList_OnSetHit (hList, wp, lp);
210
211       case LB_GETCHECK:
212          return CheckList_OnGetCheck (hList, wp, lp);
213
214       case LB_SETCHECK:
215          return CheckList_OnSetCheck (hList, wp, lp);
216       }
217
218    if (procListbox)
219       return CallWindowProc ((WNDPROC)procListbox, hList, msg, wp, lp);
220    else
221       return DefWindowProc (hList, msg, wp, lp);
222 }
223
224
225 BOOL CALLBACK CheckList_DialogProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
226 {
227    PVOID procOld = Subclass_FindNextHook (hDlg, CheckList_DialogProc);
228
229    switch (msg)
230       {
231       case WM_MEASUREITEM:
232          LPMEASUREITEMSTRUCT lpms;
233          if ((lpms = (LPMEASUREITEMSTRUCT)lp) != NULL)
234             {
235             HDC hdc = GetDC (hDlg);
236             TEXTMETRIC tm;
237             GetTextMetrics (hdc, &tm);
238             ReleaseDC (hDlg, hdc);
239             lpms->itemHeight = max( tm.tmHeight, cyCHECKBOX );
240             return TRUE;
241             }
242          break;
243
244       case WM_DRAWITEM:
245          LPDRAWITEMSTRUCT lpds;
246          if ((lpds = (LPDRAWITEMSTRUCT)lp) != NULL)
247             {
248             CheckList_OnDrawItem (lpds->hwndItem, lpds->itemID, lpds);
249             return TRUE;
250             }
251          break;
252
253       case WM_CTLCOLORLISTBOX:
254          if (IsCheckList ((HWND)lp))
255             {
256             static COLORREF clrLast = (COLORREF)-1;
257             static HBRUSH hbrStatic = NULL;
258             COLORREF clrNew = GetSysColor (IsWindowEnabled((HWND)lp) ? COLOR_WINDOW : COLOR_BTNFACE);
259             if (clrNew != clrLast)
260                hbrStatic = CreateSolidBrush (clrLast = clrNew);
261             SetBkColor ((HDC)wp, clrLast);
262             return (BOOL)hbrStatic;
263             }
264          break;
265       }
266
267    if (procOld)
268       return CallWindowProc ((WNDPROC)procOld, hDlg, msg, wp, lp);
269    else
270       return FALSE;
271 }
272
273
274 void CheckList_OnDrawItem (HWND hList, int id, LPDRAWITEMSTRUCT lpds)
275 {
276    if (id >= 0)
277       {
278       CheckList_OnDrawCheckbox (hList, id, lpds);
279       CheckList_OnDrawText (hList, id, lpds);
280       }
281 }
282
283
284 void CheckList_OnDrawCheckbox (HWND hList, int id, LPDRAWITEMSTRUCT lpds)
285 {
286    // Step 1: erase around the checkbox.
287    //
288    COLORREF clrBack = GetSysColor (COLOR_WINDOW);
289    if (lpds->itemState & ODS_DISABLED)
290       clrBack = GetSysColor (COLOR_BTNFACE);
291
292    HBRUSH hbr = CreateSolidBrush (clrBack);
293
294    POINT ptCheckbox;
295    ptCheckbox.x = lpds->rcItem.left;
296    ptCheckbox.y = lpds->rcItem.top + ((lpds->rcItem.bottom - lpds->rcItem.top) - cyCHECKBOX) /2;
297
298    // step 1a: fill in above the checkbox
299    RECT rr;
300    rr.top    = lpds->rcItem.top;
301    rr.left   = lpds->rcItem.left;
302    rr.right  = lpds->rcItem.left + cxCHECKBOX;
303    rr.bottom = ptCheckbox.y;
304    FillRect (lpds->hDC, &rr, hbr);
305
306    // step 1b: fill in below the checkbox
307    rr.top = ptCheckbox.y + cyCHECKBOX;
308    rr.bottom = lpds->rcItem.bottom;
309    FillRect (lpds->hDC, &rr, hbr);
310
311    // step 1c: fill in to the right of the checkbox
312    rr.top = lpds->rcItem.top;
313    rr.left = lpds->rcItem.left + cxCHECKBOX;
314    rr.right = lpds->rcItem.left + cxCHECKBOX + cxAFTER_CHECKBOX;
315    rr.bottom = lpds->rcItem.bottom;
316    FillRect (lpds->hDC, &rr, hbr);
317
318    DeleteObject (hbr);
319
320    // Step 2: draw the checkbox itself
321    //
322    HPEN hpOld;
323    HPEN hpNew;
324
325    // step 2a: draw the btnshadow upper-left lines
326    hpNew = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNSHADOW));
327    hpOld = (HPEN)SelectObject (lpds->hDC, hpNew);
328    MoveToEx (lpds->hDC, ptCheckbox.x, ptCheckbox.y +cyCHECKBOX -2, NULL);
329    LineTo (lpds->hDC, ptCheckbox.x, ptCheckbox.y);
330    LineTo (lpds->hDC, ptCheckbox.x +cxCHECKBOX-1, ptCheckbox.y);
331    SelectObject (lpds->hDC, hpOld);
332    DeleteObject (hpNew);
333
334    // step 2b: draw the black upper-left lines
335    hpNew = CreatePen (PS_SOLID, 1, RGB(0,0,0));
336    hpOld = (HPEN)SelectObject (lpds->hDC, hpNew);
337    MoveToEx (lpds->hDC, ptCheckbox.x+1, ptCheckbox.y+cyCHECKBOX-3, NULL);
338    LineTo (lpds->hDC, ptCheckbox.x+1, ptCheckbox.y+1);
339    LineTo (lpds->hDC, ptCheckbox.x+cxCHECKBOX-2, ptCheckbox.y+1);
340    SelectObject (lpds->hDC, hpOld);
341    DeleteObject (hpNew);
342
343    // step 2c: draw the btnface lower-right lines
344    hpNew = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNFACE));
345    hpOld = (HPEN)SelectObject (lpds->hDC, hpNew);
346    MoveToEx (lpds->hDC, ptCheckbox.x+1, ptCheckbox.y+cyCHECKBOX-2, NULL);
347    LineTo (lpds->hDC, ptCheckbox.x+cxCHECKBOX-2, ptCheckbox.y+cyCHECKBOX-2);
348    LineTo (lpds->hDC, ptCheckbox.x+cxCHECKBOX-2, ptCheckbox.y);
349    SelectObject (lpds->hDC, hpOld);
350    DeleteObject (hpNew);
351
352    // step 2d: draw the btnhighlight lower-right lines
353    hpNew = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNHIGHLIGHT));
354    hpOld = (HPEN)SelectObject (lpds->hDC, hpNew);
355    MoveToEx (lpds->hDC, ptCheckbox.x, ptCheckbox.y+cyCHECKBOX-1, NULL);
356    LineTo (lpds->hDC, ptCheckbox.x+cxCHECKBOX-1, ptCheckbox.y+cyCHECKBOX-1);
357    LineTo (lpds->hDC, ptCheckbox.x+cxCHECKBOX-1, ptCheckbox.y-1);
358    SelectObject (lpds->hDC, hpOld);
359    DeleteObject (hpNew);
360
361    // step 2e: draw the background field
362    //
363    BOOL fHit = CheckList_OnHitTest (hList, id);
364    BOOL fChecked = LB_GetCheck (hList, id);
365
366    clrBack = GetSysColor (COLOR_WINDOW);
367    if ( (lpds->itemState & ODS_DISABLED) ||
368         (fHit && (LB_GetHit(hList) == id)))
369       {
370       clrBack = GetSysColor (COLOR_BTNFACE);
371       }
372
373    rr.top  = ptCheckbox.y +2;
374    rr.left  = ptCheckbox.x +2;
375    rr.right = ptCheckbox.x +cxCHECKBOX -2;
376    rr.bottom = ptCheckbox.y +cyCHECKBOX -2;
377
378    hbr = CreateSolidBrush (clrBack);
379    FillRect (lpds->hDC, &rr, hbr);
380    DeleteObject (hbr);
381
382    // step 2f: draw the checkmark (if appropriate)
383    //
384    if (fChecked)
385       {
386       hpNew = CreatePen (PS_SOLID, 1, (lpds->itemState & ODS_DISABLED) ? GetSysColor(COLOR_BTNSHADOW) : RGB(0,0,0));
387       hpOld = (HPEN)SelectObject (lpds->hDC, hpNew);
388
389       MoveToEx (lpds->hDC, ptCheckbox.x +3, ptCheckbox.y+5, NULL);
390       LineTo (lpds->hDC, ptCheckbox.x +5, ptCheckbox.y+7);
391       LineTo (lpds->hDC, ptCheckbox.x+10, ptCheckbox.y+2);
392
393       MoveToEx (lpds->hDC, ptCheckbox.x +3, ptCheckbox.y+6, NULL);
394       LineTo (lpds->hDC, ptCheckbox.x +5, ptCheckbox.y+8);
395       LineTo (lpds->hDC, ptCheckbox.x+10, ptCheckbox.y+3);
396
397       MoveToEx (lpds->hDC, ptCheckbox.x +3, ptCheckbox.y+7, NULL);
398       LineTo (lpds->hDC, ptCheckbox.x +5, ptCheckbox.y+9);
399       LineTo (lpds->hDC, ptCheckbox.x+10, ptCheckbox.y+4);
400
401       SelectObject (lpds->hDC, hpOld);
402       DeleteObject (hpNew);
403       }
404 }
405
406
407 void CheckList_OnDrawText (HWND hList, int id, LPDRAWITEMSTRUCT lpds)
408 {
409    // Step 1: erase around the text.
410    //
411    COLORREF clrBack = GetSysColor (COLOR_WINDOW);
412    COLORREF clrFore = GetSysColor (COLOR_WINDOWTEXT);
413    if (lpds->itemState & ODS_DISABLED)
414       {
415       clrBack = GetSysColor (COLOR_BTNFACE);
416       clrFore = GetSysColor (COLOR_GRAYTEXT);
417       }
418    else if (lpds->itemState & ODS_SELECTED)
419       {
420       clrBack = GetSysColor (COLOR_HIGHLIGHT);
421       clrFore = GetSysColor (COLOR_HIGHLIGHTTEXT);
422       }
423
424    HBRUSH hbr = CreateSolidBrush (clrBack);
425
426    // step 1a: find out how big the text is, and where it should go
427    // (remember to add a few spaces to the front, so there's a little bit
428    // of highlighted leading space before the text begins)
429    TCHAR szText[256] = TEXT(" ");
430    SendMessage (hList, LB_GETTEXT, (WPARAM)id, (LPARAM)&szText[lstrlen(szText)]);
431
432    SIZE sText;
433    GetTextExtentPoint (lpds->hDC, szText, lstrlen(szText), &sText);
434
435    POINT ptText;
436    ptText.x = lpds->rcItem.left + cxCHECKBOX + cxAFTER_CHECKBOX;
437    ptText.y = lpds->rcItem.top + ((lpds->rcItem.bottom - lpds->rcItem.top) - sText.cy) /2;
438
439    // step 1b: fill in above the text
440    RECT rr;
441    rr.top    = lpds->rcItem.top;
442    rr.left   = ptText.x;
443    rr.right  = lpds->rcItem.right;
444    rr.bottom = ptText.y;
445    FillRect (lpds->hDC, &rr, hbr);
446
447    // step 1c: fill in below the text
448    rr.top    = ptText.y;
449    rr.bottom = lpds->rcItem.bottom;
450    FillRect (lpds->hDC, &rr, hbr);
451
452    // step 1d: fill in to the right of the text
453    rr.top    = lpds->rcItem.top;
454    rr.left   = ptText.x + sText.cx;
455    rr.right  = lpds->rcItem.right;
456    rr.bottom = lpds->rcItem.bottom;
457    FillRect (lpds->hDC, &rr, hbr);
458
459    DeleteObject (hbr);
460
461    // Step 2: draw the text itself
462    //
463    rr.top    = ptText.y;
464    rr.left   = ptText.x;
465    rr.right  = ptText.x + sText.cx;
466    rr.bottom = ptText.y + sText.cy;
467
468    COLORREF clrBG = SetBkColor (lpds->hDC, clrBack);
469    COLORREF clrFG = SetTextColor (lpds->hDC, clrFore);
470
471    DRAWTEXTPARAMS Params;
472    memset (&Params, 0x00, sizeof(DRAWTEXTPARAMS));
473    Params.cbSize = sizeof(Params);
474    Params.iTabLength = 15;
475
476    SetBkMode (lpds->hDC, OPAQUE);
477    DrawTextEx (lpds->hDC, szText, -1, &rr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_EXPANDTABS | DT_NOPREFIX | DT_TABSTOP | DT_NOCLIP, &Params);
478
479    SetTextColor (lpds->hDC, clrFG);
480    SetBkColor (lpds->hDC, clrBG);
481
482    // Step 3: draw the focus rect (if appropriate)
483    //
484    if (lpds->itemState & ODS_FOCUS)
485       {
486       rr.top = lpds->rcItem.top;
487       rr.left = ptText.x;
488       rr.right = lpds->rcItem.right;
489       rr.bottom = lpds->rcItem.bottom;
490       DrawFocusRect (lpds->hDC, &rr);
491       }
492 }
493
494
495 BOOL CheckList_OnHitTest (HWND hList, int id)
496 {
497    RECT rr;
498    SendMessage (hList, LB_GETITEMRECT, (WPARAM)id, (LPARAM)&rr);
499    rr.right = rr.left + cxCHECKBOX;
500
501    DWORD dw = GetMessagePos();
502    POINT pt = { LOWORD(dw), HIWORD(dw) };
503    ScreenToClient (hList, &pt);
504
505    return PtInRect (&rr, pt);
506 }
507
508
509 BOOL CheckList_OnGetHit (HWND hList, WPARAM wp, LPARAM lp)
510 {
511    return (BOOL)GetWindowLong (hList, GWL_USERDATA);
512 }
513
514
515 BOOL CheckList_OnSetHit (HWND hList, WPARAM wp, LPARAM lp)
516 {
517    int iItem = (int)wp;
518    SetWindowLong (hList, GWL_USERDATA, iItem);
519    return TRUE;
520 }
521
522
523 BOOL CheckList_OnGetCheck (HWND hList, WPARAM wp, LPARAM lp)
524 {
525    int iItem = (int)wp;
526
527    return (BOOL)SendMessage (hList, LB_GETITEMDATA, (WPARAM)iItem, 0);
528 }
529
530
531 BOOL CheckList_OnSetCheck (HWND hList, WPARAM wp, LPARAM lp)
532 {
533    int iItem = (int)wp;
534    BOOL fCheck = (BOOL)lp;
535
536    SendMessage (hList, LB_SETITEMDATA, (WPARAM)iItem, (LPARAM)fCheck);
537
538    CheckList_RedrawCheck (hList, iItem);
539
540    return TRUE;
541 }
542
543
544 void CheckList_OnMouseMove (HWND hList)
545 {
546    if (GetCapture() == hList)
547       {
548       int ii = LB_GetHit (hList);
549       if (ii != -1)
550          {
551          CheckList_RedrawCheck (hList, ii);
552          }
553       }
554 }
555
556
557 void CheckList_OnButtonDown (HWND hList)
558 {
559    if (IsWindowEnabled (hList))
560       {
561       DWORD dw = GetMessagePos();
562       POINT pt = { LOWORD(dw), HIWORD(dw) };
563       ScreenToClient (hList, &pt);
564
565       int ii = SendMessage (hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x,pt.y));
566       if (HIWORD(ii) == 0)
567          {
568          BOOL fHit = CheckList_OnHitTest (hList, ii);
569          if (fHit)
570             {
571             SetCapture (hList);
572             LB_SetHit (hList, ii);
573
574             CheckList_RedrawCheck (hList, ii);
575             }
576          }
577       }
578 }
579
580
581 void CheckList_OnButtonUp (HWND hList)
582 {
583    if (GetCapture() == hList)
584       {
585       ReleaseCapture();
586
587       int ii = LB_GetHit (hList);
588       if (ii != -1)
589          {
590          LB_SetHit (hList, -1);
591
592          BOOL fHit = CheckList_OnHitTest (hList, ii);
593
594          if (!fHit)
595             CheckList_RedrawCheck (hList, ii);
596          else
597             {
598             BOOL fChecked = LB_GetCheck (hList, ii);
599             CheckList_OnSetCheck_Selected (hList, !fChecked);
600             }
601          }
602       }
603 }
604
605
606 void CheckList_OnDoubleClick (HWND hList)
607 {
608    if (IsWindowEnabled (hList))
609       {
610       DWORD dw = GetMessagePos();
611       POINT pt = { LOWORD(dw), HIWORD(dw) };
612       ScreenToClient (hList, &pt);
613
614       int ii = SendMessage (hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x,pt.y));
615       if (HIWORD(ii) == 0)
616          {
617          BOOL fChecked = LB_GetCheck (hList, ii);
618
619          CheckList_OnSetCheck_Selected (hList, !fChecked);
620          }
621       }
622 }
623
624
625 void CheckList_OnSetCheck_Selected (HWND hList, BOOL fCheck)
626 {
627    static int   *aSel = NULL;
628    static size_t cSel = 0;
629
630    if (GetWindowLong(hList,GWL_STYLE) & LBS_MULTIPLESEL)
631       {
632       size_t cReq = SendMessage(hList,LB_GETSELCOUNT,0,0);
633       if ((cReq) && (cReq != LB_ERR) && REALLOC(aSel,cSel,cReq,4))
634          {
635          size_t iMax = (size_t)SendMessage (hList, LB_GETSELITEMS, (WPARAM)cSel, (LPARAM)aSel);
636          if (iMax != LB_ERR)
637             {
638             for (size_t ii = 0; ii < iMax; ++ii)
639                {
640                LB_SetCheck (hList, aSel[ii], fCheck);
641                }
642             }
643          }
644       }
645    else // single-sel listbox
646       {
647       int ii = SendMessage (hList, LB_GETCURSEL, 0, 0);
648       if (ii != LB_ERR)
649          {
650          LB_SetCheck (hList, ii, fCheck);
651          }
652       }
653
654    SendMessage (GetParent(hList), WM_COMMAND, MAKELONG(GetWindowLong(hList,GWL_ID),LBN_CLICKED), (LPARAM)hList);
655 }
656
657
658 void CheckList_RedrawCheck (HWND hList, int ii)
659 {
660    RECT rr;
661    SendMessage (hList, LB_GETITEMRECT, (WPARAM)ii, (LPARAM)&rr);
662    rr.right = rr.left + cxCHECKBOX;
663    InvalidateRect (hList, &rr, TRUE);
664    UpdateWindow (hList);
665 }
666