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
20 * PROJECT: ReactOS Access Control List Editor
21 * FILE: lib/aclui/checklist.c
22 * PURPOSE: Access Control List Editor
23 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
33 static const WCHAR szCheckListWndClass
[] = L
"CHECKLIST_ACLUI";
35 #define CI_TEXT_MARGIN_WIDTH (8)
36 #define CI_TEXT_MARGIN_HEIGHT (3)
37 #define CI_TEXT_SELECTIONMARGIN (1)
39 #define TIMER_ID_SETHITFOCUS (1)
40 #define TIMER_ID_RESETQUICKSEARCH (2)
42 #define DEFAULT_QUICKSEARCH_SETFOCUS_DELAY (2000)
43 #define DEFAULT_QUICKSEARCH_RESET_DELAY (3000)
45 typedef struct _CHECKITEM
47 struct _CHECKITEM
*Next
;
48 ACCESS_MASK AccessMask
;
51 } CHECKITEM
, *PCHECKITEM
;
53 typedef struct _CHECKLISTWND
59 PCHECKITEM CheckItemListHead
;
64 PCHECKITEM FocusedCheckItem
;
65 UINT FocusedCheckItemBox
;
67 COLORREF TextColor
[2];
70 PCHECKITEM QuickSearchHitItem
;
71 WCHAR QuickSearchText
[65];
72 UINT QuickSearchSetFocusDelay
;
73 UINT QuickSearchResetDelay
;
80 PCHECKITEM HoveredCheckItem
;
81 UINT HoveredCheckItemBox
;
88 UINT FocusedPushed
: 1;
89 UINT QuickSearchEnabled
: 1;
90 UINT ShowingCaret
: 1;
91 } CHECKLISTWND
, *PCHECKLISTWND
;
93 static VOID
EscapeQuickSearch(IN PCHECKLISTWND infoPtr
);
95 static VOID
ChangeCheckItemHotTrack(IN PCHECKLISTWND infoPtr
,
96 IN PCHECKITEM NewHotTrack
,
97 IN UINT NewHotTrackBox
);
99 static VOID
ChangeCheckItemFocus(IN PCHECKLISTWND infoPtr
,
100 IN PCHECKITEM NewFocus
,
101 IN UINT NewFocusBox
);
103 /******************************************************************************/
106 NotifyControlParent(IN PCHECKLISTWND infoPtr
,
112 if (infoPtr
->hNotify
!= NULL
)
114 LPNMHDR pnmh
= (LPNMHDR
)data
;
116 pnmh
->hwndFrom
= infoPtr
->hSelf
;
117 pnmh
->idFrom
= GetWindowLongPtr(infoPtr
->hSelf
,
121 Ret
= SendMessage(infoPtr
->hNotify
,
123 (WPARAM
)pnmh
->idFrom
,
131 FindCheckItemByIndex(IN PCHECKLISTWND infoPtr
,
134 PCHECKITEM Item
, Found
= NULL
;
138 for (Item
= infoPtr
->CheckItemListHead
;
156 FindCheckItemIndexByAccessMask(IN PCHECKLISTWND infoPtr
,
157 IN ACCESS_MASK AccessMask
)
160 INT Index
= 0, Found
= -1;
162 for (Item
= infoPtr
->CheckItemListHead
;
166 if (Item
->AccessMask
== AccessMask
)
179 CheckItemToIndex(IN PCHECKLISTWND infoPtr
,
185 for (CurItem
= infoPtr
->CheckItemListHead
, Index
= 0;
187 CurItem
= CurItem
->Next
, Index
++)
199 FindCheckItem(IN PCHECKLISTWND infoPtr
,
200 IN LPWSTR SearchText
)
203 SIZE_T Count
= wcslen(SearchText
);
205 for (CurItem
= infoPtr
->CheckItemListHead
;
207 CurItem
= CurItem
->Next
)
209 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
&&
210 !_wcsnicmp(CurItem
->Name
,
221 FindFirstEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
226 for (CurItem
= infoPtr
->CheckItemListHead
;
228 CurItem
= CurItem
->Next
)
230 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
232 /* return the Allow checkbox in case both check boxes are enabled! */
233 *CheckBox
= ((!(CurItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
);
242 FindLastEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
246 PCHECKITEM LastEnabledItem
= NULL
;
248 for (CurItem
= infoPtr
->CheckItemListHead
;
250 CurItem
= CurItem
->Next
)
252 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
254 LastEnabledItem
= CurItem
;
258 if (LastEnabledItem
!= NULL
)
260 /* return the Deny checkbox in case both check boxes are enabled! */
261 *CheckBox
= ((!(LastEnabledItem
->State
& CIS_DENYDISABLED
)) ? CLB_DENY
: CLB_ALLOW
);
264 return LastEnabledItem
;
268 FindPreviousEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
273 if (infoPtr
->FocusedCheckItem
!= NULL
)
275 Item
= infoPtr
->FocusedCheckItem
;
277 if (infoPtr
->FocusedCheckItemBox
== CLB_DENY
&&
278 !(Item
->State
& CIS_ALLOWDISABLED
))
280 /* currently an Deny checkbox is focused. return the Allow checkbox
282 *CheckBox
= CLB_ALLOW
;
290 for (CurItem
= infoPtr
->CheckItemListHead
;
291 CurItem
!= infoPtr
->FocusedCheckItem
;
292 CurItem
= CurItem
->Next
)
294 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
302 /* return the Deny checkbox in case both check boxes are enabled! */
303 *CheckBox
= ((!(Item
->State
& CIS_DENYDISABLED
)) ? CLB_DENY
: CLB_ALLOW
);
309 Item
= FindLastEnabledCheckBox(infoPtr
,
317 FindNextEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
322 if (infoPtr
->FocusedCheckItem
!= NULL
)
324 Item
= infoPtr
->FocusedCheckItem
;
326 if (infoPtr
->FocusedCheckItemBox
!= CLB_DENY
&&
327 !(Item
->State
& CIS_DENYDISABLED
))
329 /* currently an Allow checkbox is focused. return the Deny checkbox
331 *CheckBox
= CLB_DENY
;
339 if ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
)
341 /* return the Allow checkbox in case both check boxes are enabled! */
342 *CheckBox
= ((!(Item
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
);
352 Item
= FindFirstEnabledCheckBox(infoPtr
,
360 FindEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
361 IN BOOL ReverseSearch
,
368 Item
= FindPreviousEnabledCheckBox(infoPtr
,
373 Item
= FindNextEnabledCheckBox(infoPtr
,
381 PtToCheckItemBox(IN PCHECKLISTWND infoPtr
,
384 OUT BOOL
*DirectlyInCheckBox
)
386 INT FirstVisible
, Index
;
389 FirstVisible
= GetScrollPos(infoPtr
->hSelf
,
392 Index
= FirstVisible
+ (ppt
->y
/ infoPtr
->ItemHeight
);
394 Item
= FindCheckItemByIndex(infoPtr
,
400 cx
= infoPtr
->CheckBoxLeft
[CLB_ALLOW
] +
401 ((infoPtr
->CheckBoxLeft
[CLB_DENY
] - infoPtr
->CheckBoxLeft
[CLB_ALLOW
]) / 2);
403 *CheckBox
= ((ppt
->x
<= cx
) ? CLB_ALLOW
: CLB_DENY
);
405 if (DirectlyInCheckBox
!= NULL
)
407 INT y
= ppt
->y
% infoPtr
->ItemHeight
;
408 INT cxBox
= infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
);
410 if ((y
>= CI_TEXT_MARGIN_HEIGHT
&&
411 y
< infoPtr
->ItemHeight
- CI_TEXT_MARGIN_HEIGHT
) &&
413 (((ppt
->x
>= (infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - (cxBox
/ 2))) &&
414 (ppt
->x
< (infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - (cxBox
/ 2) + cxBox
)))
416 ((ppt
->x
>= (infoPtr
->CheckBoxLeft
[CLB_DENY
] - (cxBox
/ 2))) &&
417 (ppt
->x
< (infoPtr
->CheckBoxLeft
[CLB_DENY
] - (cxBox
/ 2) + cxBox
)))))
419 *DirectlyInCheckBox
= TRUE
;
423 *DirectlyInCheckBox
= FALSE
;
432 ClearCheckItems(IN PCHECKLISTWND infoPtr
)
434 PCHECKITEM CurItem
, NextItem
;
436 CurItem
= infoPtr
->CheckItemListHead
;
437 while (CurItem
!= NULL
)
439 NextItem
= CurItem
->Next
;
440 HeapFree(GetProcessHeap(),
446 infoPtr
->CheckItemListHead
= NULL
;
447 infoPtr
->CheckItemCount
= 0;
451 DeleteCheckItem(IN PCHECKLISTWND infoPtr
,
455 PCHECKITEM
*PrevPtr
= &infoPtr
->CheckItemListHead
;
457 for (CurItem
= infoPtr
->CheckItemListHead
;
459 CurItem
= CurItem
->Next
)
463 if (Item
== infoPtr
->QuickSearchHitItem
&& infoPtr
->QuickSearchEnabled
)
465 EscapeQuickSearch(infoPtr
);
469 if (Item
== infoPtr
->HoveredCheckItem
)
471 ChangeCheckItemHotTrack(infoPtr
,
477 if (Item
== infoPtr
->FocusedCheckItem
)
479 ChangeCheckItemFocus(infoPtr
,
484 *PrevPtr
= CurItem
->Next
;
485 HeapFree(GetProcessHeap(),
488 infoPtr
->CheckItemCount
--;
492 PrevPtr
= &CurItem
->Next
;
499 AddCheckItem(IN PCHECKLISTWND infoPtr
,
502 IN ACCESS_MASK AccessMask
,
507 PCHECKITEM
*PrevPtr
= &infoPtr
->CheckItemListHead
;
508 PCHECKITEM Item
= HeapAlloc(GetProcessHeap(),
510 sizeof(CHECKITEM
) + (wcslen(Name
) * sizeof(WCHAR
)));
513 for (CurItem
= infoPtr
->CheckItemListHead
, i
= 0;
515 CurItem
= CurItem
->Next
)
517 PrevPtr
= &CurItem
->Next
;
522 Item
->AccessMask
= AccessMask
;
523 Item
->State
= State
& CIS_MASK
;
528 infoPtr
->CheckItemCount
++;
540 ClearCheckBoxes(IN PCHECKLISTWND infoPtr
)
545 for (CurItem
= infoPtr
->CheckItemListHead
;
547 CurItem
= CurItem
->Next
)
549 if (CurItem
->State
& (CIS_ALLOW
| CIS_DENY
))
551 CurItem
->State
&= ~(CIS_ALLOW
| CIS_DENY
);
560 UpdateControl(IN PCHECKLISTWND infoPtr
)
563 SCROLLINFO ScrollInfo
;
566 GetClientRect(infoPtr
->hSelf
,
569 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
570 ScrollInfo
.fMask
= SIF_PAGE
| SIF_RANGE
;
572 ScrollInfo
.nMax
= infoPtr
->CheckItemCount
;
573 ScrollInfo
.nPage
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
575 ScrollInfo
.nTrackPos
= 0;
577 VisibleItems
= (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
;
579 if (ScrollInfo
.nPage
== (UINT
)VisibleItems
&& ScrollInfo
.nMax
> 0)
584 SetScrollInfo(infoPtr
->hSelf
,
589 RedrawWindow(infoPtr
->hSelf
,
592 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
596 UpdateCheckItem(IN PCHECKLISTWND infoPtr
,
600 INT VisibleFirst
, VisibleItems
;
601 INT Index
= CheckItemToIndex(infoPtr
,
605 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
608 if (Index
>= VisibleFirst
)
610 GetClientRect(infoPtr
->hSelf
,
613 VisibleItems
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
615 if (Index
<= VisibleFirst
+ VisibleItems
)
619 rcUpdate
.left
= rcClient
.left
;
620 rcUpdate
.right
= rcClient
.right
;
621 rcUpdate
.top
= (Index
- VisibleFirst
) * infoPtr
->ItemHeight
;
622 rcUpdate
.bottom
= rcUpdate
.top
+ infoPtr
->ItemHeight
;
624 RedrawWindow(infoPtr
->hSelf
,
627 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
634 MakeCheckItemVisible(IN PCHECKLISTWND infoPtr
,
638 INT VisibleFirst
, VisibleItems
, NewPos
;
639 INT Index
= CheckItemToIndex(infoPtr
,
643 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
646 if (Index
<= VisibleFirst
)
652 GetClientRect(infoPtr
->hSelf
,
655 VisibleItems
= (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
;
656 if (Index
- VisibleItems
+ 1 > VisibleFirst
)
658 NewPos
= Index
- VisibleItems
+ 1;
662 NewPos
= VisibleFirst
;
666 if (VisibleFirst
!= NewPos
)
668 SCROLLINFO ScrollInfo
;
670 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
671 ScrollInfo
.fMask
= SIF_POS
;
672 ScrollInfo
.nPos
= NewPos
;
673 NewPos
= SetScrollInfo(infoPtr
->hSelf
,
678 if (VisibleFirst
!= NewPos
)
680 ScrollWindowEx(infoPtr
->hSelf
,
682 (NewPos
- VisibleFirst
) * infoPtr
->ItemHeight
,
687 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
689 RedrawWindow(infoPtr
->hSelf
,
692 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
699 GetIdealItemHeight(IN PCHECKLISTWND infoPtr
)
701 HDC hdc
= GetDC(infoPtr
->hSelf
);
706 HGDIOBJ hOldFont
= SelectObject(hdc
,
709 if(GetTextMetrics(hdc
,
712 height
= tm
.tmHeight
;
722 ReleaseDC(infoPtr
->hSelf
,
731 RetChangeControlFont(IN PCHECKLISTWND infoPtr
,
735 HFONT hOldFont
= infoPtr
->hFont
;
736 infoPtr
->hFont
= hFont
;
738 if (hOldFont
!= hFont
)
740 infoPtr
->ItemHeight
= (2 * CI_TEXT_MARGIN_HEIGHT
) + GetIdealItemHeight(infoPtr
);
743 if (infoPtr
->ShowingCaret
)
746 CreateCaret(infoPtr
->hSelf
,
749 infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
));
752 UpdateControl(infoPtr
);
759 CalculateCheckBoxStyle(IN BOOL Checked
,
768 BtnState
= (Enabled
?
769 (Pushed
? CBS_CHECKEDPRESSED
: (HotTrack
? CBS_CHECKEDHOT
: CBS_CHECKEDNORMAL
)) :
770 CBS_CHECKEDDISABLED
);
774 BtnState
= (Enabled
?
775 (Pushed
? CBS_UNCHECKEDPRESSED
: (HotTrack
? CBS_UNCHECKEDHOT
: CBS_UNCHECKEDNORMAL
)) :
776 CBS_UNCHECKEDDISABLED
);
784 PaintControl(IN PCHECKLISTWND infoPtr
,
789 PCHECKITEM FirstItem
, Item
;
791 UINT VisibleFirstIndex
= rcUpdate
->top
/ infoPtr
->ItemHeight
;
792 UINT LastTouchedIndex
= rcUpdate
->bottom
/ infoPtr
->ItemHeight
;
796 (HBRUSH
)(COLOR_WINDOW
+ 1));
798 GetClientRect(infoPtr
->hSelf
,
801 ScrollPos
= GetScrollPos(infoPtr
->hSelf
,
804 FirstItem
= FindCheckItemByIndex(infoPtr
,
805 ScrollPos
+ VisibleFirstIndex
);
806 if (FirstItem
!= NULL
)
808 RECT TextRect
, ItemRect
, CheckBox
;
811 COLORREF OldTextColor
;
812 BOOL Enabled
, PrevEnabled
, IsPushed
;
819 Enabled
= IsWindowEnabled(infoPtr
->hSelf
);
820 PrevEnabled
= Enabled
;
823 ItemRect
.right
= rcClient
.right
;
824 ItemRect
.top
= VisibleFirstIndex
* infoPtr
->ItemHeight
;
826 TextRect
.left
= ItemRect
.left
+ CI_TEXT_MARGIN_WIDTH
;
827 TextRect
.right
= ItemRect
.right
- CI_TEXT_MARGIN_WIDTH
;
828 TextRect
.top
= ItemRect
.top
+ CI_TEXT_MARGIN_HEIGHT
;
835 OldTextColor
= SetTextColor(hDC
,
836 infoPtr
->TextColor
[Enabled
]);
838 hOldFont
= SelectObject(hDC
,
841 for (Item
= FirstItem
, CurrentIndex
= VisibleFirstIndex
;
842 Item
!= NULL
&& CurrentIndex
<= LastTouchedIndex
;
843 Item
= Item
->Next
, CurrentIndex
++)
845 TextRect
.bottom
= TextRect
.top
+ infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
);
846 ItemRect
.bottom
= ItemRect
.top
+ infoPtr
->ItemHeight
;
853 if (Enabled
&& PrevEnabled
!= ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
))
855 PrevEnabled
= ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
);
858 infoPtr
->TextColor
[PrevEnabled
]);
862 ItemHovered
= (Enabled
&& infoPtr
->HoveredCheckItem
== Item
);
865 if (infoPtr
->QuickSearchHitItem
== Item
)
867 COLORREF OldBkColor
, OldFgColor
;
869 SIZE_T TextLen
, HighlightLen
= wcslen(infoPtr
->QuickSearchText
);
871 /* highlight the quicksearch text */
872 if (GetTextExtentPoint32(hDC
,
877 COLORREF HighlightTextColor
, HighlightBackground
;
878 RECT rcHighlight
= TextRect
;
880 HighlightTextColor
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
881 HighlightBackground
= GetSysColor(COLOR_HIGHLIGHT
);
883 rcHighlight
.right
= rcHighlight
.left
+ TextSize
.cx
;
885 InflateRect(&rcHighlight
,
887 CI_TEXT_SELECTIONMARGIN
);
889 OldBkColor
= SetBkColor(hDC
,
890 HighlightBackground
);
891 OldFgColor
= SetTextColor(hDC
,
894 /* draw the highlighted text */
899 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
906 /* draw the remaining part of the text */
907 TextLen
= wcslen(Item
->Name
);
908 if (HighlightLen
< TextLen
)
910 rcHighlight
.left
= rcHighlight
.right
;
911 rcHighlight
.right
= TextRect
.right
;
914 Item
->Name
+ HighlightLen
,
917 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
928 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
931 CheckBox
.top
= TextRect
.top
;
932 CheckBox
.bottom
= TextRect
.bottom
;
934 /* draw the Allow checkbox */
935 IsPushed
= (Enabled
&& Item
== infoPtr
->FocusedCheckItem
&& infoPtr
->HasFocus
&&
936 !(Item
->State
& CIS_ALLOWDISABLED
) && infoPtr
->FocusedCheckItemBox
!= CLB_DENY
&&
937 infoPtr
->FocusedPushed
);
939 CheckBox
.left
= infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - ((TextRect
.bottom
- TextRect
.top
) / 2);
940 CheckBox
.right
= CheckBox
.left
+ (TextRect
.bottom
- TextRect
.top
);
942 if (infoPtr
->ThemeHandle
!= NULL
)
944 INT BtnState
= CalculateCheckBoxStyle(Item
->State
& CIS_ALLOW
,
945 Enabled
&& !(Item
->State
& CIS_ALLOWDISABLED
),
946 (ItemHovered
&& infoPtr
->HoveredCheckItemBox
!= CLB_DENY
),
950 hDrawResult
= DrawThemeBackground(infoPtr
->ThemeHandle
,
960 hDrawResult
= E_FAIL
;
963 /* draw the standard checkbox if no themes are enabled or drawing the
964 themeed control failed */
965 if (FAILED(hDrawResult
))
968 DrawFrameControl(hDC
,
971 DFCS_BUTTONCHECK
| DFCS_FLAT
|
972 ((Item
->State
& CIS_ALLOWDISABLED
) || !Enabled
? DFCS_INACTIVE
: 0) |
973 ((Item
->State
& CIS_ALLOW
) ? DFCS_CHECKED
: 0) |
974 (IsPushed
? DFCS_PUSHED
: 0));
976 if (Item
== infoPtr
->FocusedCheckItem
&& !(infoPtr
->UIState
& UISF_HIDEFOCUS
) &&
978 infoPtr
->FocusedCheckItemBox
!= CLB_DENY
)
980 RECT rcFocus
= CheckBox
;
982 InflateRect (&rcFocus
,
983 CI_TEXT_MARGIN_HEIGHT
,
984 CI_TEXT_MARGIN_HEIGHT
);
990 /* draw the Deny checkbox */
991 IsPushed
= (Enabled
&& Item
== infoPtr
->FocusedCheckItem
&& infoPtr
->HasFocus
&&
992 !(Item
->State
& CIS_DENYDISABLED
) && infoPtr
->FocusedCheckItemBox
== CLB_DENY
&&
993 infoPtr
->FocusedPushed
);
995 CheckBox
.left
= infoPtr
->CheckBoxLeft
[CLB_DENY
] - ((TextRect
.bottom
- TextRect
.top
) / 2);
996 CheckBox
.right
= CheckBox
.left
+ (TextRect
.bottom
- TextRect
.top
);
998 if (infoPtr
->ThemeHandle
!= NULL
)
1000 INT BtnState
= CalculateCheckBoxStyle(Item
->State
& CIS_DENY
,
1001 Enabled
&& !(Item
->State
& CIS_DENYDISABLED
),
1002 (ItemHovered
&& infoPtr
->HoveredCheckItemBox
== CLB_DENY
),
1005 hDrawResult
= DrawThemeBackground(infoPtr
->ThemeHandle
,
1015 hDrawResult
= E_FAIL
;
1018 /* draw the standard checkbox if no themes are enabled or drawing the
1019 themeed control failed */
1020 if (FAILED(hDrawResult
))
1023 DrawFrameControl(hDC
,
1026 DFCS_BUTTONCHECK
| DFCS_FLAT
|
1027 ((Item
->State
& CIS_DENYDISABLED
) || !Enabled
? DFCS_INACTIVE
: 0) |
1028 ((Item
->State
& CIS_DENY
) ? DFCS_CHECKED
: 0) |
1029 (IsPushed
? DFCS_PUSHED
: 0));
1031 if (infoPtr
->HasFocus
&& !(infoPtr
->UIState
& UISF_HIDEFOCUS
) &&
1032 Item
== infoPtr
->FocusedCheckItem
&&
1033 infoPtr
->FocusedCheckItemBox
== CLB_DENY
)
1035 RECT rcFocus
= CheckBox
;
1037 InflateRect (&rcFocus
,
1038 CI_TEXT_MARGIN_HEIGHT
,
1039 CI_TEXT_MARGIN_HEIGHT
);
1045 TextRect
.top
+= infoPtr
->ItemHeight
;
1046 ItemRect
.top
+= infoPtr
->ItemHeight
;
1063 ChangeCheckItemFocus(IN PCHECKLISTWND infoPtr
,
1064 IN PCHECKITEM NewFocus
,
1065 IN UINT NewFocusBox
)
1067 if (NewFocus
!= infoPtr
->FocusedCheckItem
)
1069 PCHECKITEM OldFocus
= infoPtr
->FocusedCheckItem
;
1070 infoPtr
->FocusedCheckItem
= NewFocus
;
1071 infoPtr
->FocusedCheckItemBox
= NewFocusBox
;
1073 if (OldFocus
!= NULL
)
1075 UpdateCheckItem(infoPtr
,
1081 infoPtr
->FocusedCheckItemBox
= NewFocusBox
;
1084 if (NewFocus
!= NULL
)
1086 MakeCheckItemVisible(infoPtr
,
1088 UpdateCheckItem(infoPtr
,
1094 UpdateCheckItemBox(IN PCHECKLISTWND infoPtr
,
1099 INT VisibleFirst
, VisibleItems
;
1100 INT Index
= CheckItemToIndex(infoPtr
,
1104 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
1107 if (Index
>= VisibleFirst
)
1109 GetClientRect(infoPtr
->hSelf
,
1112 VisibleItems
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
1114 if (Index
<= VisibleFirst
+ VisibleItems
)
1118 rcUpdate
.left
= rcClient
.left
+ infoPtr
->CheckBoxLeft
[ItemBox
] - (infoPtr
->ItemHeight
/ 2);
1119 rcUpdate
.right
= rcUpdate
.left
+ infoPtr
->ItemHeight
;
1120 rcUpdate
.top
= ((Index
- VisibleFirst
) * infoPtr
->ItemHeight
);
1121 rcUpdate
.bottom
= rcUpdate
.top
+ infoPtr
->ItemHeight
;
1123 RedrawWindow(infoPtr
->hSelf
,
1126 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1134 ChangeCheckItemHotTrack(IN PCHECKLISTWND infoPtr
,
1135 IN PCHECKITEM NewHotTrack
,
1136 IN UINT NewHotTrackBox
)
1138 if (NewHotTrack
!= infoPtr
->HoveredCheckItem
)
1140 PCHECKITEM OldHotTrack
= infoPtr
->HoveredCheckItem
;
1141 UINT OldHotTrackBox
= infoPtr
->HoveredCheckItemBox
;
1143 infoPtr
->HoveredCheckItem
= NewHotTrack
;
1144 infoPtr
->HoveredCheckItemBox
= NewHotTrackBox
;
1146 if (OldHotTrack
!= NULL
)
1148 UpdateCheckItemBox(infoPtr
,
1155 infoPtr
->HoveredCheckItemBox
= NewHotTrackBox
;
1158 if (NewHotTrack
!= NULL
)
1160 UpdateCheckItemBox(infoPtr
,
1168 ChangeCheckBox(IN PCHECKLISTWND infoPtr
,
1169 IN PCHECKITEM CheckItem
,
1170 IN UINT CheckItemBox
)
1172 NMCHANGEITEMCHECKBOX CheckData
;
1173 DWORD OldState
= CheckItem
->State
;
1174 DWORD CheckedBit
= ((infoPtr
->FocusedCheckItemBox
== CLB_DENY
) ? CIS_DENY
: CIS_ALLOW
);
1175 BOOL Checked
= (CheckItem
->State
& CheckedBit
) != 0;
1177 CheckData
.OldState
= OldState
;
1178 CheckData
.NewState
= (Checked
? OldState
& ~CheckedBit
: OldState
| CheckedBit
);
1179 CheckData
.CheckBox
= infoPtr
->FocusedCheckItemBox
;
1180 CheckData
.Checked
= !Checked
;
1182 if (NotifyControlParent(infoPtr
,
1183 CLN_CHANGINGITEMCHECKBOX
,
1184 &CheckData
) != (LRESULT
)-1)
1186 CheckItem
->State
= CheckData
.NewState
;
1189 return (CheckItem
->State
!= OldState
);
1193 DisplayCaret(IN PCHECKLISTWND infoPtr
)
1195 if (IsWindowEnabled(infoPtr
->hSelf
) && !infoPtr
->ShowingCaret
)
1197 infoPtr
->ShowingCaret
= TRUE
;
1199 CreateCaret(infoPtr
->hSelf
,
1201 infoPtr
->CaretWidth
,
1202 infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
));
1204 ShowCaret(infoPtr
->hSelf
);
1209 RemoveCaret(IN PCHECKLISTWND infoPtr
)
1211 if (IsWindowEnabled(infoPtr
->hSelf
) && infoPtr
->ShowingCaret
)
1213 infoPtr
->ShowingCaret
= FALSE
;
1215 HideCaret(infoPtr
->hSelf
);
1221 KillQuickSearchTimers(IN PCHECKLISTWND infoPtr
)
1223 KillTimer(infoPtr
->hSelf
,
1224 TIMER_ID_SETHITFOCUS
);
1225 KillTimer(infoPtr
->hSelf
,
1226 TIMER_ID_RESETQUICKSEARCH
);
1230 MapItemToRect(IN PCHECKLISTWND infoPtr
,
1231 IN PCHECKITEM CheckItem
,
1234 INT Index
= CheckItemToIndex(infoPtr
,
1241 GetClientRect(infoPtr
->hSelf
,
1244 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
1247 prcItem
->left
= rcClient
.left
;
1248 prcItem
->right
= rcClient
.right
;
1249 prcItem
->top
= (Index
- VisibleFirst
) * infoPtr
->ItemHeight
;
1250 prcItem
->bottom
= prcItem
->top
+ infoPtr
->ItemHeight
;
1257 prcItem
->bottom
= 0;
1262 UpdateCaretPos(IN PCHECKLISTWND infoPtr
)
1264 if (infoPtr
->ShowingCaret
&& infoPtr
->QuickSearchHitItem
!= NULL
)
1266 HDC hDC
= GetDC(infoPtr
->hSelf
);
1270 HGDIOBJ hOldFont
= SelectObject(hDC
,
1276 if (infoPtr
->QuickSearchText
[0] == L
'\0' ||
1277 GetTextExtentPoint32(hDC
,
1278 infoPtr
->QuickSearchHitItem
->Name
,
1279 wcslen(infoPtr
->QuickSearchText
),
1284 MapItemToRect(infoPtr
,
1285 infoPtr
->QuickSearchHitItem
,
1288 /* actually change the caret position */
1289 SetCaretPos(rcItem
.left
+ CI_TEXT_MARGIN_WIDTH
+ TextSize
.cx
,
1290 rcItem
.top
+ CI_TEXT_MARGIN_HEIGHT
);
1296 ReleaseDC(infoPtr
->hSelf
,
1303 EscapeQuickSearch(IN PCHECKLISTWND infoPtr
)
1305 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
)
1307 PCHECKITEM OldHit
= infoPtr
->QuickSearchHitItem
;
1309 infoPtr
->QuickSearchHitItem
= NULL
;
1310 infoPtr
->QuickSearchText
[0] = L
'\0';
1312 /* scroll back to the focused item */
1313 if (infoPtr
->FocusedCheckItem
!= NULL
)
1315 MakeCheckItemVisible(infoPtr
,
1316 infoPtr
->FocusedCheckItem
);
1319 /* repaint the old search hit item if it's still visible */
1320 UpdateCheckItem(infoPtr
,
1323 KillQuickSearchTimers(infoPtr
);
1325 RemoveCaret(infoPtr
);
1330 ChangeSearchHit(IN PCHECKLISTWND infoPtr
,
1331 IN PCHECKITEM NewHit
)
1333 PCHECKITEM OldHit
= infoPtr
->QuickSearchHitItem
;
1335 infoPtr
->QuickSearchHitItem
= NewHit
;
1337 if (OldHit
!= NewHit
)
1339 /* scroll to the new search hit */
1340 MakeCheckItemVisible(infoPtr
,
1343 /* repaint the old hit if present and visible */
1346 UpdateCheckItem(infoPtr
,
1351 /* show the caret the first time we find an item */
1352 DisplayCaret(infoPtr
);
1356 UpdateCaretPos(infoPtr
);
1358 UpdateCheckItem(infoPtr
,
1361 /* kill the reset timer and restart the set hit focus timer */
1362 KillTimer(infoPtr
->hSelf
,
1363 TIMER_ID_RESETQUICKSEARCH
);
1364 if (infoPtr
->QuickSearchSetFocusDelay
!= 0)
1366 SetTimer(infoPtr
->hSelf
,
1367 TIMER_ID_SETHITFOCUS
,
1368 infoPtr
->QuickSearchSetFocusDelay
,
1374 QuickSearchFindHit(IN PCHECKLISTWND infoPtr
,
1377 if (infoPtr
->QuickSearchEnabled
)
1387 Ret
= infoPtr
->QuickSearchHitItem
!= NULL
;
1390 /* NOTE: QuickSearchHitItem definitely has at least one
1391 enabled check box, the user can't search for disabled
1394 ChangeCheckItemFocus(infoPtr
,
1395 infoPtr
->QuickSearchHitItem
,
1396 ((!(infoPtr
->QuickSearchHitItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
));
1398 EscapeQuickSearch(infoPtr
);
1405 if (infoPtr
->QuickSearchHitItem
!= NULL
)
1407 INT SearchLen
= wcslen(infoPtr
->QuickSearchText
);
1410 /* delete the last character */
1411 infoPtr
->QuickSearchText
[--SearchLen
] = L
'\0';
1416 NewHit
= FindCheckItem(infoPtr
,
1417 infoPtr
->QuickSearchText
);
1421 /* change the search hit */
1422 ChangeSearchHit(infoPtr
,
1432 EscapeQuickSearch(infoPtr
);
1440 INT SearchLen
= wcslen(infoPtr
->QuickSearchText
);
1441 if (SearchLen
< (INT
)(sizeof(infoPtr
->QuickSearchText
) / sizeof(infoPtr
->QuickSearchText
[0])) - 1)
1443 infoPtr
->QuickSearchText
[SearchLen
++] = c
;
1444 infoPtr
->QuickSearchText
[SearchLen
] = L
'\0';
1446 NewHit
= FindCheckItem(infoPtr
,
1447 infoPtr
->QuickSearchText
);
1450 /* change the search hit */
1451 ChangeSearchHit(infoPtr
,
1458 /* reset the input */
1459 infoPtr
->QuickSearchText
[--SearchLen
] = L
'\0';
1471 static LRESULT CALLBACK
1472 CheckListWndProc(IN HWND hwnd
,
1477 PCHECKLISTWND infoPtr
;
1480 infoPtr
= (PCHECKLISTWND
)GetWindowLongPtr(hwnd
,
1483 if (infoPtr
== NULL
&& uMsg
!= WM_CREATE
)
1485 goto HandleDefaultMessage
;
1498 if (GetUpdateRect(hwnd
,
1502 hdc
= (wParam
!= 0 ? (HDC
)wParam
: BeginPaint(hwnd
, &ps
));
1506 PaintControl(infoPtr
,
1524 HWND hWndCapture
= GetCapture();
1526 pt
.x
= (LONG
)LOWORD(lParam
);
1527 pt
.y
= (LONG
)HIWORD(lParam
);
1530 /* handle hovering checkboxes */
1531 if (hWndCapture
== NULL
&& infoPtr
->ThemeHandle
!= NULL
)
1533 TRACKMOUSEEVENT tme
;
1534 PCHECKITEM HotTrackItem
;
1535 UINT HotTrackItemBox
;
1537 HotTrackItem
= PtToCheckItemBox(infoPtr
,
1541 if (HotTrackItem
!= NULL
&& InCheckBox
)
1543 if (infoPtr
->HoveredCheckItem
!= HotTrackItem
||
1544 infoPtr
->HoveredCheckItemBox
!= HotTrackItemBox
)
1546 ChangeCheckItemHotTrack(infoPtr
,
1553 ChangeCheckItemHotTrack(infoPtr
,
1558 tme
.cbSize
= sizeof(tme
);
1559 tme
.dwFlags
= TME_LEAVE
;
1560 tme
.hwndTrack
= hwnd
;
1561 tme
.dwHoverTime
= infoPtr
->HoverTime
;
1563 TrackMouseEvent(&tme
);
1567 if (hWndCapture
== hwnd
&& infoPtr
->FocusedCheckItem
!= NULL
)
1573 PtItem
= PtToCheckItemBox(infoPtr
,
1578 OldPushed
= infoPtr
->FocusedPushed
;
1579 infoPtr
->FocusedPushed
= InCheckBox
&& infoPtr
->FocusedCheckItem
== PtItem
&&
1580 infoPtr
->FocusedCheckItemBox
== PtItemBox
;
1582 if (OldPushed
!= infoPtr
->FocusedPushed
)
1584 UpdateCheckItemBox(infoPtr
,
1585 infoPtr
->FocusedCheckItem
,
1586 infoPtr
->FocusedCheckItemBox
);
1595 SCROLLINFO ScrollInfo
;
1597 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
1598 ScrollInfo
.fMask
= SIF_RANGE
| SIF_POS
;
1600 if (GetScrollInfo(hwnd
,
1604 INT OldPos
= ScrollInfo
.nPos
;
1606 switch (LOWORD(wParam
))
1609 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1613 if (ScrollInfo
.nPos
< ScrollInfo
.nMax
)
1620 if (ScrollInfo
.nPos
> 0)
1631 /* don't use ScrollInfo.nPage because we should only scroll
1632 down by the number of completely visible list entries.
1633 nPage however also includes the partly cropped list
1634 item at the bottom of the control */
1639 ScrollLines
= max(1,
1640 (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
);
1642 if (ScrollInfo
.nPos
+ ScrollLines
<= ScrollInfo
.nMax
)
1644 ScrollInfo
.nPos
+= ScrollLines
;
1648 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1658 /* don't use ScrollInfo.nPage because we should only scroll
1659 down by the number of completely visible list entries.
1660 nPage however also includes the partly cropped list
1661 item at the bottom of the control */
1666 ScrollLines
= max(1,
1667 (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
);
1669 if (ScrollInfo
.nPos
>= ScrollLines
)
1671 ScrollInfo
.nPos
-= ScrollLines
;
1675 ScrollInfo
.nPos
= 0;
1680 case SB_THUMBPOSITION
:
1683 ScrollInfo
.nPos
= HIWORD(wParam
);
1688 ScrollInfo
.nPos
= 0;
1692 if (OldPos
!= ScrollInfo
.nPos
)
1694 ScrollInfo
.fMask
= SIF_POS
;
1696 ScrollInfo
.nPos
= SetScrollInfo(hwnd
,
1701 if (OldPos
!= ScrollInfo
.nPos
)
1703 ScrollWindowEx(hwnd
,
1705 (OldPos
- ScrollInfo
.nPos
) * infoPtr
->ItemHeight
,
1710 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
1715 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1725 PCHECKITEM Item
= AddCheckItem(infoPtr
,
1728 (ACCESS_MASK
)wParam
,
1732 UpdateControl(infoPtr
);
1733 Ret
= (LRESULT
)Index
;
1744 PCHECKITEM Item
= FindCheckItemByIndex(infoPtr
,
1748 Ret
= DeleteCheckItem(infoPtr
,
1752 UpdateControl(infoPtr
);
1762 case CLM_SETITEMSTATE
:
1764 PCHECKITEM Item
= FindCheckItemByIndex(infoPtr
,
1768 DWORD OldState
= Item
->State
;
1769 Item
->State
= (DWORD
)lParam
& CIS_MASK
;
1771 if (Item
->State
!= OldState
)
1773 /* revert the focus if the currently focused item is about
1775 if (Item
== infoPtr
->FocusedCheckItem
&&
1776 (Item
->State
& CIS_DISABLED
))
1778 if (infoPtr
->FocusedCheckItemBox
== CLB_DENY
)
1780 if (Item
->State
& CIS_DENYDISABLED
)
1782 infoPtr
->FocusedCheckItem
= NULL
;
1787 if (Item
->State
& CIS_ALLOWDISABLED
)
1789 infoPtr
->FocusedCheckItem
= NULL
;
1794 UpdateControl(infoPtr
);
1801 case CLM_GETITEMCOUNT
:
1803 Ret
= infoPtr
->CheckItemCount
;
1809 ClearCheckItems(infoPtr
);
1810 UpdateControl(infoPtr
);
1814 case CLM_SETCHECKBOXCOLUMN
:
1816 infoPtr
->CheckBoxLeft
[wParam
!= CLB_DENY
] = (INT
)lParam
;
1817 UpdateControl(infoPtr
);
1822 case CLM_GETCHECKBOXCOLUMN
:
1824 Ret
= (LRESULT
)infoPtr
->CheckBoxLeft
[wParam
!= CLB_DENY
];
1828 case CLM_CLEARCHECKBOXES
:
1830 Ret
= (LRESULT
)ClearCheckBoxes(infoPtr
);
1833 UpdateControl(infoPtr
);
1838 case CLM_ENABLEQUICKSEARCH
:
1842 EscapeQuickSearch(infoPtr
);
1844 infoPtr
->QuickSearchEnabled
= (wParam
!= 0);
1848 case CLM_SETQUICKSEARCH_TIMEOUT_RESET
:
1850 infoPtr
->QuickSearchResetDelay
= (UINT
)wParam
;
1854 case CLM_SETQUICKSEARCH_TIMEOUT_SETFOCUS
:
1856 infoPtr
->QuickSearchSetFocusDelay
= (UINT
)wParam
;
1860 case CLM_FINDITEMBYACCESSMASK
:
1862 Ret
= (LRESULT
)FindCheckItemIndexByAccessMask(infoPtr
,
1863 (ACCESS_MASK
)wParam
);
1869 Ret
= (LRESULT
)RetChangeControlFont(infoPtr
,
1871 (BOOL
)LOWORD(lParam
));
1877 Ret
= (LRESULT
)infoPtr
->hFont
;
1881 case WM_STYLECHANGED
:
1883 if (wParam
== (WPARAM
)GWL_STYLE
)
1885 UpdateControl(infoPtr
);
1892 EscapeQuickSearch(infoPtr
);
1894 UpdateControl(infoPtr
);
1901 UINT ScrollLines
= 3;
1903 SystemParametersInfo(SPI_GETWHEELSCROLLLINES
,
1907 ScrollDelta
= 0 - (SHORT
)HIWORD(wParam
);
1909 if (ScrollLines
!= 0 &&
1910 abs(ScrollDelta
) >= WHEEL_DELTA
)
1912 SCROLLINFO ScrollInfo
;
1914 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
1915 ScrollInfo
.fMask
= SIF_RANGE
| SIF_POS
;
1917 if (GetScrollInfo(hwnd
,
1921 INT OldPos
= ScrollInfo
.nPos
;
1923 ScrollInfo
.nPos
+= (ScrollDelta
/ WHEEL_DELTA
) * ScrollLines
;
1924 if (ScrollInfo
.nPos
< 0)
1925 ScrollInfo
.nPos
= 0;
1926 else if (ScrollInfo
.nPos
> ScrollInfo
.nMax
)
1927 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1929 if (OldPos
!= ScrollInfo
.nPos
)
1931 ScrollInfo
.fMask
= SIF_POS
;
1933 ScrollInfo
.nPos
= SetScrollInfo(hwnd
,
1938 if (OldPos
!= ScrollInfo
.nPos
)
1940 ScrollWindowEx(hwnd
,
1942 (OldPos
- ScrollInfo
.nPos
) * infoPtr
->ItemHeight
,
1947 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
1952 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1962 infoPtr
->HasFocus
= TRUE
;
1964 if (infoPtr
->FocusedCheckItem
== NULL
)
1966 BOOL Shift
= GetKeyState(VK_SHIFT
) & 0x8000;
1967 infoPtr
->FocusedCheckItem
= FindEnabledCheckBox(infoPtr
,
1969 &infoPtr
->FocusedCheckItemBox
);
1971 if (infoPtr
->FocusedCheckItem
!= NULL
)
1973 MakeCheckItemVisible(infoPtr
,
1974 infoPtr
->FocusedCheckItem
);
1976 UpdateCheckItem(infoPtr
,
1977 infoPtr
->FocusedCheckItem
);
1984 EscapeQuickSearch(infoPtr
);
1986 infoPtr
->HasFocus
= FALSE
;
1987 if (infoPtr
->FocusedCheckItem
!= NULL
)
1989 infoPtr
->FocusedPushed
= FALSE
;
1991 UpdateCheckItem(infoPtr
,
1992 infoPtr
->FocusedCheckItem
);
1997 case WM_LBUTTONDBLCLK
:
1998 case WM_LBUTTONDOWN
:
1999 case WM_MBUTTONDOWN
:
2000 case WM_RBUTTONDOWN
:
2002 if (IsWindowEnabled(hwnd
))
2004 PCHECKITEM NewFocus
;
2005 UINT NewFocusBox
= 0;
2008 BOOL ChangeFocus
, Capture
= FALSE
;
2010 pt
.x
= (LONG
)LOWORD(lParam
);
2011 pt
.y
= (LONG
)HIWORD(lParam
);
2013 NewFocus
= PtToCheckItemBox(infoPtr
,
2017 if (NewFocus
!= NULL
)
2019 if (NewFocus
->State
& ((NewFocusBox
!= CLB_DENY
) ? CIS_ALLOWDISABLED
: CIS_DENYDISABLED
))
2021 /* the user clicked on a disabled checkbox, try to set
2022 the focus to the other one or not change it at all */
2026 ChangeFocus
= ((NewFocus
->State
& CIS_DISABLED
) != CIS_DISABLED
);
2029 NewFocusBox
= ((NewFocusBox
!= CLB_DENY
) ? CLB_DENY
: CLB_ALLOW
);
2037 if (InCheckBox
&& ChangeFocus
&& GetCapture() == NULL
&&
2038 (uMsg
== WM_LBUTTONDOWN
|| uMsg
== WM_LBUTTONDBLCLK
))
2040 infoPtr
->FocusedPushed
= TRUE
;
2051 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
&&
2052 infoPtr
->QuickSearchHitItem
!= NewFocus
)
2054 EscapeQuickSearch(infoPtr
);
2057 ChangeCheckItemFocus(infoPtr
,
2062 if (!infoPtr
->HasFocus
)
2077 if (GetCapture() == hwnd
)
2079 if (infoPtr
->FocusedCheckItem
!= NULL
&& infoPtr
->FocusedPushed
)
2086 pt
.x
= (LONG
)LOWORD(lParam
);
2087 pt
.y
= (LONG
)HIWORD(lParam
);
2089 infoPtr
->FocusedPushed
= FALSE
;
2091 PtItem
= PtToCheckItemBox(infoPtr
,
2096 if (PtItem
== infoPtr
->FocusedCheckItem
&& InCheckBox
&&
2097 PtItemBox
== infoPtr
->FocusedCheckItemBox
)
2099 UINT OtherBox
= ((PtItemBox
== CLB_ALLOW
) ? CLB_DENY
: CLB_ALLOW
);
2100 DWORD OtherStateMask
= ((OtherBox
== CLB_ALLOW
) ?
2101 (CIS_ALLOW
| CIS_ALLOWDISABLED
) :
2102 (CIS_DENY
| CIS_DENYDISABLED
));
2103 DWORD OtherStateOld
= PtItem
->State
& OtherStateMask
;
2104 if (ChangeCheckBox(infoPtr
,
2107 ((PtItem
->State
& OtherStateMask
) != OtherStateOld
))
2109 UpdateCheckItemBox(infoPtr
,
2110 infoPtr
->FocusedCheckItem
,
2115 UpdateCheckItemBox(infoPtr
,
2116 infoPtr
->FocusedCheckItem
,
2117 infoPtr
->FocusedCheckItemBox
);
2131 if (GetCapture() == NULL
&&
2132 !QuickSearchFindHit(infoPtr
,
2135 if (infoPtr
->FocusedCheckItem
!= NULL
&&
2136 (infoPtr
->QuickSearchHitItem
== NULL
||
2137 infoPtr
->QuickSearchHitItem
== infoPtr
->FocusedCheckItem
))
2139 UINT OldPushed
= infoPtr
->FocusedPushed
;
2140 infoPtr
->FocusedPushed
= TRUE
;
2142 if (infoPtr
->FocusedPushed
!= OldPushed
)
2144 MakeCheckItemVisible(infoPtr
,
2145 infoPtr
->FocusedCheckItem
);
2147 UpdateCheckItemBox(infoPtr
,
2148 infoPtr
->FocusedCheckItem
,
2149 infoPtr
->FocusedCheckItemBox
);
2158 if (GetCapture() == NULL
&&
2159 !QuickSearchFindHit(infoPtr
,
2162 if (infoPtr
->FocusedCheckItem
!= NULL
&&
2163 infoPtr
->QuickSearchHitItem
== NULL
)
2166 DWORD OtherStateMask
;
2167 DWORD OtherStateOld
;
2169 MakeCheckItemVisible(infoPtr
,
2170 infoPtr
->FocusedCheckItem
);
2172 OtherBox
= ((infoPtr
->FocusedCheckItemBox
== CLB_ALLOW
) ? CLB_DENY
: CLB_ALLOW
);
2173 OtherStateMask
= ((OtherBox
== CLB_ALLOW
) ?
2174 (CIS_ALLOW
| CIS_ALLOWDISABLED
) :
2175 (CIS_DENY
| CIS_DENYDISABLED
));
2176 OtherStateOld
= infoPtr
->FocusedCheckItem
->State
& OtherStateMask
;
2177 if (ChangeCheckBox(infoPtr
,
2178 infoPtr
->FocusedCheckItem
,
2179 infoPtr
->FocusedCheckItemBox
))
2181 UpdateCheckItemBox(infoPtr
,
2182 infoPtr
->FocusedCheckItem
,
2183 infoPtr
->FocusedCheckItemBox
);
2184 if ((infoPtr
->FocusedCheckItem
->State
& OtherStateMask
) != OtherStateOld
)
2186 UpdateCheckItemBox(infoPtr
,
2187 infoPtr
->FocusedCheckItem
,
2198 if (GetCapture() == NULL
)
2200 PCHECKITEM NewFocus
;
2201 UINT NewFocusBox
= 0;
2202 BOOL Shift
= GetKeyState(VK_SHIFT
) & 0x8000;
2204 EscapeQuickSearch(infoPtr
);
2206 NewFocus
= FindEnabledCheckBox(infoPtr
,
2210 /* update the UI status */
2211 SendMessage(GetAncestor(hwnd
,
2214 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 DWORD OldUIState
= infoPtr
->UIState
;
2399 switch (LOWORD(wParam
))
2402 infoPtr
->UIState
|= HIWORD(wParam
);
2406 infoPtr
->UIState
&= ~(HIWORD(wParam
));
2410 if (OldUIState
!= infoPtr
->UIState
)
2412 if (infoPtr
->FocusedCheckItem
!= NULL
)
2414 UpdateCheckItemBox(infoPtr
,
2415 infoPtr
->FocusedCheckItem
,
2416 infoPtr
->FocusedCheckItemBox
);
2426 case TIMER_ID_SETHITFOCUS
:
2428 /* kill the timer */
2432 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
)
2434 /* change the focus to the hit item, this item has to have
2435 at least one enabled checkbox! */
2436 ChangeCheckItemFocus(infoPtr
,
2437 infoPtr
->QuickSearchHitItem
,
2438 ((!(infoPtr
->QuickSearchHitItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
));
2440 /* start the timer to reset quicksearch */
2441 if (infoPtr
->QuickSearchResetDelay
!= 0)
2444 TIMER_ID_RESETQUICKSEARCH
,
2445 infoPtr
->QuickSearchResetDelay
,
2451 case TIMER_ID_RESETQUICKSEARCH
:
2453 /* kill the timer */
2457 /* escape quick search */
2458 EscapeQuickSearch(infoPtr
);
2467 infoPtr
= HeapAlloc(GetProcessHeap(),
2469 sizeof(CHECKLISTWND
));
2470 if (infoPtr
!= NULL
)
2474 infoPtr
->hSelf
= hwnd
;
2475 infoPtr
->hNotify
= ((LPCREATESTRUCTW
)lParam
)->hwndParent
;
2477 SetWindowLongPtr(hwnd
,
2479 (DWORD_PTR
)infoPtr
);
2481 infoPtr
->CheckItemListHead
= NULL
;
2482 infoPtr
->CheckItemCount
= 0;
2484 if (!SystemParametersInfo(SPI_GETCARETWIDTH
,
2486 &infoPtr
->CaretWidth
,
2489 infoPtr
->CaretWidth
= 2;
2491 infoPtr
->ItemHeight
= 10;
2492 infoPtr
->ShowingCaret
= FALSE
;
2494 infoPtr
->HasFocus
= FALSE
;
2495 infoPtr
->FocusedCheckItem
= NULL
;
2496 infoPtr
->FocusedCheckItemBox
= 0;
2497 infoPtr
->FocusedPushed
= FALSE
;
2499 infoPtr
->TextColor
[0] = GetSysColor(COLOR_GRAYTEXT
);
2500 infoPtr
->TextColor
[1] = GetSysColor(COLOR_WINDOWTEXT
);
2505 infoPtr
->CheckBoxLeft
[0] = rcClient
.right
- 30;
2506 infoPtr
->CheckBoxLeft
[1] = rcClient
.right
- 15;
2508 infoPtr
->QuickSearchEnabled
= FALSE
;
2509 infoPtr
->QuickSearchText
[0] = L
'\0';
2511 infoPtr
->QuickSearchSetFocusDelay
= DEFAULT_QUICKSEARCH_SETFOCUS_DELAY
;
2512 infoPtr
->QuickSearchResetDelay
= DEFAULT_QUICKSEARCH_RESET_DELAY
;
2515 infoPtr
->HoveredCheckItem
= NULL
;
2516 infoPtr
->HoveredCheckItemBox
= 0;
2517 if (!SystemParametersInfo(SPI_GETMOUSEHOVERTIME
,
2519 &infoPtr
->HoverTime
,
2522 infoPtr
->HoverTime
= HOVER_DEFAULT
;
2527 infoPtr
->ThemeHandle
= OpenThemeData(infoPtr
->hSelf
,
2532 infoPtr
->ThemeHandle
= NULL
;
2536 infoPtr
->UIState
= SendMessage(hwnd
,
2550 if (infoPtr
->ShowingCaret
)
2555 ClearCheckItems(infoPtr
);
2558 if (infoPtr
->ThemeHandle
!= NULL
)
2560 CloseThemeData(infoPtr
->ThemeHandle
);
2564 HeapFree(GetProcessHeap(),
2567 SetWindowLongPtr(hwnd
,
2575 HandleDefaultMessage
:
2576 Ret
= DefWindowProc(hwnd
,
2588 RegisterCheckListControl(IN HINSTANCE hInstance
)
2592 wc
.style
= CS_DBLCLKS
;
2593 wc
.lpfnWndProc
= CheckListWndProc
;
2595 wc
.cbWndExtra
= sizeof(PCHECKLISTWND
);
2596 wc
.hInstance
= hInstance
;
2598 wc
.hCursor
= LoadCursor(NULL
,
2600 wc
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
2601 wc
.lpszMenuName
= NULL
;
2602 wc
.lpszClassName
= szCheckListWndClass
;
2604 return RegisterClass(&wc
) != 0;
2608 UnregisterCheckListControl(HINSTANCE hInstance
)
2610 UnregisterClass(szCheckListWndClass
,