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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 #define CI_TEXT_MARGIN_WIDTH (8)
35 #define CI_TEXT_MARGIN_HEIGHT (3)
36 #define CI_TEXT_SELECTIONMARGIN (1)
38 #define TIMER_ID_SETHITFOCUS (1)
39 #define TIMER_ID_RESETQUICKSEARCH (2)
41 #define DEFAULT_QUICKSEARCH_SETFOCUS_DELAY (2000)
42 #define DEFAULT_QUICKSEARCH_RESET_DELAY (3000)
44 typedef struct _CHECKITEM
46 struct _CHECKITEM
*Next
;
47 ACCESS_MASK AccessMask
;
50 } CHECKITEM
, *PCHECKITEM
;
52 typedef struct _CHECKLISTWND
58 PCHECKITEM CheckItemListHead
;
64 PCHECKITEM FocusedCheckItem
;
65 UINT FocusedCheckItemBox
;
69 COLORREF TextColor
[2];
72 BOOL QuickSearchEnabled
;
73 PCHECKITEM QuickSearchHitItem
;
74 WCHAR QuickSearchText
[65];
75 UINT QuickSearchSetFocusDelay
;
76 UINT QuickSearchResetDelay
;
82 PCHECKITEM HoveredCheckItem
;
83 UINT HoveredCheckItemBox
;
88 } CHECKLISTWND
, *PCHECKLISTWND
;
90 static VOID
EscapeQuickSearch(IN PCHECKLISTWND infoPtr
);
92 static VOID
ChangeCheckItemHotTrack(IN PCHECKLISTWND infoPtr
,
93 IN PCHECKITEM NewHotTrack
,
94 IN UINT NewHotTrackBox
);
96 static VOID
ChangeCheckItemFocus(IN PCHECKLISTWND infoPtr
,
97 IN PCHECKITEM NewFocus
,
100 /******************************************************************************/
103 NotifyControlParent(IN PCHECKLISTWND infoPtr
,
109 if (infoPtr
->hNotify
!= NULL
)
111 LPNMHDR pnmh
= (LPNMHDR
)data
;
113 pnmh
->hwndFrom
= infoPtr
->hSelf
;
114 pnmh
->idFrom
= GetWindowLongPtr(infoPtr
->hSelf
,
118 Ret
= SendMessage(infoPtr
->hNotify
,
120 (WPARAM
)pnmh
->idFrom
,
128 FindCheckItemByIndex(IN PCHECKLISTWND infoPtr
,
131 PCHECKITEM Item
, Found
= NULL
;
135 for (Item
= infoPtr
->CheckItemListHead
;
153 FindCheckItemIndexByAccessMask(IN PCHECKLISTWND infoPtr
,
154 IN ACCESS_MASK AccessMask
)
157 UINT Index
= 0, Found
= -1;
159 for (Item
= infoPtr
->CheckItemListHead
;
163 if (Item
->AccessMask
== AccessMask
)
176 CheckItemToIndex(IN PCHECKLISTWND infoPtr
,
182 for (CurItem
= infoPtr
->CheckItemListHead
, Index
= 0;
184 CurItem
= CurItem
->Next
, Index
++)
196 FindCheckItem(IN PCHECKLISTWND infoPtr
,
197 IN LPWSTR SearchText
)
200 SIZE_T Count
= wcslen(SearchText
);
202 for (CurItem
= infoPtr
->CheckItemListHead
;
204 CurItem
= CurItem
->Next
)
206 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
&&
207 !wcsnicmp(CurItem
->Name
,
218 FindFirstEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
223 for (CurItem
= infoPtr
->CheckItemListHead
;
225 CurItem
= CurItem
->Next
)
227 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
229 /* return the Allow checkbox in case both check boxes are enabled! */
230 *CheckBox
= ((!(CurItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
);
239 FindLastEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
243 PCHECKITEM LastEnabledItem
= NULL
;
245 for (CurItem
= infoPtr
->CheckItemListHead
;
247 CurItem
= CurItem
->Next
)
249 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
251 LastEnabledItem
= CurItem
;
255 if (LastEnabledItem
!= NULL
)
257 /* return the Deny checkbox in case both check boxes are enabled! */
258 *CheckBox
= ((!(LastEnabledItem
->State
& CIS_DENYDISABLED
)) ? CLB_DENY
: CLB_ALLOW
);
261 return LastEnabledItem
;
265 FindPreviousEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
270 if (infoPtr
->FocusedCheckItem
!= NULL
)
272 Item
= infoPtr
->FocusedCheckItem
;
274 if (infoPtr
->FocusedCheckItemBox
== CLB_DENY
&&
275 !(Item
->State
& CIS_ALLOWDISABLED
))
277 /* currently an Deny checkbox is focused. return the Allow checkbox
279 *CheckBox
= CLB_ALLOW
;
287 for (CurItem
= infoPtr
->CheckItemListHead
;
288 CurItem
!= infoPtr
->FocusedCheckItem
;
289 CurItem
= CurItem
->Next
)
291 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
299 /* return the Deny checkbox in case both check boxes are enabled! */
300 *CheckBox
= ((!(Item
->State
& CIS_DENYDISABLED
)) ? CLB_DENY
: CLB_ALLOW
);
306 Item
= FindLastEnabledCheckBox(infoPtr
,
314 FindNextEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
319 if (infoPtr
->FocusedCheckItem
!= NULL
)
321 Item
= infoPtr
->FocusedCheckItem
;
323 if (infoPtr
->FocusedCheckItemBox
!= CLB_DENY
&&
324 !(Item
->State
& CIS_DENYDISABLED
))
326 /* currently an Allow checkbox is focused. return the Deny checkbox
328 *CheckBox
= CLB_DENY
;
336 if ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
)
338 /* return the Allow checkbox in case both check boxes are enabled! */
339 *CheckBox
= ((!(Item
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
);
349 Item
= FindFirstEnabledCheckBox(infoPtr
,
357 FindEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
358 IN BOOL ReverseSearch
,
365 Item
= FindPreviousEnabledCheckBox(infoPtr
,
370 Item
= FindNextEnabledCheckBox(infoPtr
,
378 PtToCheckItemBox(IN PCHECKLISTWND infoPtr
,
381 OUT BOOL
*DirectlyInCheckBox
)
383 INT FirstVisible
, Index
;
386 FirstVisible
= GetScrollPos(infoPtr
->hSelf
,
389 Index
= FirstVisible
+ (ppt
->y
/ infoPtr
->ItemHeight
);
391 Item
= FindCheckItemByIndex(infoPtr
,
397 cx
= infoPtr
->CheckBoxLeft
[CLB_ALLOW
] +
398 ((infoPtr
->CheckBoxLeft
[CLB_DENY
] - infoPtr
->CheckBoxLeft
[CLB_ALLOW
]) / 2);
400 *CheckBox
= ((ppt
->x
<= cx
) ? CLB_ALLOW
: CLB_DENY
);
402 if (DirectlyInCheckBox
!= NULL
)
404 INT y
= ppt
->y
% infoPtr
->ItemHeight
;
405 INT cxBox
= infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
);
407 if ((y
>= CI_TEXT_MARGIN_HEIGHT
&&
408 y
< infoPtr
->ItemHeight
- CI_TEXT_MARGIN_HEIGHT
) &&
410 (((ppt
->x
>= (infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - (cxBox
/ 2))) &&
411 (ppt
->x
< (infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - (cxBox
/ 2) + cxBox
)))
413 ((ppt
->x
>= (infoPtr
->CheckBoxLeft
[CLB_DENY
] - (cxBox
/ 2))) &&
414 (ppt
->x
< (infoPtr
->CheckBoxLeft
[CLB_DENY
] - (cxBox
/ 2) + cxBox
)))))
416 *DirectlyInCheckBox
= TRUE
;
420 *DirectlyInCheckBox
= FALSE
;
429 ClearCheckItems(IN PCHECKLISTWND infoPtr
)
431 PCHECKITEM CurItem
, NextItem
;
433 CurItem
= infoPtr
->CheckItemListHead
;
434 while (CurItem
!= NULL
)
436 NextItem
= CurItem
->Next
;
437 HeapFree(GetProcessHeap(),
443 infoPtr
->CheckItemListHead
= NULL
;
444 infoPtr
->CheckItemCount
= 0;
448 DeleteCheckItem(IN PCHECKLISTWND infoPtr
,
452 PCHECKITEM
*PrevPtr
= &infoPtr
->CheckItemListHead
;
454 for (CurItem
= infoPtr
->CheckItemListHead
;
456 CurItem
= CurItem
->Next
)
460 if (Item
== infoPtr
->QuickSearchHitItem
&& infoPtr
->QuickSearchEnabled
)
462 EscapeQuickSearch(infoPtr
);
466 if (Item
== infoPtr
->HoveredCheckItem
)
468 ChangeCheckItemHotTrack(infoPtr
,
474 if (Item
== infoPtr
->FocusedCheckItem
)
476 ChangeCheckItemFocus(infoPtr
,
481 *PrevPtr
= CurItem
->Next
;
482 HeapFree(GetProcessHeap(),
485 infoPtr
->CheckItemCount
--;
489 PrevPtr
= &CurItem
->Next
;
496 AddCheckItem(IN PCHECKLISTWND infoPtr
,
499 IN ACCESS_MASK AccessMask
,
504 PCHECKITEM
*PrevPtr
= &infoPtr
->CheckItemListHead
;
505 PCHECKITEM Item
= HeapAlloc(GetProcessHeap(),
507 sizeof(CHECKITEM
) + (wcslen(Name
) * sizeof(WCHAR
)));
510 for (CurItem
= infoPtr
->CheckItemListHead
, i
= 0;
512 CurItem
= CurItem
->Next
)
514 PrevPtr
= &CurItem
->Next
;
519 Item
->AccessMask
= AccessMask
;
520 Item
->State
= State
& CIS_MASK
;
525 infoPtr
->CheckItemCount
++;
537 ClearCheckBoxes(IN PCHECKLISTWND infoPtr
)
542 for (CurItem
= infoPtr
->CheckItemListHead
;
544 CurItem
= CurItem
->Next
)
546 if (CurItem
->State
& (CIS_ALLOW
| CIS_DENY
))
548 CurItem
->State
&= ~(CIS_ALLOW
| CIS_DENY
);
557 UpdateControl(IN PCHECKLISTWND infoPtr
)
560 SCROLLINFO ScrollInfo
;
563 GetClientRect(infoPtr
->hSelf
,
566 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
567 ScrollInfo
.fMask
= SIF_PAGE
| SIF_RANGE
;
569 ScrollInfo
.nMax
= infoPtr
->CheckItemCount
;
570 ScrollInfo
.nPage
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
572 ScrollInfo
.nTrackPos
= 0;
574 VisibleItems
= (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
;
576 if (ScrollInfo
.nPage
== (UINT
)VisibleItems
&& ScrollInfo
.nMax
> 0)
581 SetScrollInfo(infoPtr
->hSelf
,
586 RedrawWindow(infoPtr
->hSelf
,
589 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
593 UpdateCheckItem(IN PCHECKLISTWND infoPtr
,
597 INT VisibleFirst
, VisibleItems
;
598 INT Index
= CheckItemToIndex(infoPtr
,
602 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
605 if (Index
>= VisibleFirst
)
607 GetClientRect(infoPtr
->hSelf
,
610 VisibleItems
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
612 if (Index
<= VisibleFirst
+ VisibleItems
)
616 rcUpdate
.left
= rcClient
.left
;
617 rcUpdate
.right
= rcClient
.right
;
618 rcUpdate
.top
= (Index
- VisibleFirst
) * infoPtr
->ItemHeight
;
619 rcUpdate
.bottom
= rcUpdate
.top
+ infoPtr
->ItemHeight
;
621 RedrawWindow(infoPtr
->hSelf
,
624 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
631 MakeCheckItemVisible(IN PCHECKLISTWND infoPtr
,
635 INT VisibleFirst
, VisibleItems
, NewPos
;
636 INT Index
= CheckItemToIndex(infoPtr
,
640 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
643 if (Index
<= VisibleFirst
)
649 GetClientRect(infoPtr
->hSelf
,
652 VisibleItems
= (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
;
653 if (Index
- VisibleItems
+ 1 > VisibleFirst
)
655 NewPos
= Index
- VisibleItems
+ 1;
659 NewPos
= VisibleFirst
;
663 if (VisibleFirst
!= NewPos
)
665 SCROLLINFO ScrollInfo
;
667 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
668 ScrollInfo
.fMask
= SIF_POS
;
669 ScrollInfo
.nPos
= NewPos
;
670 NewPos
= SetScrollInfo(infoPtr
->hSelf
,
675 if (VisibleFirst
!= NewPos
)
677 ScrollWindowEx(infoPtr
->hSelf
,
679 (NewPos
- VisibleFirst
) * infoPtr
->ItemHeight
,
684 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
686 RedrawWindow(infoPtr
->hSelf
,
689 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
696 GetIdealItemHeight(IN PCHECKLISTWND infoPtr
)
698 HDC hdc
= GetDC(infoPtr
->hSelf
);
703 HGDIOBJ hOldFont
= SelectObject(hdc
,
706 if(GetTextMetrics(hdc
,
709 height
= tm
.tmHeight
;
719 ReleaseDC(infoPtr
->hSelf
,
728 RetChangeControlFont(IN PCHECKLISTWND infoPtr
,
732 HFONT hOldFont
= infoPtr
->hFont
;
733 infoPtr
->hFont
= hFont
;
735 if (hOldFont
!= hFont
)
737 infoPtr
->ItemHeight
= (2 * CI_TEXT_MARGIN_HEIGHT
) + GetIdealItemHeight(infoPtr
);
740 if (infoPtr
->ShowingCaret
)
743 CreateCaret(infoPtr
->hSelf
,
746 infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
));
749 UpdateControl(infoPtr
);
756 CalculateCheckBoxStyle(IN BOOL Checked
,
765 BtnState
= (Enabled
?
766 (Pushed
? CBS_CHECKEDPRESSED
: (HotTrack
? CBS_CHECKEDHOT
: CBS_CHECKEDNORMAL
)) :
767 CBS_CHECKEDDISABLED
);
771 BtnState
= (Enabled
?
772 (Pushed
? CBS_UNCHECKEDPRESSED
: (HotTrack
? CBS_UNCHECKEDHOT
: CBS_UNCHECKEDNORMAL
)) :
773 CBS_UNCHECKEDDISABLED
);
781 PaintControl(IN PCHECKLISTWND infoPtr
,
786 PCHECKITEM FirstItem
, Item
;
788 UINT VisibleFirstIndex
= rcUpdate
->top
/ infoPtr
->ItemHeight
;
789 UINT LastTouchedIndex
= rcUpdate
->bottom
/ infoPtr
->ItemHeight
;
793 (HBRUSH
)(COLOR_WINDOW
+ 1));
795 GetClientRect(infoPtr
->hSelf
,
798 ScrollPos
= GetScrollPos(infoPtr
->hSelf
,
801 FirstItem
= FindCheckItemByIndex(infoPtr
,
802 ScrollPos
+ VisibleFirstIndex
);
803 if (FirstItem
!= NULL
)
805 RECT TextRect
, ItemRect
, CheckBox
;
808 COLORREF OldTextColor
;
809 BOOL Enabled
, PrevEnabled
, IsPushed
;
816 Enabled
= IsWindowEnabled(infoPtr
->hSelf
);
817 PrevEnabled
= Enabled
;
820 ItemRect
.right
= rcClient
.right
;
821 ItemRect
.top
= VisibleFirstIndex
* infoPtr
->ItemHeight
;
823 TextRect
.left
= ItemRect
.left
+ CI_TEXT_MARGIN_WIDTH
;
824 TextRect
.right
= ItemRect
.right
- CI_TEXT_MARGIN_WIDTH
;
825 TextRect
.top
= ItemRect
.top
+ CI_TEXT_MARGIN_HEIGHT
;
832 OldTextColor
= SetTextColor(hDC
,
833 infoPtr
->TextColor
[Enabled
]);
835 hOldFont
= SelectObject(hDC
,
838 for (Item
= FirstItem
, CurrentIndex
= VisibleFirstIndex
;
839 Item
!= NULL
&& CurrentIndex
<= LastTouchedIndex
;
840 Item
= Item
->Next
, CurrentIndex
++)
842 TextRect
.bottom
= TextRect
.top
+ infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
);
843 ItemRect
.bottom
= ItemRect
.top
+ infoPtr
->ItemHeight
;
850 if (Enabled
&& PrevEnabled
!= ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
))
852 PrevEnabled
= ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
);
855 infoPtr
->TextColor
[PrevEnabled
]);
859 ItemHovered
= (Enabled
&& infoPtr
->HoveredCheckItem
== Item
);
862 if (infoPtr
->QuickSearchHitItem
== Item
)
864 COLORREF OldBkColor
, OldFgColor
;
866 SIZE_T TextLen
, HighlightLen
= wcslen(infoPtr
->QuickSearchText
);
868 /* highlight the quicksearch text */
869 if (GetTextExtentPoint32(hDC
,
874 COLORREF HighlightTextColor
, HighlightBackground
;
875 RECT rcHighlight
= TextRect
;
877 HighlightTextColor
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
878 HighlightBackground
= GetSysColor(COLOR_HIGHLIGHT
);
880 rcHighlight
.right
= rcHighlight
.left
+ TextSize
.cx
;
882 InflateRect(&rcHighlight
,
884 CI_TEXT_SELECTIONMARGIN
);
886 OldBkColor
= SetBkColor(hDC
,
887 HighlightBackground
);
888 OldFgColor
= SetTextColor(hDC
,
891 /* draw the highlighted text */
896 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
903 /* draw the remaining part of the text */
904 TextLen
= wcslen(Item
->Name
);
905 if (HighlightLen
< TextLen
)
907 rcHighlight
.left
= rcHighlight
.right
;
908 rcHighlight
.right
= TextRect
.right
;
911 Item
->Name
+ HighlightLen
,
914 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
925 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
928 CheckBox
.top
= TextRect
.top
;
929 CheckBox
.bottom
= TextRect
.bottom
;
931 /* draw the Allow checkbox */
932 IsPushed
= (Enabled
&& Item
== infoPtr
->FocusedCheckItem
&& infoPtr
->HasFocus
&&
933 !(Item
->State
& CIS_ALLOWDISABLED
) && infoPtr
->FocusedCheckItemBox
!= CLB_DENY
&&
934 infoPtr
->FocusedPushed
);
936 CheckBox
.left
= infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - ((TextRect
.bottom
- TextRect
.top
) / 2);
937 CheckBox
.right
= CheckBox
.left
+ (TextRect
.bottom
- TextRect
.top
);
939 if (infoPtr
->ThemeHandle
!= NULL
)
941 INT BtnState
= CalculateCheckBoxStyle(Item
->State
& CIS_ALLOW
,
942 Enabled
&& !(Item
->State
& CIS_ALLOWDISABLED
),
943 (ItemHovered
&& infoPtr
->HoveredCheckItemBox
!= CLB_DENY
),
947 hDrawResult
= DrawThemeBackground(infoPtr
->ThemeHandle
,
957 hDrawResult
= E_FAIL
;
960 /* draw the standard checkbox if no themes are enabled or drawing the
961 themeed control failed */
962 if (FAILED(hDrawResult
))
965 DrawFrameControl(hDC
,
968 DFCS_BUTTONCHECK
| DFCS_FLAT
|
969 ((Item
->State
& CIS_ALLOWDISABLED
) || !Enabled
? DFCS_INACTIVE
: 0) |
970 ((Item
->State
& CIS_ALLOW
) ? DFCS_CHECKED
: 0) |
971 (IsPushed
? DFCS_PUSHED
: 0));
973 if (Item
== infoPtr
->FocusedCheckItem
&& infoPtr
->FocusVisible
&&
975 infoPtr
->FocusedCheckItemBox
!= CLB_DENY
)
977 RECT rcFocus
= CheckBox
;
979 InflateRect (&rcFocus
,
980 CI_TEXT_MARGIN_HEIGHT
,
981 CI_TEXT_MARGIN_HEIGHT
);
987 /* draw the Deny checkbox */
988 IsPushed
= (Enabled
&& Item
== infoPtr
->FocusedCheckItem
&& infoPtr
->HasFocus
&&
989 !(Item
->State
& CIS_DENYDISABLED
) && infoPtr
->FocusedCheckItemBox
== CLB_DENY
&&
990 infoPtr
->FocusedPushed
);
992 CheckBox
.left
= infoPtr
->CheckBoxLeft
[CLB_DENY
] - ((TextRect
.bottom
- TextRect
.top
) / 2);
993 CheckBox
.right
= CheckBox
.left
+ (TextRect
.bottom
- TextRect
.top
);
995 if (infoPtr
->ThemeHandle
!= NULL
)
997 INT BtnState
= CalculateCheckBoxStyle(Item
->State
& CIS_DENY
,
998 Enabled
&& !(Item
->State
& CIS_DENYDISABLED
),
999 (ItemHovered
&& infoPtr
->HoveredCheckItemBox
== CLB_DENY
),
1002 hDrawResult
= DrawThemeBackground(infoPtr
->ThemeHandle
,
1012 hDrawResult
= E_FAIL
;
1015 /* draw the standard checkbox if no themes are enabled or drawing the
1016 themeed control failed */
1017 if (FAILED(hDrawResult
))
1020 DrawFrameControl(hDC
,
1023 DFCS_BUTTONCHECK
| DFCS_FLAT
|
1024 ((Item
->State
& CIS_DENYDISABLED
) || !Enabled
? DFCS_INACTIVE
: 0) |
1025 ((Item
->State
& CIS_DENY
) ? DFCS_CHECKED
: 0) |
1026 (IsPushed
? DFCS_PUSHED
: 0));
1028 if (infoPtr
->HasFocus
&& infoPtr
->FocusVisible
&&
1029 Item
== infoPtr
->FocusedCheckItem
&&
1030 infoPtr
->FocusedCheckItemBox
== CLB_DENY
)
1032 RECT rcFocus
= CheckBox
;
1034 InflateRect (&rcFocus
,
1035 CI_TEXT_MARGIN_HEIGHT
,
1036 CI_TEXT_MARGIN_HEIGHT
);
1042 TextRect
.top
+= infoPtr
->ItemHeight
;
1043 ItemRect
.top
+= infoPtr
->ItemHeight
;
1060 ChangeCheckItemFocus(IN PCHECKLISTWND infoPtr
,
1061 IN PCHECKITEM NewFocus
,
1062 IN UINT NewFocusBox
)
1064 if (NewFocus
!= infoPtr
->FocusedCheckItem
)
1066 PCHECKITEM OldFocus
= infoPtr
->FocusedCheckItem
;
1067 infoPtr
->FocusedCheckItem
= NewFocus
;
1068 infoPtr
->FocusedCheckItemBox
= NewFocusBox
;
1070 if (OldFocus
!= NULL
)
1072 UpdateCheckItem(infoPtr
,
1078 infoPtr
->FocusedCheckItemBox
= NewFocusBox
;
1081 if (NewFocus
!= NULL
)
1083 MakeCheckItemVisible(infoPtr
,
1085 UpdateCheckItem(infoPtr
,
1091 UpdateCheckItemBox(IN PCHECKLISTWND infoPtr
,
1096 INT VisibleFirst
, VisibleItems
;
1097 INT Index
= CheckItemToIndex(infoPtr
,
1101 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
1104 if (Index
>= VisibleFirst
)
1106 GetClientRect(infoPtr
->hSelf
,
1109 VisibleItems
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
1111 if (Index
<= VisibleFirst
+ VisibleItems
)
1115 rcUpdate
.left
= rcClient
.left
+ infoPtr
->CheckBoxLeft
[ItemBox
] - (infoPtr
->ItemHeight
/ 2);
1116 rcUpdate
.right
= rcUpdate
.left
+ infoPtr
->ItemHeight
;
1117 rcUpdate
.top
= ((Index
- VisibleFirst
) * infoPtr
->ItemHeight
);
1118 rcUpdate
.bottom
= rcUpdate
.top
+ infoPtr
->ItemHeight
;
1120 RedrawWindow(infoPtr
->hSelf
,
1123 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1131 ChangeCheckItemHotTrack(IN PCHECKLISTWND infoPtr
,
1132 IN PCHECKITEM NewHotTrack
,
1133 IN UINT NewHotTrackBox
)
1135 if (NewHotTrack
!= infoPtr
->HoveredCheckItem
)
1137 PCHECKITEM OldHotTrack
= infoPtr
->HoveredCheckItem
;
1138 UINT OldHotTrackBox
= infoPtr
->HoveredCheckItemBox
;
1140 infoPtr
->HoveredCheckItem
= NewHotTrack
;
1141 infoPtr
->HoveredCheckItemBox
= NewHotTrackBox
;
1143 if (OldHotTrack
!= NULL
)
1145 UpdateCheckItemBox(infoPtr
,
1152 infoPtr
->HoveredCheckItemBox
= NewHotTrackBox
;
1155 if (NewHotTrack
!= NULL
)
1157 UpdateCheckItemBox(infoPtr
,
1165 ChangeCheckBox(IN PCHECKLISTWND infoPtr
,
1166 IN PCHECKITEM CheckItem
,
1167 IN UINT CheckItemBox
)
1169 NMCHANGEITEMCHECKBOX CheckData
;
1170 DWORD OldState
= CheckItem
->State
;
1171 DWORD CheckedBit
= ((infoPtr
->FocusedCheckItemBox
== CLB_DENY
) ? CIS_DENY
: CIS_ALLOW
);
1172 BOOL Checked
= (CheckItem
->State
& CheckedBit
) != 0;
1174 CheckData
.OldState
= OldState
;
1175 CheckData
.NewState
= (Checked
? OldState
& ~CheckedBit
: OldState
| CheckedBit
);
1176 CheckData
.CheckBox
= infoPtr
->FocusedCheckItemBox
;
1177 CheckData
.Checked
= !Checked
;
1179 if (NotifyControlParent(infoPtr
,
1180 CLN_CHANGINGITEMCHECKBOX
,
1181 &CheckData
) != (LRESULT
)-1)
1183 CheckItem
->State
= CheckData
.NewState
;
1186 return (CheckItem
->State
!= OldState
);
1190 DisplayCaret(IN PCHECKLISTWND infoPtr
)
1192 if (IsWindowEnabled(infoPtr
->hSelf
) && !infoPtr
->ShowingCaret
)
1194 infoPtr
->ShowingCaret
= TRUE
;
1196 CreateCaret(infoPtr
->hSelf
,
1198 infoPtr
->CaretWidth
,
1199 infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
));
1201 ShowCaret(infoPtr
->hSelf
);
1206 RemoveCaret(IN PCHECKLISTWND infoPtr
)
1208 if (IsWindowEnabled(infoPtr
->hSelf
) && infoPtr
->ShowingCaret
)
1210 infoPtr
->ShowingCaret
= FALSE
;
1212 HideCaret(infoPtr
->hSelf
);
1218 KillQuickSearchTimers(IN PCHECKLISTWND infoPtr
)
1220 KillTimer(infoPtr
->hSelf
,
1221 TIMER_ID_SETHITFOCUS
);
1222 KillTimer(infoPtr
->hSelf
,
1223 TIMER_ID_RESETQUICKSEARCH
);
1227 MapItemToRect(IN PCHECKLISTWND infoPtr
,
1228 IN PCHECKITEM CheckItem
,
1231 INT Index
= CheckItemToIndex(infoPtr
,
1238 GetClientRect(infoPtr
->hSelf
,
1241 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
1244 prcItem
->left
= rcClient
.left
;
1245 prcItem
->right
= rcClient
.right
;
1246 prcItem
->top
= (Index
- VisibleFirst
) * infoPtr
->ItemHeight
;
1247 prcItem
->bottom
= prcItem
->top
+ infoPtr
->ItemHeight
;
1254 prcItem
->bottom
= 0;
1259 UpdateCaretPos(IN PCHECKLISTWND infoPtr
)
1261 if (infoPtr
->ShowingCaret
&& infoPtr
->QuickSearchHitItem
!= NULL
)
1263 HDC hDC
= GetDC(infoPtr
->hSelf
);
1267 HGDIOBJ hOldFont
= SelectObject(hDC
,
1273 if (infoPtr
->QuickSearchText
[0] == L
'\0' ||
1274 GetTextExtentPoint32(hDC
,
1275 infoPtr
->QuickSearchHitItem
->Name
,
1276 wcslen(infoPtr
->QuickSearchText
),
1281 MapItemToRect(infoPtr
,
1282 infoPtr
->QuickSearchHitItem
,
1285 /* actually change the caret position */
1286 SetCaretPos(rcItem
.left
+ CI_TEXT_MARGIN_WIDTH
+ TextSize
.cx
,
1287 rcItem
.top
+ CI_TEXT_MARGIN_HEIGHT
);
1293 ReleaseDC(infoPtr
->hSelf
,
1300 EscapeQuickSearch(IN PCHECKLISTWND infoPtr
)
1302 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
)
1304 PCHECKITEM OldHit
= infoPtr
->QuickSearchHitItem
;
1306 infoPtr
->QuickSearchHitItem
= NULL
;
1307 infoPtr
->QuickSearchText
[0] = L
'\0';
1309 /* scroll back to the focused item */
1310 if (infoPtr
->FocusedCheckItem
!= NULL
)
1312 MakeCheckItemVisible(infoPtr
,
1313 infoPtr
->FocusedCheckItem
);
1316 /* repaint the old search hit item if it's still visible */
1317 UpdateCheckItem(infoPtr
,
1320 KillQuickSearchTimers(infoPtr
);
1322 RemoveCaret(infoPtr
);
1327 ChangeSearchHit(IN PCHECKLISTWND infoPtr
,
1328 IN PCHECKITEM NewHit
)
1330 PCHECKITEM OldHit
= infoPtr
->QuickSearchHitItem
;
1332 infoPtr
->QuickSearchHitItem
= NewHit
;
1334 if (OldHit
!= NewHit
)
1336 /* scroll to the new search hit */
1337 MakeCheckItemVisible(infoPtr
,
1340 /* repaint the old hit if present and visible */
1343 UpdateCheckItem(infoPtr
,
1348 /* show the caret the first time we find an item */
1349 DisplayCaret(infoPtr
);
1353 UpdateCaretPos(infoPtr
);
1355 UpdateCheckItem(infoPtr
,
1358 /* kill the reset timer and restart the set hit focus timer */
1359 KillTimer(infoPtr
->hSelf
,
1360 TIMER_ID_RESETQUICKSEARCH
);
1361 if (infoPtr
->QuickSearchSetFocusDelay
!= 0)
1363 SetTimer(infoPtr
->hSelf
,
1364 TIMER_ID_SETHITFOCUS
,
1365 infoPtr
->QuickSearchSetFocusDelay
,
1371 QuickSearchFindHit(IN PCHECKLISTWND infoPtr
,
1374 if (infoPtr
->QuickSearchEnabled
)
1384 Ret
= infoPtr
->QuickSearchHitItem
!= NULL
;
1387 /* NOTE: QuickSearchHitItem definitely has at least one
1388 enabled check box, the user can't search for disabled
1391 ChangeCheckItemFocus(infoPtr
,
1392 infoPtr
->QuickSearchHitItem
,
1393 ((!(infoPtr
->QuickSearchHitItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
));
1395 EscapeQuickSearch(infoPtr
);
1402 if (infoPtr
->QuickSearchHitItem
!= NULL
)
1404 INT SearchLen
= wcslen(infoPtr
->QuickSearchText
);
1407 /* delete the last character */
1408 infoPtr
->QuickSearchText
[--SearchLen
] = L
'\0';
1413 NewHit
= FindCheckItem(infoPtr
,
1414 infoPtr
->QuickSearchText
);
1418 /* change the search hit */
1419 ChangeSearchHit(infoPtr
,
1429 EscapeQuickSearch(infoPtr
);
1437 INT SearchLen
= wcslen(infoPtr
->QuickSearchText
);
1438 if (SearchLen
< (INT
)(sizeof(infoPtr
->QuickSearchText
) / sizeof(infoPtr
->QuickSearchText
[0])) - 1)
1440 infoPtr
->QuickSearchText
[SearchLen
++] = c
;
1441 infoPtr
->QuickSearchText
[SearchLen
] = L
'\0';
1443 NewHit
= FindCheckItem(infoPtr
,
1444 infoPtr
->QuickSearchText
);
1447 /* change the search hit */
1448 ChangeSearchHit(infoPtr
,
1455 /* reset the input */
1456 infoPtr
->QuickSearchText
[--SearchLen
] = L
'\0';
1468 static LRESULT CALLBACK
1469 CheckListWndProc(IN HWND hwnd
,
1474 PCHECKLISTWND infoPtr
;
1477 infoPtr
= (PCHECKLISTWND
)GetWindowLongPtr(hwnd
,
1480 if (infoPtr
== NULL
&& uMsg
!= WM_CREATE
)
1482 goto HandleDefaultMessage
;
1495 if (GetUpdateRect(hwnd
,
1499 hdc
= (wParam
!= 0 ? (HDC
)wParam
: BeginPaint(hwnd
, &ps
));
1503 PaintControl(infoPtr
,
1521 HWND hWndCapture
= GetCapture();
1523 pt
.x
= (LONG
)LOWORD(lParam
);
1524 pt
.y
= (LONG
)HIWORD(lParam
);
1527 /* handle hovering checkboxes */
1528 if (hWndCapture
== NULL
&& infoPtr
->ThemeHandle
!= NULL
)
1530 TRACKMOUSEEVENT tme
;
1531 PCHECKITEM HotTrackItem
;
1532 UINT HotTrackItemBox
;
1534 HotTrackItem
= PtToCheckItemBox(infoPtr
,
1538 if (HotTrackItem
!= NULL
&& InCheckBox
)
1540 if (infoPtr
->HoveredCheckItem
!= HotTrackItem
||
1541 infoPtr
->HoveredCheckItemBox
!= HotTrackItemBox
)
1543 ChangeCheckItemHotTrack(infoPtr
,
1550 ChangeCheckItemHotTrack(infoPtr
,
1555 tme
.cbSize
= sizeof(tme
);
1556 tme
.dwFlags
= TME_LEAVE
;
1557 tme
.hwndTrack
= hwnd
;
1558 tme
.dwHoverTime
= infoPtr
->HoverTime
;
1560 TrackMouseEvent(&tme
);
1564 if (hWndCapture
== hwnd
&& infoPtr
->FocusedCheckItem
!= NULL
)
1570 PtItem
= PtToCheckItemBox(infoPtr
,
1575 OldPushed
= infoPtr
->FocusedPushed
;
1576 infoPtr
->FocusedPushed
= InCheckBox
&& infoPtr
->FocusedCheckItem
== PtItem
&&
1577 infoPtr
->FocusedCheckItemBox
== PtItemBox
;
1579 if (OldPushed
!= infoPtr
->FocusedPushed
)
1581 UpdateCheckItemBox(infoPtr
,
1582 infoPtr
->FocusedCheckItem
,
1583 infoPtr
->FocusedCheckItemBox
);
1592 SCROLLINFO ScrollInfo
;
1594 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
1595 ScrollInfo
.fMask
= SIF_RANGE
| SIF_POS
;
1597 if (GetScrollInfo(hwnd
,
1601 INT OldPos
= ScrollInfo
.nPos
;
1603 switch (LOWORD(wParam
))
1606 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1610 if (ScrollInfo
.nPos
< ScrollInfo
.nMax
)
1617 if (ScrollInfo
.nPos
> 0)
1628 /* don't use ScrollInfo.nPage because we should only scroll
1629 down by the number of completely visible list entries.
1630 nPage however also includes the partly cropped list
1631 item at the bottom of the control */
1636 ScrollLines
= max(1,
1637 (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
);
1639 if (ScrollInfo
.nPos
+ ScrollLines
<= ScrollInfo
.nMax
)
1641 ScrollInfo
.nPos
+= ScrollLines
;
1645 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1655 /* don't use ScrollInfo.nPage because we should only scroll
1656 down by the number of completely visible list entries.
1657 nPage however also includes the partly cropped list
1658 item at the bottom of the control */
1663 ScrollLines
= max(1,
1664 (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
);
1666 if (ScrollInfo
.nPos
>= ScrollLines
)
1668 ScrollInfo
.nPos
-= ScrollLines
;
1672 ScrollInfo
.nPos
= 0;
1677 case SB_THUMBPOSITION
:
1680 ScrollInfo
.nPos
= HIWORD(wParam
);
1685 ScrollInfo
.nPos
= 0;
1689 if (OldPos
!= ScrollInfo
.nPos
)
1691 ScrollInfo
.fMask
= SIF_POS
;
1693 ScrollInfo
.nPos
= SetScrollInfo(hwnd
,
1698 if (OldPos
!= ScrollInfo
.nPos
)
1700 ScrollWindowEx(hwnd
,
1702 (OldPos
- ScrollInfo
.nPos
) * infoPtr
->ItemHeight
,
1707 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
1712 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1722 PCHECKITEM Item
= AddCheckItem(infoPtr
,
1725 (ACCESS_MASK
)wParam
,
1729 UpdateControl(infoPtr
);
1730 Ret
= (LRESULT
)Index
;
1741 PCHECKITEM Item
= FindCheckItemByIndex(infoPtr
,
1745 Ret
= DeleteCheckItem(infoPtr
,
1749 UpdateControl(infoPtr
);
1759 case CLM_SETITEMSTATE
:
1761 PCHECKITEM Item
= FindCheckItemByIndex(infoPtr
,
1765 DWORD OldState
= Item
->State
;
1766 Item
->State
= (DWORD
)lParam
& CIS_MASK
;
1768 if (Item
->State
!= OldState
)
1770 /* revert the focus if the currently focused item is about
1772 if (Item
== infoPtr
->FocusedCheckItem
&&
1773 (Item
->State
& CIS_DISABLED
))
1775 if (infoPtr
->FocusedCheckItemBox
== CLB_DENY
)
1777 if (Item
->State
& CIS_DENYDISABLED
)
1779 infoPtr
->FocusedCheckItem
= NULL
;
1784 if (Item
->State
& CIS_ALLOWDISABLED
)
1786 infoPtr
->FocusedCheckItem
= NULL
;
1791 UpdateControl(infoPtr
);
1798 case CLM_GETITEMCOUNT
:
1800 Ret
= infoPtr
->CheckItemCount
;
1806 ClearCheckItems(infoPtr
);
1807 UpdateControl(infoPtr
);
1811 case CLM_SETCHECKBOXCOLUMN
:
1813 infoPtr
->CheckBoxLeft
[wParam
!= CLB_DENY
] = (INT
)lParam
;
1814 UpdateControl(infoPtr
);
1819 case CLM_GETCHECKBOXCOLUMN
:
1821 Ret
= (LRESULT
)infoPtr
->CheckBoxLeft
[wParam
!= CLB_DENY
];
1825 case CLM_CLEARCHECKBOXES
:
1827 Ret
= (LRESULT
)ClearCheckBoxes(infoPtr
);
1830 UpdateControl(infoPtr
);
1835 case CLM_ENABLEQUICKSEARCH
:
1839 EscapeQuickSearch(infoPtr
);
1841 infoPtr
->QuickSearchEnabled
= (wParam
!= 0);
1845 case CLM_SETQUICKSEARCH_TIMEOUT_RESET
:
1847 infoPtr
->QuickSearchResetDelay
= (UINT
)wParam
;
1851 case CLM_SETQUICKSEARCH_TIMEOUT_SETFOCUS
:
1853 infoPtr
->QuickSearchSetFocusDelay
= (UINT
)wParam
;
1857 case CLM_FINDITEMBYACCESSMASK
:
1859 Ret
= (LRESULT
)FindCheckItemIndexByAccessMask(infoPtr
,
1860 (ACCESS_MASK
)wParam
);
1866 Ret
= (LRESULT
)RetChangeControlFont(infoPtr
,
1874 Ret
= (LRESULT
)infoPtr
->hFont
;
1878 case WM_STYLECHANGED
:
1880 if (wParam
== (WPARAM
)GWL_STYLE
)
1882 UpdateControl(infoPtr
);
1889 EscapeQuickSearch(infoPtr
);
1891 UpdateControl(infoPtr
);
1898 UINT ScrollLines
= 3;
1900 SystemParametersInfo(SPI_GETWHEELSCROLLLINES
,
1904 ScrollDelta
= 0 - (SHORT
)HIWORD(wParam
);
1906 if (ScrollLines
!= 0 &&
1907 abs(ScrollDelta
) >= WHEEL_DELTA
)
1909 SCROLLINFO ScrollInfo
;
1911 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
1912 ScrollInfo
.fMask
= SIF_RANGE
| SIF_POS
;
1914 if (GetScrollInfo(hwnd
,
1918 INT OldPos
= ScrollInfo
.nPos
;
1920 ScrollInfo
.nPos
+= (ScrollDelta
/ WHEEL_DELTA
) * ScrollLines
;
1921 if (ScrollInfo
.nPos
< 0)
1922 ScrollInfo
.nPos
= 0;
1923 else if (ScrollInfo
.nPos
> ScrollInfo
.nMax
)
1924 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1926 if (OldPos
!= ScrollInfo
.nPos
)
1928 ScrollInfo
.fMask
= SIF_POS
;
1930 ScrollInfo
.nPos
= SetScrollInfo(hwnd
,
1935 if (OldPos
!= ScrollInfo
.nPos
)
1937 ScrollWindowEx(hwnd
,
1939 (OldPos
- ScrollInfo
.nPos
) * infoPtr
->ItemHeight
,
1944 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
1949 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1959 infoPtr
->HasFocus
= TRUE
;
1961 if (infoPtr
->FocusedCheckItem
== NULL
)
1963 BOOL Shift
= GetKeyState(VK_SHIFT
) & 0x8000;
1964 infoPtr
->FocusedCheckItem
= FindEnabledCheckBox(infoPtr
,
1966 &infoPtr
->FocusedCheckItemBox
);
1968 if (infoPtr
->FocusedCheckItem
!= NULL
)
1970 MakeCheckItemVisible(infoPtr
,
1971 infoPtr
->FocusedCheckItem
);
1973 UpdateCheckItem(infoPtr
,
1974 infoPtr
->FocusedCheckItem
);
1981 EscapeQuickSearch(infoPtr
);
1983 infoPtr
->HasFocus
= FALSE
;
1984 if (infoPtr
->FocusedCheckItem
!= NULL
)
1986 infoPtr
->FocusedPushed
= FALSE
;
1988 UpdateCheckItem(infoPtr
,
1989 infoPtr
->FocusedCheckItem
);
1994 case WM_LBUTTONDBLCLK
:
1995 case WM_LBUTTONDOWN
:
1996 case WM_MBUTTONDOWN
:
1997 case WM_RBUTTONDOWN
:
1999 if (IsWindowEnabled(hwnd
))
2001 PCHECKITEM NewFocus
;
2002 UINT NewFocusBox
= 0;
2005 BOOL ChangeFocus
, Capture
= FALSE
;
2007 pt
.x
= (LONG
)LOWORD(lParam
);
2008 pt
.y
= (LONG
)HIWORD(lParam
);
2010 NewFocus
= PtToCheckItemBox(infoPtr
,
2014 if (NewFocus
!= NULL
)
2016 if (NewFocus
->State
& ((NewFocusBox
!= CLB_DENY
) ? CIS_ALLOWDISABLED
: CIS_DENYDISABLED
))
2018 /* the user clicked on a disabled checkbox, try to set
2019 the focus to the other one or not change it at all */
2023 ChangeFocus
= ((NewFocus
->State
& CIS_DISABLED
) != CIS_DISABLED
);
2026 NewFocusBox
= ((NewFocusBox
!= CLB_DENY
) ? CLB_DENY
: CLB_ALLOW
);
2034 if (InCheckBox
&& ChangeFocus
&& GetCapture() == NULL
&&
2035 (uMsg
== WM_LBUTTONDOWN
|| uMsg
== WM_LBUTTONDBLCLK
))
2037 infoPtr
->FocusedPushed
= TRUE
;
2048 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
&&
2049 infoPtr
->QuickSearchHitItem
!= NewFocus
)
2051 EscapeQuickSearch(infoPtr
);
2054 ChangeCheckItemFocus(infoPtr
,
2059 if (!infoPtr
->HasFocus
)
2074 if (GetCapture() == hwnd
)
2076 if (infoPtr
->FocusedCheckItem
!= NULL
&& infoPtr
->FocusedPushed
)
2083 pt
.x
= (LONG
)LOWORD(lParam
);
2084 pt
.y
= (LONG
)HIWORD(lParam
);
2086 infoPtr
->FocusedPushed
= FALSE
;
2088 PtItem
= PtToCheckItemBox(infoPtr
,
2093 if (PtItem
== infoPtr
->FocusedCheckItem
&& InCheckBox
&&
2094 PtItemBox
== infoPtr
->FocusedCheckItemBox
)
2096 UINT OtherBox
= ((PtItemBox
== CLB_ALLOW
) ? CLB_DENY
: CLB_ALLOW
);
2097 DWORD OtherStateMask
= ((OtherBox
== CLB_ALLOW
) ?
2098 (CIS_ALLOW
| CIS_ALLOWDISABLED
) :
2099 (CIS_DENY
| CIS_DENYDISABLED
));
2100 DWORD OtherStateOld
= PtItem
->State
& OtherStateMask
;
2101 if (ChangeCheckBox(infoPtr
,
2104 ((PtItem
->State
& OtherStateMask
) != OtherStateOld
))
2106 UpdateCheckItemBox(infoPtr
,
2107 infoPtr
->FocusedCheckItem
,
2112 UpdateCheckItemBox(infoPtr
,
2113 infoPtr
->FocusedCheckItem
,
2114 infoPtr
->FocusedCheckItemBox
);
2128 if (GetCapture() == NULL
&&
2129 !QuickSearchFindHit(infoPtr
,
2132 if (infoPtr
->FocusedCheckItem
!= NULL
&&
2133 (infoPtr
->QuickSearchHitItem
== NULL
||
2134 infoPtr
->QuickSearchHitItem
== infoPtr
->FocusedCheckItem
))
2136 BOOL OldPushed
= infoPtr
->FocusedPushed
;
2137 infoPtr
->FocusedPushed
= TRUE
;
2139 if (infoPtr
->FocusedPushed
!= OldPushed
)
2141 MakeCheckItemVisible(infoPtr
,
2142 infoPtr
->FocusedCheckItem
);
2144 UpdateCheckItemBox(infoPtr
,
2145 infoPtr
->FocusedCheckItem
,
2146 infoPtr
->FocusedCheckItemBox
);
2155 if (GetCapture() == NULL
&&
2156 !QuickSearchFindHit(infoPtr
,
2159 if (infoPtr
->FocusedCheckItem
!= NULL
&&
2160 infoPtr
->QuickSearchHitItem
== NULL
)
2163 DWORD OtherStateMask
;
2164 DWORD OtherStateOld
;
2166 MakeCheckItemVisible(infoPtr
,
2167 infoPtr
->FocusedCheckItem
);
2169 OtherBox
= ((infoPtr
->FocusedCheckItemBox
== CLB_ALLOW
) ? CLB_DENY
: CLB_ALLOW
);
2170 OtherStateMask
= ((OtherBox
== CLB_ALLOW
) ?
2171 (CIS_ALLOW
| CIS_ALLOWDISABLED
) :
2172 (CIS_DENY
| CIS_DENYDISABLED
));
2173 OtherStateOld
= infoPtr
->FocusedCheckItem
->State
& OtherStateMask
;
2174 if (ChangeCheckBox(infoPtr
,
2175 infoPtr
->FocusedCheckItem
,
2176 infoPtr
->FocusedCheckItemBox
))
2178 UpdateCheckItemBox(infoPtr
,
2179 infoPtr
->FocusedCheckItem
,
2180 infoPtr
->FocusedCheckItemBox
);
2181 if ((infoPtr
->FocusedCheckItem
->State
& OtherStateMask
) != OtherStateOld
)
2183 UpdateCheckItemBox(infoPtr
,
2184 infoPtr
->FocusedCheckItem
,
2195 if (GetCapture() == NULL
)
2197 PCHECKITEM NewFocus
;
2198 UINT NewFocusBox
= 0;
2199 BOOL Shift
= GetKeyState(VK_SHIFT
) & 0x8000;
2201 EscapeQuickSearch(infoPtr
);
2203 NewFocus
= FindEnabledCheckBox(infoPtr
,
2207 if (!infoPtr
->FocusVisible
)
2209 /* change the UI status */
2210 SendMessage(GetAncestor(hwnd
,
2213 MAKEWPARAM(UIS_INITIALIZE
,
2218 ChangeCheckItemFocus(infoPtr
,
2227 goto HandleDefaultMessage
;
2235 if (wParam
== VK_SPACE
&& IsWindowEnabled(hwnd
) &&
2236 infoPtr
->FocusedCheckItem
!= NULL
&&
2237 infoPtr
->FocusedPushed
)
2239 UINT OtherBox
= ((infoPtr
->FocusedCheckItemBox
== CLB_ALLOW
) ? CLB_DENY
: CLB_ALLOW
);
2240 DWORD OtherStateMask
= ((OtherBox
== CLB_ALLOW
) ?
2241 (CIS_ALLOW
| CIS_ALLOWDISABLED
) :
2242 (CIS_DENY
| CIS_DENYDISABLED
));
2243 DWORD OtherStateOld
= infoPtr
->FocusedCheckItem
->State
& OtherStateMask
;
2245 infoPtr
->FocusedPushed
= FALSE
;
2247 if (ChangeCheckBox(infoPtr
,
2248 infoPtr
->FocusedCheckItem
,
2249 infoPtr
->FocusedCheckItemBox
))
2251 UpdateCheckItemBox(infoPtr
,
2252 infoPtr
->FocusedCheckItem
,
2253 infoPtr
->FocusedCheckItemBox
);
2255 if ((infoPtr
->FocusedCheckItem
->State
& OtherStateMask
) != OtherStateOld
)
2257 UpdateCheckItemBox(infoPtr
,
2258 infoPtr
->FocusedCheckItem
,
2271 virtKey
= (lParam
!= 0 ? (INT
)((LPMSG
)lParam
)->wParam
: 0);
2276 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
)
2278 Ret
|= DLGC_WANTCHARS
| DLGC_WANTMESSAGE
;
2282 Ret
|= DLGC_WANTMESSAGE
;
2291 BOOL Shift
= GetKeyState(VK_SHIFT
) & 0x8000;
2293 EnabledBox
= FindEnabledCheckBox(infoPtr
,
2296 Ret
|= (EnabledBox
? DLGC_WANTTAB
: DLGC_WANTCHARS
);
2302 if (infoPtr
->QuickSearchEnabled
)
2304 Ret
|= DLGC_WANTCHARS
;
2314 QuickSearchFindHit(infoPtr
,
2319 case WM_SYSCOLORCHANGE
:
2321 infoPtr
->TextColor
[0] = GetSysColor(COLOR_GRAYTEXT
);
2322 infoPtr
->TextColor
[1] = GetSysColor(COLOR_WINDOWTEXT
);
2329 if (infoPtr
->HoveredCheckItem
!= NULL
)
2331 /* reset and repaint the hovered check item box */
2332 ChangeCheckItemHotTrack(infoPtr
,
2339 case WM_THEMECHANGED
:
2341 if (infoPtr
->ThemeHandle
!= NULL
)
2343 CloseThemeData(infoPtr
->ThemeHandle
);
2344 infoPtr
->ThemeHandle
= NULL
;
2348 infoPtr
->ThemeHandle
= OpenThemeData(infoPtr
->hSelf
,
2355 case WM_SETTINGCHANGE
:
2357 DWORD OldCaretWidth
= infoPtr
->CaretWidth
;
2360 /* update the hover time */
2361 if (!SystemParametersInfo(SPI_GETMOUSEHOVERTIME
,
2363 &infoPtr
->HoverTime
,
2366 infoPtr
->HoverTime
= HOVER_DEFAULT
;
2370 /* update the caret */
2371 if (!SystemParametersInfo(SPI_GETCARETWIDTH
,
2373 &infoPtr
->CaretWidth
,
2376 infoPtr
->CaretWidth
= 2;
2378 if (OldCaretWidth
!= infoPtr
->CaretWidth
&& infoPtr
->ShowingCaret
)
2383 infoPtr
->CaretWidth
,
2384 infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
));
2391 UpdateControl(infoPtr
);
2395 case WM_UPDATEUISTATE
:
2397 if (HIWORD(wParam
) & UISF_HIDEFOCUS
)
2399 BOOL OldFocusVisible
= infoPtr
->FocusVisible
;
2401 infoPtr
->FocusVisible
= (LOWORD(wParam
) == UIS_CLEAR
);
2403 if (infoPtr
->FocusVisible
!= OldFocusVisible
&&
2404 infoPtr
->FocusedCheckItem
!= NULL
)
2406 UpdateCheckItemBox(infoPtr
,
2407 infoPtr
->FocusedCheckItem
,
2408 infoPtr
->FocusedCheckItemBox
);
2418 case TIMER_ID_SETHITFOCUS
:
2420 /* kill the timer */
2424 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
)
2426 /* change the focus to the hit item, this item has to have
2427 at least one enabled checkbox! */
2428 ChangeCheckItemFocus(infoPtr
,
2429 infoPtr
->QuickSearchHitItem
,
2430 ((!(infoPtr
->QuickSearchHitItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
));
2432 /* start the timer to reset quicksearch */
2433 if (infoPtr
->QuickSearchResetDelay
!= 0)
2436 TIMER_ID_RESETQUICKSEARCH
,
2437 infoPtr
->QuickSearchResetDelay
,
2443 case TIMER_ID_RESETQUICKSEARCH
:
2445 /* kill the timer */
2449 /* escape quick search */
2450 EscapeQuickSearch(infoPtr
);
2459 infoPtr
= HeapAlloc(GetProcessHeap(),
2461 sizeof(CHECKLISTWND
));
2462 if (infoPtr
!= NULL
)
2466 infoPtr
->hSelf
= hwnd
;
2467 infoPtr
->hNotify
= ((LPCREATESTRUCTW
)lParam
)->hwndParent
;
2469 SetWindowLongPtr(hwnd
,
2471 (DWORD_PTR
)infoPtr
);
2473 infoPtr
->CheckItemListHead
= NULL
;
2474 infoPtr
->CheckItemCount
= 0;
2476 if (!SystemParametersInfo(SPI_GETCARETWIDTH
,
2478 &infoPtr
->CaretWidth
,
2481 infoPtr
->CaretWidth
= 2;
2483 infoPtr
->ItemHeight
= 10;
2484 infoPtr
->ShowingCaret
= FALSE
;
2486 infoPtr
->HasFocus
= FALSE
;
2487 infoPtr
->FocusedCheckItem
= NULL
;
2488 infoPtr
->FocusedCheckItemBox
= 0;
2489 infoPtr
->FocusedPushed
= FALSE
;
2491 infoPtr
->TextColor
[0] = GetSysColor(COLOR_GRAYTEXT
);
2492 infoPtr
->TextColor
[1] = GetSysColor(COLOR_WINDOWTEXT
);
2497 infoPtr
->CheckBoxLeft
[0] = rcClient
.right
- 30;
2498 infoPtr
->CheckBoxLeft
[1] = rcClient
.right
- 15;
2500 infoPtr
->QuickSearchEnabled
= FALSE
;
2501 infoPtr
->QuickSearchText
[0] = L
'\0';
2503 infoPtr
->QuickSearchSetFocusDelay
= DEFAULT_QUICKSEARCH_SETFOCUS_DELAY
;
2504 infoPtr
->QuickSearchResetDelay
= DEFAULT_QUICKSEARCH_RESET_DELAY
;
2507 infoPtr
->HoveredCheckItem
= NULL
;
2508 infoPtr
->HoveredCheckItemBox
= 0;
2509 if (!SystemParametersInfo(SPI_GETMOUSEHOVERTIME
,
2511 &infoPtr
->HoverTime
,
2514 infoPtr
->HoverTime
= HOVER_DEFAULT
;
2519 infoPtr
->ThemeHandle
= OpenThemeData(infoPtr
->hSelf
,
2524 infoPtr
->ThemeHandle
= NULL
;
2528 infoPtr
->FocusVisible
= !(SendMessage(hwnd
,
2531 0) & UISF_HIDEFOCUS
);
2542 if (infoPtr
->ShowingCaret
)
2547 ClearCheckItems(infoPtr
);
2550 if (infoPtr
->ThemeHandle
!= NULL
)
2552 CloseThemeData(infoPtr
->ThemeHandle
);
2556 HeapFree(GetProcessHeap(),
2559 SetWindowLongPtr(hwnd
,
2567 HandleDefaultMessage
:
2568 Ret
= DefWindowProc(hwnd
,
2580 RegisterCheckListControl(IN HINSTANCE hInstance
)
2584 wc
.style
= CS_DBLCLKS
;
2585 wc
.lpfnWndProc
= CheckListWndProc
;
2587 wc
.cbWndExtra
= sizeof(PCHECKLISTWND
);
2588 wc
.hInstance
= hInstance
;
2590 wc
.hCursor
= LoadCursor(NULL
,
2592 wc
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
2593 wc
.lpszMenuName
= NULL
;
2594 wc
.lpszClassName
= L
"CHECKLIST_ACLUI";
2596 return RegisterClass(&wc
) != 0;
2600 UnregisterCheckListControl(VOID
)
2602 UnregisterClass(L
"CHECKLIST_ACLUI",