2 * ReactOS Access Control List Editor
3 * Copyright (C) 2004-2005 ReactOS Team
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * PROJECT: ReactOS Access Control List Editor
22 * FILE: lib/aclui/checklist.c
23 * PURPOSE: Access Control List Editor
24 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
34 static const WCHAR szCheckListWndClass
[] = L
"CHECKLIST_ACLUI";
36 #define CI_TEXT_MARGIN_WIDTH (8)
37 #define CI_TEXT_MARGIN_HEIGHT (3)
38 #define CI_TEXT_SELECTIONMARGIN (1)
40 #define TIMER_ID_SETHITFOCUS (1)
41 #define TIMER_ID_RESETQUICKSEARCH (2)
43 #define DEFAULT_QUICKSEARCH_SETFOCUS_DELAY (2000)
44 #define DEFAULT_QUICKSEARCH_RESET_DELAY (3000)
46 typedef struct _CHECKITEM
48 struct _CHECKITEM
*Next
;
49 ACCESS_MASK AccessMask
;
52 } CHECKITEM
, *PCHECKITEM
;
54 typedef struct _CHECKLISTWND
60 PCHECKITEM CheckItemListHead
;
65 PCHECKITEM FocusedCheckItem
;
66 UINT FocusedCheckItemBox
;
68 COLORREF TextColor
[2];
71 PCHECKITEM QuickSearchHitItem
;
72 WCHAR QuickSearchText
[65];
73 UINT QuickSearchSetFocusDelay
;
74 UINT QuickSearchResetDelay
;
81 PCHECKITEM HoveredCheckItem
;
82 UINT HoveredCheckItemBox
;
89 UINT FocusedPushed
: 1;
90 UINT QuickSearchEnabled
: 1;
91 UINT ShowingCaret
: 1;
92 } CHECKLISTWND
, *PCHECKLISTWND
;
94 static VOID
EscapeQuickSearch(IN PCHECKLISTWND infoPtr
);
96 static VOID
ChangeCheckItemHotTrack(IN PCHECKLISTWND infoPtr
,
97 IN PCHECKITEM NewHotTrack
,
98 IN UINT NewHotTrackBox
);
100 static VOID
ChangeCheckItemFocus(IN PCHECKLISTWND infoPtr
,
101 IN PCHECKITEM NewFocus
,
102 IN UINT NewFocusBox
);
104 /******************************************************************************/
107 NotifyControlParent(IN PCHECKLISTWND infoPtr
,
113 if (infoPtr
->hNotify
!= NULL
)
115 LPNMHDR pnmh
= (LPNMHDR
)data
;
117 pnmh
->hwndFrom
= infoPtr
->hSelf
;
118 pnmh
->idFrom
= GetWindowLongPtr(infoPtr
->hSelf
,
122 Ret
= SendMessage(infoPtr
->hNotify
,
124 (WPARAM
)pnmh
->idFrom
,
132 FindCheckItemByIndex(IN PCHECKLISTWND infoPtr
,
135 PCHECKITEM Item
, Found
= NULL
;
139 for (Item
= infoPtr
->CheckItemListHead
;
157 FindCheckItemIndexByAccessMask(IN PCHECKLISTWND infoPtr
,
158 IN ACCESS_MASK AccessMask
)
161 INT Index
= 0, Found
= -1;
163 for (Item
= infoPtr
->CheckItemListHead
;
167 if (Item
->AccessMask
== AccessMask
)
180 CheckItemToIndex(IN PCHECKLISTWND infoPtr
,
186 for (CurItem
= infoPtr
->CheckItemListHead
, Index
= 0;
188 CurItem
= CurItem
->Next
, Index
++)
200 FindCheckItem(IN PCHECKLISTWND infoPtr
,
201 IN LPWSTR SearchText
)
204 SIZE_T Count
= wcslen(SearchText
);
206 for (CurItem
= infoPtr
->CheckItemListHead
;
208 CurItem
= CurItem
->Next
)
210 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
&&
211 !_wcsnicmp(CurItem
->Name
,
222 FindFirstEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
227 for (CurItem
= infoPtr
->CheckItemListHead
;
229 CurItem
= CurItem
->Next
)
231 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
233 /* return the Allow checkbox in case both check boxes are enabled! */
234 *CheckBox
= ((!(CurItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
);
243 FindLastEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
247 PCHECKITEM LastEnabledItem
= NULL
;
249 for (CurItem
= infoPtr
->CheckItemListHead
;
251 CurItem
= CurItem
->Next
)
253 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
255 LastEnabledItem
= CurItem
;
259 if (LastEnabledItem
!= NULL
)
261 /* return the Deny checkbox in case both check boxes are enabled! */
262 *CheckBox
= ((!(LastEnabledItem
->State
& CIS_DENYDISABLED
)) ? CLB_DENY
: CLB_ALLOW
);
265 return LastEnabledItem
;
269 FindPreviousEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
274 if (infoPtr
->FocusedCheckItem
!= NULL
)
276 Item
= infoPtr
->FocusedCheckItem
;
278 if (infoPtr
->FocusedCheckItemBox
== CLB_DENY
&&
279 !(Item
->State
& CIS_ALLOWDISABLED
))
281 /* currently an Deny checkbox is focused. return the Allow checkbox
283 *CheckBox
= CLB_ALLOW
;
291 for (CurItem
= infoPtr
->CheckItemListHead
;
292 CurItem
!= infoPtr
->FocusedCheckItem
;
293 CurItem
= CurItem
->Next
)
295 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
303 /* return the Deny checkbox in case both check boxes are enabled! */
304 *CheckBox
= ((!(Item
->State
& CIS_DENYDISABLED
)) ? CLB_DENY
: CLB_ALLOW
);
310 Item
= FindLastEnabledCheckBox(infoPtr
,
318 FindNextEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
323 if (infoPtr
->FocusedCheckItem
!= NULL
)
325 Item
= infoPtr
->FocusedCheckItem
;
327 if (infoPtr
->FocusedCheckItemBox
!= CLB_DENY
&&
328 !(Item
->State
& CIS_DENYDISABLED
))
330 /* currently an Allow checkbox is focused. return the Deny checkbox
332 *CheckBox
= CLB_DENY
;
340 if ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
)
342 /* return the Allow checkbox in case both check boxes are enabled! */
343 *CheckBox
= ((!(Item
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
);
353 Item
= FindFirstEnabledCheckBox(infoPtr
,
361 FindEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
362 IN BOOL ReverseSearch
,
369 Item
= FindPreviousEnabledCheckBox(infoPtr
,
374 Item
= FindNextEnabledCheckBox(infoPtr
,
382 PtToCheckItemBox(IN PCHECKLISTWND infoPtr
,
385 OUT BOOL
*DirectlyInCheckBox
)
387 INT FirstVisible
, Index
;
390 FirstVisible
= GetScrollPos(infoPtr
->hSelf
,
393 Index
= FirstVisible
+ (ppt
->y
/ infoPtr
->ItemHeight
);
395 Item
= FindCheckItemByIndex(infoPtr
,
401 cx
= infoPtr
->CheckBoxLeft
[CLB_ALLOW
] +
402 ((infoPtr
->CheckBoxLeft
[CLB_DENY
] - infoPtr
->CheckBoxLeft
[CLB_ALLOW
]) / 2);
404 *CheckBox
= ((ppt
->x
<= cx
) ? CLB_ALLOW
: CLB_DENY
);
406 if (DirectlyInCheckBox
!= NULL
)
408 INT y
= ppt
->y
% infoPtr
->ItemHeight
;
409 INT cxBox
= infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
);
411 if ((y
>= CI_TEXT_MARGIN_HEIGHT
&&
412 y
< infoPtr
->ItemHeight
- CI_TEXT_MARGIN_HEIGHT
) &&
414 (((ppt
->x
>= (infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - (cxBox
/ 2))) &&
415 (ppt
->x
< (infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - (cxBox
/ 2) + cxBox
)))
417 ((ppt
->x
>= (infoPtr
->CheckBoxLeft
[CLB_DENY
] - (cxBox
/ 2))) &&
418 (ppt
->x
< (infoPtr
->CheckBoxLeft
[CLB_DENY
] - (cxBox
/ 2) + cxBox
)))))
420 *DirectlyInCheckBox
= TRUE
;
424 *DirectlyInCheckBox
= FALSE
;
433 ClearCheckItems(IN PCHECKLISTWND infoPtr
)
435 PCHECKITEM CurItem
, NextItem
;
437 CurItem
= infoPtr
->CheckItemListHead
;
438 while (CurItem
!= NULL
)
440 NextItem
= CurItem
->Next
;
441 HeapFree(GetProcessHeap(),
447 infoPtr
->CheckItemListHead
= NULL
;
448 infoPtr
->CheckItemCount
= 0;
452 DeleteCheckItem(IN PCHECKLISTWND infoPtr
,
456 PCHECKITEM
*PrevPtr
= &infoPtr
->CheckItemListHead
;
458 for (CurItem
= infoPtr
->CheckItemListHead
;
460 CurItem
= CurItem
->Next
)
464 if (Item
== infoPtr
->QuickSearchHitItem
&& infoPtr
->QuickSearchEnabled
)
466 EscapeQuickSearch(infoPtr
);
470 if (Item
== infoPtr
->HoveredCheckItem
)
472 ChangeCheckItemHotTrack(infoPtr
,
478 if (Item
== infoPtr
->FocusedCheckItem
)
480 ChangeCheckItemFocus(infoPtr
,
485 *PrevPtr
= CurItem
->Next
;
486 HeapFree(GetProcessHeap(),
489 infoPtr
->CheckItemCount
--;
493 PrevPtr
= &CurItem
->Next
;
500 AddCheckItem(IN PCHECKLISTWND infoPtr
,
503 IN ACCESS_MASK AccessMask
,
508 PCHECKITEM
*PrevPtr
= &infoPtr
->CheckItemListHead
;
509 PCHECKITEM Item
= HeapAlloc(GetProcessHeap(),
511 sizeof(CHECKITEM
) + (wcslen(Name
) * sizeof(WCHAR
)));
514 for (CurItem
= infoPtr
->CheckItemListHead
, i
= 0;
516 CurItem
= CurItem
->Next
)
518 PrevPtr
= &CurItem
->Next
;
523 Item
->AccessMask
= AccessMask
;
524 Item
->State
= State
& CIS_MASK
;
529 infoPtr
->CheckItemCount
++;
541 ClearCheckBoxes(IN PCHECKLISTWND infoPtr
)
546 for (CurItem
= infoPtr
->CheckItemListHead
;
548 CurItem
= CurItem
->Next
)
550 if (CurItem
->State
& (CIS_ALLOW
| CIS_DENY
))
552 CurItem
->State
&= ~(CIS_ALLOW
| CIS_DENY
);
561 UpdateControl(IN PCHECKLISTWND infoPtr
)
564 SCROLLINFO ScrollInfo
;
567 GetClientRect(infoPtr
->hSelf
,
570 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
571 ScrollInfo
.fMask
= SIF_PAGE
| SIF_RANGE
;
573 ScrollInfo
.nMax
= infoPtr
->CheckItemCount
;
574 ScrollInfo
.nPage
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
576 ScrollInfo
.nTrackPos
= 0;
578 VisibleItems
= (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
;
580 if (ScrollInfo
.nPage
== (UINT
)VisibleItems
&& ScrollInfo
.nMax
> 0)
585 SetScrollInfo(infoPtr
->hSelf
,
590 RedrawWindow(infoPtr
->hSelf
,
593 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
597 UpdateCheckItem(IN PCHECKLISTWND infoPtr
,
601 INT VisibleFirst
, VisibleItems
;
602 INT Index
= CheckItemToIndex(infoPtr
,
606 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
609 if (Index
>= VisibleFirst
)
611 GetClientRect(infoPtr
->hSelf
,
614 VisibleItems
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
616 if (Index
<= VisibleFirst
+ VisibleItems
)
620 rcUpdate
.left
= rcClient
.left
;
621 rcUpdate
.right
= rcClient
.right
;
622 rcUpdate
.top
= (Index
- VisibleFirst
) * infoPtr
->ItemHeight
;
623 rcUpdate
.bottom
= rcUpdate
.top
+ infoPtr
->ItemHeight
;
625 RedrawWindow(infoPtr
->hSelf
,
628 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
635 MakeCheckItemVisible(IN PCHECKLISTWND infoPtr
,
639 INT VisibleFirst
, VisibleItems
, NewPos
;
640 INT Index
= CheckItemToIndex(infoPtr
,
644 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
647 if (Index
<= VisibleFirst
)
653 GetClientRect(infoPtr
->hSelf
,
656 VisibleItems
= (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
;
657 if (Index
- VisibleItems
+ 1 > VisibleFirst
)
659 NewPos
= Index
- VisibleItems
+ 1;
663 NewPos
= VisibleFirst
;
667 if (VisibleFirst
!= NewPos
)
669 SCROLLINFO ScrollInfo
;
671 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
672 ScrollInfo
.fMask
= SIF_POS
;
673 ScrollInfo
.nPos
= NewPos
;
674 NewPos
= SetScrollInfo(infoPtr
->hSelf
,
679 if (VisibleFirst
!= NewPos
)
681 ScrollWindowEx(infoPtr
->hSelf
,
683 (NewPos
- VisibleFirst
) * infoPtr
->ItemHeight
,
688 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
690 RedrawWindow(infoPtr
->hSelf
,
693 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
700 GetIdealItemHeight(IN PCHECKLISTWND infoPtr
)
702 HDC hdc
= GetDC(infoPtr
->hSelf
);
707 HGDIOBJ hOldFont
= SelectObject(hdc
,
710 if(GetTextMetrics(hdc
,
713 height
= tm
.tmHeight
;
723 ReleaseDC(infoPtr
->hSelf
,
732 RetChangeControlFont(IN PCHECKLISTWND infoPtr
,
736 HFONT hOldFont
= infoPtr
->hFont
;
737 infoPtr
->hFont
= hFont
;
739 if (hOldFont
!= hFont
)
741 infoPtr
->ItemHeight
= (2 * CI_TEXT_MARGIN_HEIGHT
) + GetIdealItemHeight(infoPtr
);
744 if (infoPtr
->ShowingCaret
)
747 CreateCaret(infoPtr
->hSelf
,
750 infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
));
753 UpdateControl(infoPtr
);
760 CalculateCheckBoxStyle(IN BOOL Checked
,
769 BtnState
= (Enabled
?
770 (Pushed
? CBS_CHECKEDPRESSED
: (HotTrack
? CBS_CHECKEDHOT
: CBS_CHECKEDNORMAL
)) :
771 CBS_CHECKEDDISABLED
);
775 BtnState
= (Enabled
?
776 (Pushed
? CBS_UNCHECKEDPRESSED
: (HotTrack
? CBS_UNCHECKEDHOT
: CBS_UNCHECKEDNORMAL
)) :
777 CBS_UNCHECKEDDISABLED
);
785 PaintControl(IN PCHECKLISTWND infoPtr
,
790 PCHECKITEM FirstItem
, Item
;
792 UINT VisibleFirstIndex
= rcUpdate
->top
/ infoPtr
->ItemHeight
;
793 UINT LastTouchedIndex
= rcUpdate
->bottom
/ infoPtr
->ItemHeight
;
797 (HBRUSH
)(COLOR_WINDOW
+ 1));
799 GetClientRect(infoPtr
->hSelf
,
802 ScrollPos
= GetScrollPos(infoPtr
->hSelf
,
805 FirstItem
= FindCheckItemByIndex(infoPtr
,
806 ScrollPos
+ VisibleFirstIndex
);
807 if (FirstItem
!= NULL
)
809 RECT TextRect
, ItemRect
, CheckBox
;
812 COLORREF OldTextColor
;
813 BOOL Enabled
, PrevEnabled
, IsPushed
;
820 Enabled
= IsWindowEnabled(infoPtr
->hSelf
);
821 PrevEnabled
= Enabled
;
824 ItemRect
.right
= rcClient
.right
;
825 ItemRect
.top
= VisibleFirstIndex
* infoPtr
->ItemHeight
;
827 TextRect
.left
= ItemRect
.left
+ CI_TEXT_MARGIN_WIDTH
;
828 TextRect
.right
= ItemRect
.right
- CI_TEXT_MARGIN_WIDTH
;
829 TextRect
.top
= ItemRect
.top
+ CI_TEXT_MARGIN_HEIGHT
;
836 OldTextColor
= SetTextColor(hDC
,
837 infoPtr
->TextColor
[Enabled
]);
839 hOldFont
= SelectObject(hDC
,
842 for (Item
= FirstItem
, CurrentIndex
= VisibleFirstIndex
;
843 Item
!= NULL
&& CurrentIndex
<= LastTouchedIndex
;
844 Item
= Item
->Next
, CurrentIndex
++)
846 TextRect
.bottom
= TextRect
.top
+ infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
);
847 ItemRect
.bottom
= ItemRect
.top
+ infoPtr
->ItemHeight
;
854 if (Enabled
&& PrevEnabled
!= ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
))
856 PrevEnabled
= ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
);
859 infoPtr
->TextColor
[PrevEnabled
]);
863 ItemHovered
= (Enabled
&& infoPtr
->HoveredCheckItem
== Item
);
866 if (infoPtr
->QuickSearchHitItem
== Item
)
868 COLORREF OldBkColor
, OldFgColor
;
870 SIZE_T TextLen
, HighlightLen
= wcslen(infoPtr
->QuickSearchText
);
872 /* highlight the quicksearch text */
873 if (GetTextExtentPoint32(hDC
,
878 COLORREF HighlightTextColor
, HighlightBackground
;
879 RECT rcHighlight
= TextRect
;
881 HighlightTextColor
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
882 HighlightBackground
= GetSysColor(COLOR_HIGHLIGHT
);
884 rcHighlight
.right
= rcHighlight
.left
+ TextSize
.cx
;
886 InflateRect(&rcHighlight
,
888 CI_TEXT_SELECTIONMARGIN
);
890 OldBkColor
= SetBkColor(hDC
,
891 HighlightBackground
);
892 OldFgColor
= SetTextColor(hDC
,
895 /* draw the highlighted text */
900 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
907 /* draw the remaining part of the text */
908 TextLen
= wcslen(Item
->Name
);
909 if (HighlightLen
< TextLen
)
911 rcHighlight
.left
= rcHighlight
.right
;
912 rcHighlight
.right
= TextRect
.right
;
915 Item
->Name
+ HighlightLen
,
918 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
929 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
932 CheckBox
.top
= TextRect
.top
;
933 CheckBox
.bottom
= TextRect
.bottom
;
935 /* draw the Allow checkbox */
936 IsPushed
= (Enabled
&& Item
== infoPtr
->FocusedCheckItem
&& infoPtr
->HasFocus
&&
937 !(Item
->State
& CIS_ALLOWDISABLED
) && infoPtr
->FocusedCheckItemBox
!= CLB_DENY
&&
938 infoPtr
->FocusedPushed
);
940 CheckBox
.left
= infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - ((TextRect
.bottom
- TextRect
.top
) / 2);
941 CheckBox
.right
= CheckBox
.left
+ (TextRect
.bottom
- TextRect
.top
);
943 if (infoPtr
->ThemeHandle
!= NULL
)
945 INT BtnState
= CalculateCheckBoxStyle(Item
->State
& CIS_ALLOW
,
946 Enabled
&& !(Item
->State
& CIS_ALLOWDISABLED
),
947 (ItemHovered
&& infoPtr
->HoveredCheckItemBox
!= CLB_DENY
),
951 hDrawResult
= DrawThemeBackground(infoPtr
->ThemeHandle
,
961 hDrawResult
= E_FAIL
;
964 /* draw the standard checkbox if no themes are enabled or drawing the
965 themeed control failed */
966 if (FAILED(hDrawResult
))
969 DrawFrameControl(hDC
,
972 DFCS_BUTTONCHECK
| DFCS_FLAT
|
973 ((Item
->State
& CIS_ALLOWDISABLED
) || !Enabled
? DFCS_INACTIVE
: 0) |
974 ((Item
->State
& CIS_ALLOW
) ? DFCS_CHECKED
: 0) |
975 (IsPushed
? DFCS_PUSHED
: 0));
977 if (Item
== infoPtr
->FocusedCheckItem
&& !(infoPtr
->UIState
& UISF_HIDEFOCUS
) &&
979 infoPtr
->FocusedCheckItemBox
!= CLB_DENY
)
981 RECT rcFocus
= CheckBox
;
983 InflateRect (&rcFocus
,
984 CI_TEXT_MARGIN_HEIGHT
,
985 CI_TEXT_MARGIN_HEIGHT
);
991 /* draw the Deny checkbox */
992 IsPushed
= (Enabled
&& Item
== infoPtr
->FocusedCheckItem
&& infoPtr
->HasFocus
&&
993 !(Item
->State
& CIS_DENYDISABLED
) && infoPtr
->FocusedCheckItemBox
== CLB_DENY
&&
994 infoPtr
->FocusedPushed
);
996 CheckBox
.left
= infoPtr
->CheckBoxLeft
[CLB_DENY
] - ((TextRect
.bottom
- TextRect
.top
) / 2);
997 CheckBox
.right
= CheckBox
.left
+ (TextRect
.bottom
- TextRect
.top
);
999 if (infoPtr
->ThemeHandle
!= NULL
)
1001 INT BtnState
= CalculateCheckBoxStyle(Item
->State
& CIS_DENY
,
1002 Enabled
&& !(Item
->State
& CIS_DENYDISABLED
),
1003 (ItemHovered
&& infoPtr
->HoveredCheckItemBox
== CLB_DENY
),
1006 hDrawResult
= DrawThemeBackground(infoPtr
->ThemeHandle
,
1016 hDrawResult
= E_FAIL
;
1019 /* draw the standard checkbox if no themes are enabled or drawing the
1020 themeed control failed */
1021 if (FAILED(hDrawResult
))
1024 DrawFrameControl(hDC
,
1027 DFCS_BUTTONCHECK
| DFCS_FLAT
|
1028 ((Item
->State
& CIS_DENYDISABLED
) || !Enabled
? DFCS_INACTIVE
: 0) |
1029 ((Item
->State
& CIS_DENY
) ? DFCS_CHECKED
: 0) |
1030 (IsPushed
? DFCS_PUSHED
: 0));
1032 if (infoPtr
->HasFocus
&& !(infoPtr
->UIState
& UISF_HIDEFOCUS
) &&
1033 Item
== infoPtr
->FocusedCheckItem
&&
1034 infoPtr
->FocusedCheckItemBox
== CLB_DENY
)
1036 RECT rcFocus
= CheckBox
;
1038 InflateRect (&rcFocus
,
1039 CI_TEXT_MARGIN_HEIGHT
,
1040 CI_TEXT_MARGIN_HEIGHT
);
1046 TextRect
.top
+= infoPtr
->ItemHeight
;
1047 ItemRect
.top
+= infoPtr
->ItemHeight
;
1064 ChangeCheckItemFocus(IN PCHECKLISTWND infoPtr
,
1065 IN PCHECKITEM NewFocus
,
1066 IN UINT NewFocusBox
)
1068 if (NewFocus
!= infoPtr
->FocusedCheckItem
)
1070 PCHECKITEM OldFocus
= infoPtr
->FocusedCheckItem
;
1071 infoPtr
->FocusedCheckItem
= NewFocus
;
1072 infoPtr
->FocusedCheckItemBox
= NewFocusBox
;
1074 if (OldFocus
!= NULL
)
1076 UpdateCheckItem(infoPtr
,
1082 infoPtr
->FocusedCheckItemBox
= NewFocusBox
;
1085 if (NewFocus
!= NULL
)
1087 MakeCheckItemVisible(infoPtr
,
1089 UpdateCheckItem(infoPtr
,
1095 UpdateCheckItemBox(IN PCHECKLISTWND infoPtr
,
1100 INT VisibleFirst
, VisibleItems
;
1101 INT Index
= CheckItemToIndex(infoPtr
,
1105 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
1108 if (Index
>= VisibleFirst
)
1110 GetClientRect(infoPtr
->hSelf
,
1113 VisibleItems
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
1115 if (Index
<= VisibleFirst
+ VisibleItems
)
1119 rcUpdate
.left
= rcClient
.left
+ infoPtr
->CheckBoxLeft
[ItemBox
] - (infoPtr
->ItemHeight
/ 2);
1120 rcUpdate
.right
= rcUpdate
.left
+ infoPtr
->ItemHeight
;
1121 rcUpdate
.top
= ((Index
- VisibleFirst
) * infoPtr
->ItemHeight
);
1122 rcUpdate
.bottom
= rcUpdate
.top
+ infoPtr
->ItemHeight
;
1124 RedrawWindow(infoPtr
->hSelf
,
1127 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1135 ChangeCheckItemHotTrack(IN PCHECKLISTWND infoPtr
,
1136 IN PCHECKITEM NewHotTrack
,
1137 IN UINT NewHotTrackBox
)
1139 if (NewHotTrack
!= infoPtr
->HoveredCheckItem
)
1141 PCHECKITEM OldHotTrack
= infoPtr
->HoveredCheckItem
;
1142 UINT OldHotTrackBox
= infoPtr
->HoveredCheckItemBox
;
1144 infoPtr
->HoveredCheckItem
= NewHotTrack
;
1145 infoPtr
->HoveredCheckItemBox
= NewHotTrackBox
;
1147 if (OldHotTrack
!= NULL
)
1149 UpdateCheckItemBox(infoPtr
,
1156 infoPtr
->HoveredCheckItemBox
= NewHotTrackBox
;
1159 if (NewHotTrack
!= NULL
)
1161 UpdateCheckItemBox(infoPtr
,
1169 ChangeCheckBox(IN PCHECKLISTWND infoPtr
,
1170 IN PCHECKITEM CheckItem
,
1171 IN UINT CheckItemBox
)
1173 NMCHANGEITEMCHECKBOX CheckData
;
1174 DWORD OldState
= CheckItem
->State
;
1175 DWORD CheckedBit
= ((infoPtr
->FocusedCheckItemBox
== CLB_DENY
) ? CIS_DENY
: CIS_ALLOW
);
1176 BOOL Checked
= (CheckItem
->State
& CheckedBit
) != 0;
1178 CheckData
.OldState
= OldState
;
1179 CheckData
.NewState
= (Checked
? OldState
& ~CheckedBit
: OldState
| CheckedBit
);
1180 CheckData
.CheckBox
= infoPtr
->FocusedCheckItemBox
;
1181 CheckData
.Checked
= !Checked
;
1183 if (NotifyControlParent(infoPtr
,
1184 CLN_CHANGINGITEMCHECKBOX
,
1185 &CheckData
) != (LRESULT
)-1)
1187 CheckItem
->State
= CheckData
.NewState
;
1190 return (CheckItem
->State
!= OldState
);
1194 DisplayCaret(IN PCHECKLISTWND infoPtr
)
1196 if (IsWindowEnabled(infoPtr
->hSelf
) && !infoPtr
->ShowingCaret
)
1198 infoPtr
->ShowingCaret
= TRUE
;
1200 CreateCaret(infoPtr
->hSelf
,
1202 infoPtr
->CaretWidth
,
1203 infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
));
1205 ShowCaret(infoPtr
->hSelf
);
1210 RemoveCaret(IN PCHECKLISTWND infoPtr
)
1212 if (IsWindowEnabled(infoPtr
->hSelf
) && infoPtr
->ShowingCaret
)
1214 infoPtr
->ShowingCaret
= FALSE
;
1216 HideCaret(infoPtr
->hSelf
);
1222 KillQuickSearchTimers(IN PCHECKLISTWND infoPtr
)
1224 KillTimer(infoPtr
->hSelf
,
1225 TIMER_ID_SETHITFOCUS
);
1226 KillTimer(infoPtr
->hSelf
,
1227 TIMER_ID_RESETQUICKSEARCH
);
1231 MapItemToRect(IN PCHECKLISTWND infoPtr
,
1232 IN PCHECKITEM CheckItem
,
1235 INT Index
= CheckItemToIndex(infoPtr
,
1242 GetClientRect(infoPtr
->hSelf
,
1245 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
1248 prcItem
->left
= rcClient
.left
;
1249 prcItem
->right
= rcClient
.right
;
1250 prcItem
->top
= (Index
- VisibleFirst
) * infoPtr
->ItemHeight
;
1251 prcItem
->bottom
= prcItem
->top
+ infoPtr
->ItemHeight
;
1258 prcItem
->bottom
= 0;
1263 UpdateCaretPos(IN PCHECKLISTWND infoPtr
)
1265 if (infoPtr
->ShowingCaret
&& infoPtr
->QuickSearchHitItem
!= NULL
)
1267 HDC hDC
= GetDC(infoPtr
->hSelf
);
1271 HGDIOBJ hOldFont
= SelectObject(hDC
,
1277 if (infoPtr
->QuickSearchText
[0] == L
'\0' ||
1278 GetTextExtentPoint32(hDC
,
1279 infoPtr
->QuickSearchHitItem
->Name
,
1280 wcslen(infoPtr
->QuickSearchText
),
1285 MapItemToRect(infoPtr
,
1286 infoPtr
->QuickSearchHitItem
,
1289 /* actually change the caret position */
1290 SetCaretPos(rcItem
.left
+ CI_TEXT_MARGIN_WIDTH
+ TextSize
.cx
,
1291 rcItem
.top
+ CI_TEXT_MARGIN_HEIGHT
);
1297 ReleaseDC(infoPtr
->hSelf
,
1304 EscapeQuickSearch(IN PCHECKLISTWND infoPtr
)
1306 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
)
1308 PCHECKITEM OldHit
= infoPtr
->QuickSearchHitItem
;
1310 infoPtr
->QuickSearchHitItem
= NULL
;
1311 infoPtr
->QuickSearchText
[0] = L
'\0';
1313 /* scroll back to the focused item */
1314 if (infoPtr
->FocusedCheckItem
!= NULL
)
1316 MakeCheckItemVisible(infoPtr
,
1317 infoPtr
->FocusedCheckItem
);
1320 /* repaint the old search hit item if it's still visible */
1321 UpdateCheckItem(infoPtr
,
1324 KillQuickSearchTimers(infoPtr
);
1326 RemoveCaret(infoPtr
);
1331 ChangeSearchHit(IN PCHECKLISTWND infoPtr
,
1332 IN PCHECKITEM NewHit
)
1334 PCHECKITEM OldHit
= infoPtr
->QuickSearchHitItem
;
1336 infoPtr
->QuickSearchHitItem
= NewHit
;
1338 if (OldHit
!= NewHit
)
1340 /* scroll to the new search hit */
1341 MakeCheckItemVisible(infoPtr
,
1344 /* repaint the old hit if present and visible */
1347 UpdateCheckItem(infoPtr
,
1352 /* show the caret the first time we find an item */
1353 DisplayCaret(infoPtr
);
1357 UpdateCaretPos(infoPtr
);
1359 UpdateCheckItem(infoPtr
,
1362 /* kill the reset timer and restart the set hit focus timer */
1363 KillTimer(infoPtr
->hSelf
,
1364 TIMER_ID_RESETQUICKSEARCH
);
1365 if (infoPtr
->QuickSearchSetFocusDelay
!= 0)
1367 SetTimer(infoPtr
->hSelf
,
1368 TIMER_ID_SETHITFOCUS
,
1369 infoPtr
->QuickSearchSetFocusDelay
,
1375 QuickSearchFindHit(IN PCHECKLISTWND infoPtr
,
1378 if (infoPtr
->QuickSearchEnabled
)
1388 Ret
= infoPtr
->QuickSearchHitItem
!= NULL
;
1391 /* NOTE: QuickSearchHitItem definitely has at least one
1392 enabled check box, the user can't search for disabled
1395 ChangeCheckItemFocus(infoPtr
,
1396 infoPtr
->QuickSearchHitItem
,
1397 ((!(infoPtr
->QuickSearchHitItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
));
1399 EscapeQuickSearch(infoPtr
);
1406 if (infoPtr
->QuickSearchHitItem
!= NULL
)
1408 INT SearchLen
= wcslen(infoPtr
->QuickSearchText
);
1411 /* delete the last character */
1412 infoPtr
->QuickSearchText
[--SearchLen
] = L
'\0';
1417 NewHit
= FindCheckItem(infoPtr
,
1418 infoPtr
->QuickSearchText
);
1422 /* change the search hit */
1423 ChangeSearchHit(infoPtr
,
1433 EscapeQuickSearch(infoPtr
);
1441 INT SearchLen
= wcslen(infoPtr
->QuickSearchText
);
1442 if (SearchLen
< (INT
)(sizeof(infoPtr
->QuickSearchText
) / sizeof(infoPtr
->QuickSearchText
[0])) - 1)
1444 infoPtr
->QuickSearchText
[SearchLen
++] = c
;
1445 infoPtr
->QuickSearchText
[SearchLen
] = L
'\0';
1447 NewHit
= FindCheckItem(infoPtr
,
1448 infoPtr
->QuickSearchText
);
1451 /* change the search hit */
1452 ChangeSearchHit(infoPtr
,
1459 /* reset the input */
1460 infoPtr
->QuickSearchText
[--SearchLen
] = L
'\0';
1472 static LRESULT CALLBACK
1473 CheckListWndProc(IN HWND hwnd
,
1478 PCHECKLISTWND infoPtr
;
1481 infoPtr
= (PCHECKLISTWND
)GetWindowLongPtr(hwnd
,
1484 if (infoPtr
== NULL
&& uMsg
!= WM_CREATE
)
1486 goto HandleDefaultMessage
;
1499 if (GetUpdateRect(hwnd
,
1503 hdc
= (wParam
!= 0 ? (HDC
)wParam
: BeginPaint(hwnd
, &ps
));
1507 PaintControl(infoPtr
,
1525 HWND hWndCapture
= GetCapture();
1527 pt
.x
= (LONG
)LOWORD(lParam
);
1528 pt
.y
= (LONG
)HIWORD(lParam
);
1531 /* handle hovering checkboxes */
1532 if (hWndCapture
== NULL
&& infoPtr
->ThemeHandle
!= NULL
)
1534 TRACKMOUSEEVENT tme
;
1535 PCHECKITEM HotTrackItem
;
1536 UINT HotTrackItemBox
;
1538 HotTrackItem
= PtToCheckItemBox(infoPtr
,
1542 if (HotTrackItem
!= NULL
&& InCheckBox
)
1544 if (infoPtr
->HoveredCheckItem
!= HotTrackItem
||
1545 infoPtr
->HoveredCheckItemBox
!= HotTrackItemBox
)
1547 ChangeCheckItemHotTrack(infoPtr
,
1554 ChangeCheckItemHotTrack(infoPtr
,
1559 tme
.cbSize
= sizeof(tme
);
1560 tme
.dwFlags
= TME_LEAVE
;
1561 tme
.hwndTrack
= hwnd
;
1562 tme
.dwHoverTime
= infoPtr
->HoverTime
;
1564 TrackMouseEvent(&tme
);
1568 if (hWndCapture
== hwnd
&& infoPtr
->FocusedCheckItem
!= NULL
)
1574 PtItem
= PtToCheckItemBox(infoPtr
,
1579 OldPushed
= infoPtr
->FocusedPushed
;
1580 infoPtr
->FocusedPushed
= InCheckBox
&& infoPtr
->FocusedCheckItem
== PtItem
&&
1581 infoPtr
->FocusedCheckItemBox
== PtItemBox
;
1583 if (OldPushed
!= infoPtr
->FocusedPushed
)
1585 UpdateCheckItemBox(infoPtr
,
1586 infoPtr
->FocusedCheckItem
,
1587 infoPtr
->FocusedCheckItemBox
);
1596 SCROLLINFO ScrollInfo
;
1598 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
1599 ScrollInfo
.fMask
= SIF_RANGE
| SIF_POS
;
1601 if (GetScrollInfo(hwnd
,
1605 INT OldPos
= ScrollInfo
.nPos
;
1607 switch (LOWORD(wParam
))
1610 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1614 if (ScrollInfo
.nPos
< ScrollInfo
.nMax
)
1621 if (ScrollInfo
.nPos
> 0)
1632 /* don't use ScrollInfo.nPage because we should only scroll
1633 down by the number of completely visible list entries.
1634 nPage however also includes the partly cropped list
1635 item at the bottom of the control */
1640 ScrollLines
= max(1,
1641 (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
);
1643 if (ScrollInfo
.nPos
+ ScrollLines
<= ScrollInfo
.nMax
)
1645 ScrollInfo
.nPos
+= ScrollLines
;
1649 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1659 /* don't use ScrollInfo.nPage because we should only scroll
1660 down by the number of completely visible list entries.
1661 nPage however also includes the partly cropped list
1662 item at the bottom of the control */
1667 ScrollLines
= max(1,
1668 (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
);
1670 if (ScrollInfo
.nPos
>= ScrollLines
)
1672 ScrollInfo
.nPos
-= ScrollLines
;
1676 ScrollInfo
.nPos
= 0;
1681 case SB_THUMBPOSITION
:
1684 ScrollInfo
.nPos
= HIWORD(wParam
);
1689 ScrollInfo
.nPos
= 0;
1693 if (OldPos
!= ScrollInfo
.nPos
)
1695 ScrollInfo
.fMask
= SIF_POS
;
1697 ScrollInfo
.nPos
= SetScrollInfo(hwnd
,
1702 if (OldPos
!= ScrollInfo
.nPos
)
1704 ScrollWindowEx(hwnd
,
1706 (OldPos
- ScrollInfo
.nPos
) * infoPtr
->ItemHeight
,
1711 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
1716 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1726 PCHECKITEM Item
= AddCheckItem(infoPtr
,
1729 (ACCESS_MASK
)wParam
,
1733 UpdateControl(infoPtr
);
1734 Ret
= (LRESULT
)Index
;
1745 PCHECKITEM Item
= FindCheckItemByIndex(infoPtr
,
1749 Ret
= DeleteCheckItem(infoPtr
,
1753 UpdateControl(infoPtr
);
1763 case CLM_SETITEMSTATE
:
1765 PCHECKITEM Item
= FindCheckItemByIndex(infoPtr
,
1769 DWORD OldState
= Item
->State
;
1770 Item
->State
= (DWORD
)lParam
& CIS_MASK
;
1772 if (Item
->State
!= OldState
)
1774 /* revert the focus if the currently focused item is about
1776 if (Item
== infoPtr
->FocusedCheckItem
&&
1777 (Item
->State
& CIS_DISABLED
))
1779 if (infoPtr
->FocusedCheckItemBox
== CLB_DENY
)
1781 if (Item
->State
& CIS_DENYDISABLED
)
1783 infoPtr
->FocusedCheckItem
= NULL
;
1788 if (Item
->State
& CIS_ALLOWDISABLED
)
1790 infoPtr
->FocusedCheckItem
= NULL
;
1795 UpdateControl(infoPtr
);
1802 case CLM_GETITEMCOUNT
:
1804 Ret
= infoPtr
->CheckItemCount
;
1810 ClearCheckItems(infoPtr
);
1811 UpdateControl(infoPtr
);
1815 case CLM_SETCHECKBOXCOLUMN
:
1817 infoPtr
->CheckBoxLeft
[wParam
!= CLB_DENY
] = (INT
)lParam
;
1818 UpdateControl(infoPtr
);
1823 case CLM_GETCHECKBOXCOLUMN
:
1825 Ret
= (LRESULT
)infoPtr
->CheckBoxLeft
[wParam
!= CLB_DENY
];
1829 case CLM_CLEARCHECKBOXES
:
1831 Ret
= (LRESULT
)ClearCheckBoxes(infoPtr
);
1834 UpdateControl(infoPtr
);
1839 case CLM_ENABLEQUICKSEARCH
:
1843 EscapeQuickSearch(infoPtr
);
1845 infoPtr
->QuickSearchEnabled
= (wParam
!= 0);
1849 case CLM_SETQUICKSEARCH_TIMEOUT_RESET
:
1851 infoPtr
->QuickSearchResetDelay
= (UINT
)wParam
;
1855 case CLM_SETQUICKSEARCH_TIMEOUT_SETFOCUS
:
1857 infoPtr
->QuickSearchSetFocusDelay
= (UINT
)wParam
;
1861 case CLM_FINDITEMBYACCESSMASK
:
1863 Ret
= (LRESULT
)FindCheckItemIndexByAccessMask(infoPtr
,
1864 (ACCESS_MASK
)wParam
);
1870 Ret
= (LRESULT
)RetChangeControlFont(infoPtr
,
1872 (BOOL
)LOWORD(lParam
));
1878 Ret
= (LRESULT
)infoPtr
->hFont
;
1882 case WM_STYLECHANGED
:
1884 if (wParam
== (WPARAM
)GWL_STYLE
)
1886 UpdateControl(infoPtr
);
1893 EscapeQuickSearch(infoPtr
);
1895 UpdateControl(infoPtr
);
1902 UINT ScrollLines
= 3;
1904 SystemParametersInfo(SPI_GETWHEELSCROLLLINES
,
1908 ScrollDelta
= 0 - (SHORT
)HIWORD(wParam
);
1910 if (ScrollLines
!= 0 &&
1911 abs(ScrollDelta
) >= WHEEL_DELTA
)
1913 SCROLLINFO ScrollInfo
;
1915 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
1916 ScrollInfo
.fMask
= SIF_RANGE
| SIF_POS
;
1918 if (GetScrollInfo(hwnd
,
1922 INT OldPos
= ScrollInfo
.nPos
;
1924 ScrollInfo
.nPos
+= (ScrollDelta
/ WHEEL_DELTA
) * ScrollLines
;
1925 if (ScrollInfo
.nPos
< 0)
1926 ScrollInfo
.nPos
= 0;
1927 else if (ScrollInfo
.nPos
> ScrollInfo
.nMax
)
1928 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1930 if (OldPos
!= ScrollInfo
.nPos
)
1932 ScrollInfo
.fMask
= SIF_POS
;
1934 ScrollInfo
.nPos
= SetScrollInfo(hwnd
,
1939 if (OldPos
!= ScrollInfo
.nPos
)
1941 ScrollWindowEx(hwnd
,
1943 (OldPos
- ScrollInfo
.nPos
) * infoPtr
->ItemHeight
,
1948 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
1953 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1963 infoPtr
->HasFocus
= TRUE
;
1965 if (infoPtr
->FocusedCheckItem
== NULL
)
1967 BOOL Shift
= GetKeyState(VK_SHIFT
) & 0x8000;
1968 infoPtr
->FocusedCheckItem
= FindEnabledCheckBox(infoPtr
,
1970 &infoPtr
->FocusedCheckItemBox
);
1972 if (infoPtr
->FocusedCheckItem
!= NULL
)
1974 MakeCheckItemVisible(infoPtr
,
1975 infoPtr
->FocusedCheckItem
);
1977 UpdateCheckItem(infoPtr
,
1978 infoPtr
->FocusedCheckItem
);
1985 EscapeQuickSearch(infoPtr
);
1987 infoPtr
->HasFocus
= FALSE
;
1988 if (infoPtr
->FocusedCheckItem
!= NULL
)
1990 infoPtr
->FocusedPushed
= FALSE
;
1992 UpdateCheckItem(infoPtr
,
1993 infoPtr
->FocusedCheckItem
);
1998 case WM_LBUTTONDBLCLK
:
1999 case WM_LBUTTONDOWN
:
2000 case WM_MBUTTONDOWN
:
2001 case WM_RBUTTONDOWN
:
2003 if (IsWindowEnabled(hwnd
))
2005 PCHECKITEM NewFocus
;
2006 UINT NewFocusBox
= 0;
2009 BOOL ChangeFocus
, Capture
= FALSE
;
2011 pt
.x
= (LONG
)LOWORD(lParam
);
2012 pt
.y
= (LONG
)HIWORD(lParam
);
2014 NewFocus
= PtToCheckItemBox(infoPtr
,
2018 if (NewFocus
!= NULL
)
2020 if (NewFocus
->State
& ((NewFocusBox
!= CLB_DENY
) ? CIS_ALLOWDISABLED
: CIS_DENYDISABLED
))
2022 /* the user clicked on a disabled checkbox, try to set
2023 the focus to the other one or not change it at all */
2027 ChangeFocus
= ((NewFocus
->State
& CIS_DISABLED
) != CIS_DISABLED
);
2030 NewFocusBox
= ((NewFocusBox
!= CLB_DENY
) ? CLB_DENY
: CLB_ALLOW
);
2038 if (InCheckBox
&& ChangeFocus
&& GetCapture() == NULL
&&
2039 (uMsg
== WM_LBUTTONDOWN
|| uMsg
== WM_LBUTTONDBLCLK
))
2041 infoPtr
->FocusedPushed
= TRUE
;
2052 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
&&
2053 infoPtr
->QuickSearchHitItem
!= NewFocus
)
2055 EscapeQuickSearch(infoPtr
);
2058 ChangeCheckItemFocus(infoPtr
,
2063 if (!infoPtr
->HasFocus
)
2078 if (GetCapture() == hwnd
)
2080 if (infoPtr
->FocusedCheckItem
!= NULL
&& infoPtr
->FocusedPushed
)
2087 pt
.x
= (LONG
)LOWORD(lParam
);
2088 pt
.y
= (LONG
)HIWORD(lParam
);
2090 infoPtr
->FocusedPushed
= FALSE
;
2092 PtItem
= PtToCheckItemBox(infoPtr
,
2097 if (PtItem
== infoPtr
->FocusedCheckItem
&& InCheckBox
&&
2098 PtItemBox
== infoPtr
->FocusedCheckItemBox
)
2100 UINT OtherBox
= ((PtItemBox
== CLB_ALLOW
) ? CLB_DENY
: CLB_ALLOW
);
2101 DWORD OtherStateMask
= ((OtherBox
== CLB_ALLOW
) ?
2102 (CIS_ALLOW
| CIS_ALLOWDISABLED
) :
2103 (CIS_DENY
| CIS_DENYDISABLED
));
2104 DWORD OtherStateOld
= PtItem
->State
& OtherStateMask
;
2105 if (ChangeCheckBox(infoPtr
,
2108 ((PtItem
->State
& OtherStateMask
) != OtherStateOld
))
2110 UpdateCheckItemBox(infoPtr
,
2111 infoPtr
->FocusedCheckItem
,
2116 UpdateCheckItemBox(infoPtr
,
2117 infoPtr
->FocusedCheckItem
,
2118 infoPtr
->FocusedCheckItemBox
);
2132 if (GetCapture() == NULL
&&
2133 !QuickSearchFindHit(infoPtr
,
2136 if (infoPtr
->FocusedCheckItem
!= NULL
&&
2137 (infoPtr
->QuickSearchHitItem
== NULL
||
2138 infoPtr
->QuickSearchHitItem
== infoPtr
->FocusedCheckItem
))
2140 UINT OldPushed
= infoPtr
->FocusedPushed
;
2141 infoPtr
->FocusedPushed
= TRUE
;
2143 if (infoPtr
->FocusedPushed
!= OldPushed
)
2145 MakeCheckItemVisible(infoPtr
,
2146 infoPtr
->FocusedCheckItem
);
2148 UpdateCheckItemBox(infoPtr
,
2149 infoPtr
->FocusedCheckItem
,
2150 infoPtr
->FocusedCheckItemBox
);
2159 if (GetCapture() == NULL
&&
2160 !QuickSearchFindHit(infoPtr
,
2163 if (infoPtr
->FocusedCheckItem
!= NULL
&&
2164 infoPtr
->QuickSearchHitItem
== NULL
)
2167 DWORD OtherStateMask
;
2168 DWORD OtherStateOld
;
2170 MakeCheckItemVisible(infoPtr
,
2171 infoPtr
->FocusedCheckItem
);
2173 OtherBox
= ((infoPtr
->FocusedCheckItemBox
== CLB_ALLOW
) ? CLB_DENY
: CLB_ALLOW
);
2174 OtherStateMask
= ((OtherBox
== CLB_ALLOW
) ?
2175 (CIS_ALLOW
| CIS_ALLOWDISABLED
) :
2176 (CIS_DENY
| CIS_DENYDISABLED
));
2177 OtherStateOld
= infoPtr
->FocusedCheckItem
->State
& OtherStateMask
;
2178 if (ChangeCheckBox(infoPtr
,
2179 infoPtr
->FocusedCheckItem
,
2180 infoPtr
->FocusedCheckItemBox
))
2182 UpdateCheckItemBox(infoPtr
,
2183 infoPtr
->FocusedCheckItem
,
2184 infoPtr
->FocusedCheckItemBox
);
2185 if ((infoPtr
->FocusedCheckItem
->State
& OtherStateMask
) != OtherStateOld
)
2187 UpdateCheckItemBox(infoPtr
,
2188 infoPtr
->FocusedCheckItem
,
2199 if (GetCapture() == NULL
)
2201 PCHECKITEM NewFocus
;
2202 UINT NewFocusBox
= 0;
2203 BOOL Shift
= GetKeyState(VK_SHIFT
) & 0x8000;
2205 EscapeQuickSearch(infoPtr
);
2207 NewFocus
= FindEnabledCheckBox(infoPtr
,
2211 /* update the UI status */
2212 SendMessage(GetAncestor(hwnd
,
2215 MAKEWPARAM(UIS_INITIALIZE
,
2219 ChangeCheckItemFocus(infoPtr
,
2228 goto HandleDefaultMessage
;
2236 if (wParam
== VK_SPACE
&& IsWindowEnabled(hwnd
) &&
2237 infoPtr
->FocusedCheckItem
!= NULL
&&
2238 infoPtr
->FocusedPushed
)
2240 UINT OtherBox
= ((infoPtr
->FocusedCheckItemBox
== CLB_ALLOW
) ? CLB_DENY
: CLB_ALLOW
);
2241 DWORD OtherStateMask
= ((OtherBox
== CLB_ALLOW
) ?
2242 (CIS_ALLOW
| CIS_ALLOWDISABLED
) :
2243 (CIS_DENY
| CIS_DENYDISABLED
));
2244 DWORD OtherStateOld
= infoPtr
->FocusedCheckItem
->State
& OtherStateMask
;
2246 infoPtr
->FocusedPushed
= FALSE
;
2248 if (ChangeCheckBox(infoPtr
,
2249 infoPtr
->FocusedCheckItem
,
2250 infoPtr
->FocusedCheckItemBox
))
2252 UpdateCheckItemBox(infoPtr
,
2253 infoPtr
->FocusedCheckItem
,
2254 infoPtr
->FocusedCheckItemBox
);
2256 if ((infoPtr
->FocusedCheckItem
->State
& OtherStateMask
) != OtherStateOld
)
2258 UpdateCheckItemBox(infoPtr
,
2259 infoPtr
->FocusedCheckItem
,
2272 virtKey
= (lParam
!= 0 ? (INT
)((LPMSG
)lParam
)->wParam
: 0);
2277 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
)
2279 Ret
|= DLGC_WANTCHARS
| DLGC_WANTMESSAGE
;
2283 Ret
|= DLGC_WANTMESSAGE
;
2292 BOOL Shift
= GetKeyState(VK_SHIFT
) & 0x8000;
2294 EnabledBox
= FindEnabledCheckBox(infoPtr
,
2297 Ret
|= (EnabledBox
? DLGC_WANTTAB
: DLGC_WANTCHARS
);
2303 if (infoPtr
->QuickSearchEnabled
)
2305 Ret
|= DLGC_WANTCHARS
;
2315 QuickSearchFindHit(infoPtr
,
2320 case WM_SYSCOLORCHANGE
:
2322 infoPtr
->TextColor
[0] = GetSysColor(COLOR_GRAYTEXT
);
2323 infoPtr
->TextColor
[1] = GetSysColor(COLOR_WINDOWTEXT
);
2330 if (infoPtr
->HoveredCheckItem
!= NULL
)
2332 /* reset and repaint the hovered check item box */
2333 ChangeCheckItemHotTrack(infoPtr
,
2340 case WM_THEMECHANGED
:
2342 if (infoPtr
->ThemeHandle
!= NULL
)
2344 CloseThemeData(infoPtr
->ThemeHandle
);
2345 infoPtr
->ThemeHandle
= NULL
;
2349 infoPtr
->ThemeHandle
= OpenThemeData(infoPtr
->hSelf
,
2356 case WM_SETTINGCHANGE
:
2358 DWORD OldCaretWidth
= infoPtr
->CaretWidth
;
2361 /* update the hover time */
2362 if (!SystemParametersInfo(SPI_GETMOUSEHOVERTIME
,
2364 &infoPtr
->HoverTime
,
2367 infoPtr
->HoverTime
= HOVER_DEFAULT
;
2371 /* update the caret */
2372 if (!SystemParametersInfo(SPI_GETCARETWIDTH
,
2374 &infoPtr
->CaretWidth
,
2377 infoPtr
->CaretWidth
= 2;
2379 if (OldCaretWidth
!= infoPtr
->CaretWidth
&& infoPtr
->ShowingCaret
)
2384 infoPtr
->CaretWidth
,
2385 infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
));
2392 UpdateControl(infoPtr
);
2396 case WM_UPDATEUISTATE
:
2398 DWORD OldUIState
= infoPtr
->UIState
;
2400 switch (LOWORD(wParam
))
2403 infoPtr
->UIState
|= HIWORD(wParam
);
2407 infoPtr
->UIState
&= ~(HIWORD(wParam
));
2411 if (OldUIState
!= infoPtr
->UIState
)
2413 if (infoPtr
->FocusedCheckItem
!= NULL
)
2415 UpdateCheckItemBox(infoPtr
,
2416 infoPtr
->FocusedCheckItem
,
2417 infoPtr
->FocusedCheckItemBox
);
2427 case TIMER_ID_SETHITFOCUS
:
2429 /* kill the timer */
2433 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
)
2435 /* change the focus to the hit item, this item has to have
2436 at least one enabled checkbox! */
2437 ChangeCheckItemFocus(infoPtr
,
2438 infoPtr
->QuickSearchHitItem
,
2439 ((!(infoPtr
->QuickSearchHitItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
));
2441 /* start the timer to reset quicksearch */
2442 if (infoPtr
->QuickSearchResetDelay
!= 0)
2445 TIMER_ID_RESETQUICKSEARCH
,
2446 infoPtr
->QuickSearchResetDelay
,
2452 case TIMER_ID_RESETQUICKSEARCH
:
2454 /* kill the timer */
2458 /* escape quick search */
2459 EscapeQuickSearch(infoPtr
);
2468 infoPtr
= HeapAlloc(GetProcessHeap(),
2470 sizeof(CHECKLISTWND
));
2471 if (infoPtr
!= NULL
)
2475 infoPtr
->hSelf
= hwnd
;
2476 infoPtr
->hNotify
= ((LPCREATESTRUCTW
)lParam
)->hwndParent
;
2478 SetWindowLongPtr(hwnd
,
2480 (DWORD_PTR
)infoPtr
);
2482 infoPtr
->CheckItemListHead
= NULL
;
2483 infoPtr
->CheckItemCount
= 0;
2485 if (!SystemParametersInfo(SPI_GETCARETWIDTH
,
2487 &infoPtr
->CaretWidth
,
2490 infoPtr
->CaretWidth
= 2;
2492 infoPtr
->ItemHeight
= 10;
2493 infoPtr
->ShowingCaret
= FALSE
;
2495 infoPtr
->HasFocus
= FALSE
;
2496 infoPtr
->FocusedCheckItem
= NULL
;
2497 infoPtr
->FocusedCheckItemBox
= 0;
2498 infoPtr
->FocusedPushed
= FALSE
;
2500 infoPtr
->TextColor
[0] = GetSysColor(COLOR_GRAYTEXT
);
2501 infoPtr
->TextColor
[1] = GetSysColor(COLOR_WINDOWTEXT
);
2506 infoPtr
->CheckBoxLeft
[0] = rcClient
.right
- 30;
2507 infoPtr
->CheckBoxLeft
[1] = rcClient
.right
- 15;
2509 infoPtr
->QuickSearchEnabled
= FALSE
;
2510 infoPtr
->QuickSearchText
[0] = L
'\0';
2512 infoPtr
->QuickSearchSetFocusDelay
= DEFAULT_QUICKSEARCH_SETFOCUS_DELAY
;
2513 infoPtr
->QuickSearchResetDelay
= DEFAULT_QUICKSEARCH_RESET_DELAY
;
2516 infoPtr
->HoveredCheckItem
= NULL
;
2517 infoPtr
->HoveredCheckItemBox
= 0;
2518 if (!SystemParametersInfo(SPI_GETMOUSEHOVERTIME
,
2520 &infoPtr
->HoverTime
,
2523 infoPtr
->HoverTime
= HOVER_DEFAULT
;
2528 infoPtr
->ThemeHandle
= OpenThemeData(infoPtr
->hSelf
,
2533 infoPtr
->ThemeHandle
= NULL
;
2537 infoPtr
->UIState
= SendMessage(hwnd
,
2551 if (infoPtr
->ShowingCaret
)
2556 ClearCheckItems(infoPtr
);
2559 if (infoPtr
->ThemeHandle
!= NULL
)
2561 CloseThemeData(infoPtr
->ThemeHandle
);
2565 HeapFree(GetProcessHeap(),
2568 SetWindowLongPtr(hwnd
,
2576 HandleDefaultMessage
:
2577 Ret
= DefWindowProc(hwnd
,
2589 RegisterCheckListControl(IN HINSTANCE hInstance
)
2593 wc
.style
= CS_DBLCLKS
;
2594 wc
.lpfnWndProc
= CheckListWndProc
;
2596 wc
.cbWndExtra
= sizeof(PCHECKLISTWND
);
2597 wc
.hInstance
= hInstance
;
2599 wc
.hCursor
= LoadCursor(NULL
,
2601 wc
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
2602 wc
.lpszMenuName
= NULL
;
2603 wc
.lpszClassName
= szCheckListWndClass
;
2605 return RegisterClass(&wc
) != 0;
2609 UnregisterCheckListControl(HINSTANCE hInstance
)
2611 UnregisterClass(szCheckListWndClass
,