2 * ReactOS Access Control List Editor
3 * Copyright (C) 2004 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>
31 #define CI_TEXT_MARGIN_WIDTH (8)
32 #define CI_TEXT_MARGIN_HEIGHT (3)
33 #define CI_TEXT_SELECTIONMARGIN (1)
35 #define TIMER_ID_SETHITFOCUS (1)
36 #define TIMER_ID_RESETQUICKSEARCH (2)
38 #define DEFAULT_QUICKSEARCH_SETFOCUS_DELAY (2000)
39 #define DEFAULT_QUICKSEARCH_RESET_DELAY (3000)
41 typedef struct _CHECKITEM
43 struct _CHECKITEM
*Next
;
46 } CHECKITEM
, *PCHECKITEM
;
48 typedef struct _CHECKLISTWND
54 PCHECKITEM CheckItemListHead
;
60 PCHECKITEM FocusedCheckItem
;
61 UINT FocusedCheckItemBox
;
65 COLORREF TextColor
[2];
68 BOOL QuickSearchEnabled
;
69 PCHECKITEM QuickSearchHitItem
;
70 WCHAR QuickSearchText
[65];
71 UINT QuickSearchSetFocusDelay
;
72 UINT QuickSearchResetDelay
;
78 PCHECKITEM HoveredCheckItem
;
79 UINT HoveredCheckItemBox
;
84 } CHECKLISTWND
, *PCHECKLISTWND
;
86 static VOID
EscapeQuickSearch(IN PCHECKLISTWND infoPtr
);
88 static VOID
ChangeCheckItemHotTrack(IN PCHECKLISTWND infoPtr
,
89 IN PCHECKITEM NewHotTrack
,
90 IN UINT NewHotTrackBox
);
92 static VOID
ChangeCheckItemFocus(IN PCHECKLISTWND infoPtr
,
93 IN PCHECKITEM NewFocus
,
96 /******************************************************************************/
99 FindCheckItemByIndex(IN PCHECKLISTWND infoPtr
,
102 PCHECKITEM Item
, Found
= NULL
;
106 for (Item
= infoPtr
->CheckItemListHead
;
124 CheckItemToIndex(IN PCHECKLISTWND infoPtr
,
130 for (CurItem
= infoPtr
->CheckItemListHead
, Index
= 0;
132 CurItem
= CurItem
->Next
, Index
++)
144 FindCheckItem(IN PCHECKLISTWND infoPtr
,
145 IN LPWSTR SearchText
)
148 SIZE_T Count
= wcslen(SearchText
);
150 for (CurItem
= infoPtr
->CheckItemListHead
;
152 CurItem
= CurItem
->Next
)
154 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
&&
155 !wcsnicmp(CurItem
->Name
, SearchText
, Count
))
165 FindFirstEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
170 for (CurItem
= infoPtr
->CheckItemListHead
;
172 CurItem
= CurItem
->Next
)
174 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
176 /* return the Allow checkbox in case both check boxes are enabled! */
177 *CheckBox
= ((!(CurItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
);
186 FindLastEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
190 PCHECKITEM LastEnabledItem
= NULL
;
192 for (CurItem
= infoPtr
->CheckItemListHead
;
194 CurItem
= CurItem
->Next
)
196 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
198 LastEnabledItem
= CurItem
;
202 if (LastEnabledItem
!= NULL
)
204 /* return the Deny checkbox in case both check boxes are enabled! */
205 *CheckBox
= ((!(LastEnabledItem
->State
& CIS_DENYDISABLED
)) ? CLB_DENY
: CLB_ALLOW
);
208 return LastEnabledItem
;
212 FindPreviousEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
217 if (infoPtr
->FocusedCheckItem
!= NULL
)
219 Item
= infoPtr
->FocusedCheckItem
;
221 if (infoPtr
->FocusedCheckItemBox
== CLB_DENY
&&
222 !(Item
->State
& CIS_ALLOWDISABLED
))
224 /* currently an Deny checkbox is focused. return the Allow checkbox
226 *CheckBox
= CLB_ALLOW
;
234 for (CurItem
= infoPtr
->CheckItemListHead
;
235 CurItem
!= infoPtr
->FocusedCheckItem
;
236 CurItem
= CurItem
->Next
)
238 if ((CurItem
->State
& CIS_DISABLED
) != CIS_DISABLED
)
246 /* return the Deny checkbox in case both check boxes are enabled! */
247 *CheckBox
= ((!(Item
->State
& CIS_DENYDISABLED
)) ? CLB_DENY
: CLB_ALLOW
);
253 Item
= FindLastEnabledCheckBox(infoPtr
,
261 FindNextEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
266 if (infoPtr
->FocusedCheckItem
!= NULL
)
268 Item
= infoPtr
->FocusedCheckItem
;
270 if (infoPtr
->FocusedCheckItemBox
!= CLB_DENY
&&
271 !(Item
->State
& CIS_DENYDISABLED
))
273 /* currently an Allow checkbox is focused. return the Deny checkbox
275 *CheckBox
= CLB_DENY
;
283 if ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
)
285 /* return the Allow checkbox in case both check boxes are enabled! */
286 *CheckBox
= ((!(Item
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
);
296 Item
= FindFirstEnabledCheckBox(infoPtr
,
304 FindEnabledCheckBox(IN PCHECKLISTWND infoPtr
,
305 IN BOOL ReverseSearch
,
312 Item
= FindPreviousEnabledCheckBox(infoPtr
,
317 Item
= FindNextEnabledCheckBox(infoPtr
,
325 PtToCheckItemBox(IN PCHECKLISTWND infoPtr
,
328 OUT BOOL
*DirectlyInCheckBox
)
331 INT FirstVisible
, Index
;
334 Style
= GetWindowLong(infoPtr
->hSelf
,
337 if (Style
& WS_VSCROLL
)
339 FirstVisible
= GetScrollPos(infoPtr
->hSelf
,
347 Index
= FirstVisible
+ (ppt
->y
/ infoPtr
->ItemHeight
);
349 Item
= FindCheckItemByIndex(infoPtr
,
355 cx
= infoPtr
->CheckBoxLeft
[CLB_ALLOW
] +
356 ((infoPtr
->CheckBoxLeft
[CLB_DENY
] - infoPtr
->CheckBoxLeft
[CLB_ALLOW
]) / 2);
358 *CheckBox
= ((ppt
->x
<= cx
) ? CLB_ALLOW
: CLB_DENY
);
360 if (DirectlyInCheckBox
!= NULL
)
362 INT y
= ppt
->y
% infoPtr
->ItemHeight
;
363 INT cxBox
= infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
);
365 if ((y
>= CI_TEXT_MARGIN_HEIGHT
&&
366 y
< infoPtr
->ItemHeight
- CI_TEXT_MARGIN_HEIGHT
) &&
368 (((ppt
->x
>= (infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - (cxBox
/ 2))) &&
369 (ppt
->x
< (infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - (cxBox
/ 2) + cxBox
)))
371 ((ppt
->x
>= (infoPtr
->CheckBoxLeft
[CLB_DENY
] - (cxBox
/ 2))) &&
372 (ppt
->x
< (infoPtr
->CheckBoxLeft
[CLB_DENY
] - (cxBox
/ 2) + cxBox
)))))
374 *DirectlyInCheckBox
= TRUE
;
378 *DirectlyInCheckBox
= FALSE
;
387 ClearCheckItems(IN PCHECKLISTWND infoPtr
)
389 PCHECKITEM CurItem
, NextItem
;
391 CurItem
= infoPtr
->CheckItemListHead
;
392 while (CurItem
!= NULL
)
394 NextItem
= CurItem
->Next
;
395 HeapFree(GetProcessHeap(),
401 infoPtr
->CheckItemListHead
= NULL
;
402 infoPtr
->CheckItemCount
= 0;
406 DeleteCheckItem(IN PCHECKLISTWND infoPtr
,
410 PCHECKITEM
*PrevPtr
= &infoPtr
->CheckItemListHead
;
412 for (CurItem
= infoPtr
->CheckItemListHead
;
414 CurItem
= CurItem
->Next
)
418 if (Item
== infoPtr
->QuickSearchHitItem
&& infoPtr
->QuickSearchEnabled
)
420 EscapeQuickSearch(infoPtr
);
424 if (Item
== infoPtr
->HoveredCheckItem
)
426 ChangeCheckItemHotTrack(infoPtr
,
432 if (Item
== infoPtr
->FocusedCheckItem
)
434 ChangeCheckItemFocus(infoPtr
,
439 *PrevPtr
= CurItem
->Next
;
440 HeapFree(GetProcessHeap(),
443 infoPtr
->CheckItemCount
--;
447 PrevPtr
= &CurItem
->Next
;
454 AddCheckItem(IN PCHECKLISTWND infoPtr
,
461 PCHECKITEM
*PrevPtr
= &infoPtr
->CheckItemListHead
;
462 PCHECKITEM Item
= HeapAlloc(GetProcessHeap(),
464 sizeof(CHECKITEM
) + (wcslen(Name
) * sizeof(WCHAR
)));
467 for (CurItem
= infoPtr
->CheckItemListHead
, i
= 0;
469 CurItem
= CurItem
->Next
)
471 PrevPtr
= &CurItem
->Next
;
476 Item
->State
= State
& CIS_MASK
;
481 infoPtr
->CheckItemCount
++;
493 ClearCheckBoxes(IN PCHECKLISTWND infoPtr
)
498 for (CurItem
= infoPtr
->CheckItemListHead
;
500 CurItem
= CurItem
->Next
)
502 if (CurItem
->State
& (CIS_ALLOW
| CIS_DENY
))
504 CurItem
->State
&= ~(CIS_ALLOW
| CIS_DENY
);
513 UpdateControl(IN PCHECKLISTWND infoPtr
,
514 IN BOOL AllowChangeStyle
)
517 SCROLLINFO ScrollInfo
;
521 GetClientRect(infoPtr
->hSelf
,
524 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
525 ScrollInfo
.fMask
= SIF_PAGE
| SIF_RANGE
;
527 ScrollInfo
.nMax
= infoPtr
->CheckItemCount
;
528 ScrollInfo
.nPage
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
530 ScrollInfo
.nTrackPos
= 0;
532 VisibleItems
= (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
;
534 if (ScrollInfo
.nPage
== VisibleItems
&& ScrollInfo
.nMax
> 0)
539 SetScrollInfo(infoPtr
->hSelf
,
544 if (AllowChangeStyle
)
546 Style
= GetWindowLong(infoPtr
->hSelf
,
549 /* determine whether the vertical scrollbar has to be visible or not */
550 if (ScrollInfo
.nMax
> VisibleItems
&&
551 !(Style
& WS_VSCROLL
))
553 SetWindowLong(infoPtr
->hSelf
,
557 else if (ScrollInfo
.nMax
<= VisibleItems
&&
558 (Style
& WS_VSCROLL
))
560 SetWindowLong(infoPtr
->hSelf
,
562 Style
& ~WS_VSCROLL
);
566 RedrawWindow(infoPtr
->hSelf
,
569 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
573 UpdateCheckItem(IN PCHECKLISTWND infoPtr
,
578 INT VisibleFirst
, VisibleItems
;
579 INT Index
= CheckItemToIndex(infoPtr
,
583 Style
= GetWindowLong(infoPtr
->hSelf
,
586 if (Style
& WS_VSCROLL
)
588 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
596 if (Index
>= VisibleFirst
)
598 GetClientRect(infoPtr
->hSelf
,
601 VisibleItems
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
603 if (Index
<= VisibleFirst
+ VisibleItems
)
607 rcUpdate
.left
= rcClient
.left
;
608 rcUpdate
.right
= rcClient
.right
;
609 rcUpdate
.top
= (Index
- VisibleFirst
) * infoPtr
->ItemHeight
;
610 rcUpdate
.bottom
= rcUpdate
.top
+ infoPtr
->ItemHeight
;
612 RedrawWindow(infoPtr
->hSelf
,
615 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
622 MakeCheckItemVisible(IN PCHECKLISTWND infoPtr
,
627 INT VisibleFirst
, VisibleItems
, NewPos
;
628 INT Index
= CheckItemToIndex(infoPtr
,
632 Style
= GetWindowLong(infoPtr
->hSelf
,
635 if (Style
& WS_VSCROLL
)
637 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
640 if (Index
<= VisibleFirst
)
646 GetClientRect(infoPtr
->hSelf
,
649 VisibleItems
= (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
;
650 if (Index
- VisibleItems
+ 1 > VisibleFirst
)
652 NewPos
= Index
- VisibleItems
+ 1;
656 NewPos
= VisibleFirst
;
660 if (VisibleFirst
!= NewPos
)
662 SCROLLINFO ScrollInfo
;
664 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
665 ScrollInfo
.fMask
= SIF_POS
;
666 ScrollInfo
.nPos
= NewPos
;
667 NewPos
= SetScrollInfo(infoPtr
->hSelf
,
672 if (VisibleFirst
!= NewPos
)
674 ScrollWindowEx(infoPtr
->hSelf
,
676 (NewPos
- VisibleFirst
) * infoPtr
->ItemHeight
,
681 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
683 RedrawWindow(infoPtr
->hSelf
,
686 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
694 GetIdealItemHeight(IN PCHECKLISTWND infoPtr
)
696 HDC hdc
= GetDC(infoPtr
->hSelf
);
701 HGDIOBJ hOldFont
= SelectObject(hdc
,
704 if(GetTextMetrics(hdc
,
707 height
= tm
.tmHeight
;
717 ReleaseDC(infoPtr
->hSelf
,
726 RetChangeControlFont(IN PCHECKLISTWND infoPtr
,
730 HFONT hOldFont
= infoPtr
->hFont
;
731 infoPtr
->hFont
= hFont
;
733 if (hOldFont
!= hFont
)
735 infoPtr
->ItemHeight
= (2 * CI_TEXT_MARGIN_HEIGHT
) + GetIdealItemHeight(infoPtr
);
738 if (infoPtr
->ShowingCaret
)
741 CreateCaret(infoPtr
->hSelf
,
744 infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
));
747 UpdateControl(infoPtr
,
755 CalculateCheckBoxStyle(IN BOOL Checked
,
764 BtnState
= (Enabled
?
765 (Pushed
? CBS_CHECKEDPRESSED
: (HotTrack
? CBS_CHECKEDHOT
: CBS_CHECKEDNORMAL
)) :
766 CBS_CHECKEDDISABLED
);
770 BtnState
= (Enabled
?
771 (Pushed
? CBS_UNCHECKEDPRESSED
: (HotTrack
? CBS_UNCHECKEDHOT
: CBS_UNCHECKEDNORMAL
)) :
772 CBS_UNCHECKEDDISABLED
);
780 PaintControl(IN PCHECKLISTWND infoPtr
,
785 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
, &rcClient
);
797 Style
= GetWindowLong(infoPtr
->hSelf
,
800 if (Style
& WS_VSCROLL
)
802 ScrollPos
= GetScrollPos(infoPtr
->hSelf
,
810 FirstItem
= FindCheckItemByIndex(infoPtr
,
811 ScrollPos
+ VisibleFirstIndex
);
812 if (FirstItem
!= NULL
)
814 RECT TextRect
, ItemRect
, CheckBox
;
817 COLORREF OldTextColor
;
818 BOOL Enabled
, PrevEnabled
, IsPushed
;
825 Enabled
= IsWindowEnabled(infoPtr
->hSelf
);
826 PrevEnabled
= Enabled
;
829 ItemRect
.right
= rcClient
.right
;
830 ItemRect
.top
= VisibleFirstIndex
* infoPtr
->ItemHeight
;
832 TextRect
.left
= ItemRect
.left
+ CI_TEXT_MARGIN_WIDTH
;
833 TextRect
.right
= ItemRect
.right
- CI_TEXT_MARGIN_WIDTH
;
834 TextRect
.top
= ItemRect
.top
+ CI_TEXT_MARGIN_HEIGHT
;
841 OldTextColor
= SetTextColor(hDC
,
842 infoPtr
->TextColor
[Enabled
]);
844 hOldFont
= SelectObject(hDC
,
847 for (Item
= FirstItem
, CurrentIndex
= VisibleFirstIndex
;
848 Item
!= NULL
&& CurrentIndex
<= LastTouchedIndex
;
849 Item
= Item
->Next
, CurrentIndex
++)
851 TextRect
.bottom
= TextRect
.top
+ infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
);
852 ItemRect
.bottom
= ItemRect
.top
+ infoPtr
->ItemHeight
;
859 if (Enabled
&& PrevEnabled
!= ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
))
861 PrevEnabled
= ((Item
->State
& CIS_DISABLED
) != CIS_DISABLED
);
864 infoPtr
->TextColor
[PrevEnabled
]);
868 ItemHovered
= (Enabled
&& infoPtr
->HoveredCheckItem
== Item
);
871 if (infoPtr
->QuickSearchHitItem
== Item
)
873 COLORREF OldBkColor
, OldFgColor
;
875 SIZE_T TextLen
, HighlightLen
= wcslen(infoPtr
->QuickSearchText
);
877 /* highlight the quicksearch text */
878 if (GetTextExtentPoint32(hDC
,
883 COLORREF HighlightTextColor
, HighlightBackground
;
884 RECT rcHighlight
= TextRect
;
886 HighlightTextColor
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
887 HighlightBackground
= GetSysColor(COLOR_HIGHLIGHT
);
889 rcHighlight
.right
= rcHighlight
.left
+ TextSize
.cx
;
891 InflateRect(&rcHighlight
,
893 CI_TEXT_SELECTIONMARGIN
);
895 OldBkColor
= SetBkColor(hDC
,
896 HighlightBackground
);
897 OldFgColor
= SetTextColor(hDC
,
900 /* draw the highlighted text */
905 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
912 /* draw the remaining part of the text */
913 TextLen
= wcslen(Item
->Name
);
914 if (HighlightLen
< TextLen
)
916 rcHighlight
.left
= rcHighlight
.right
;
917 rcHighlight
.right
= TextRect
.right
;
920 Item
->Name
+ HighlightLen
,
923 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
934 DT_LEFT
| DT_NOPREFIX
| DT_SINGLELINE
| DT_VCENTER
);
937 CheckBox
.top
= TextRect
.top
;
938 CheckBox
.bottom
= TextRect
.bottom
;
940 /* draw the Allow checkbox */
941 IsPushed
= (Enabled
&& Item
== infoPtr
->FocusedCheckItem
&& infoPtr
->HasFocus
&&
942 !(Item
->State
& CIS_ALLOWDISABLED
) && infoPtr
->FocusedCheckItemBox
!= CLB_DENY
&&
943 infoPtr
->FocusedPushed
);
945 CheckBox
.left
= infoPtr
->CheckBoxLeft
[CLB_ALLOW
] - ((TextRect
.bottom
- TextRect
.top
) / 2);
946 CheckBox
.right
= CheckBox
.left
+ (TextRect
.bottom
- TextRect
.top
);
948 if (infoPtr
->ThemeHandle
!= NULL
)
950 INT BtnState
= CalculateCheckBoxStyle(Item
->State
& CIS_ALLOW
,
951 Enabled
&& !(Item
->State
& CIS_ALLOWDISABLED
),
952 (ItemHovered
&& infoPtr
->HoveredCheckItemBox
!= CLB_DENY
),
956 hDrawResult
= DrawThemeBackground(infoPtr
->ThemeHandle
,
966 hDrawResult
= E_FAIL
;
969 /* draw the standard checkbox if no themes are enabled or drawing the
970 themeed control failed */
971 if (FAILED(hDrawResult
))
974 DrawFrameControl(hDC
,
977 DFCS_BUTTONCHECK
| DFCS_FLAT
|
978 ((Item
->State
& CIS_ALLOWDISABLED
) || !Enabled
? DFCS_INACTIVE
: 0) |
979 ((Item
->State
& CIS_ALLOW
) ? DFCS_CHECKED
: 0) |
980 (IsPushed
? DFCS_PUSHED
: 0));
982 if (Item
== infoPtr
->FocusedCheckItem
&& infoPtr
->FocusVisible
&&
984 infoPtr
->FocusedCheckItemBox
!= CLB_DENY
)
986 RECT rcFocus
= CheckBox
;
988 InflateRect (&rcFocus
,
989 CI_TEXT_MARGIN_HEIGHT
,
990 CI_TEXT_MARGIN_HEIGHT
);
996 /* draw the Deny checkbox */
997 IsPushed
= (Enabled
&& Item
== infoPtr
->FocusedCheckItem
&& infoPtr
->HasFocus
&&
998 !(Item
->State
& CIS_DENYDISABLED
) && infoPtr
->FocusedCheckItemBox
== CLB_DENY
&&
999 infoPtr
->FocusedPushed
);
1001 CheckBox
.left
= infoPtr
->CheckBoxLeft
[CLB_DENY
] - ((TextRect
.bottom
- TextRect
.top
) / 2);
1002 CheckBox
.right
= CheckBox
.left
+ (TextRect
.bottom
- TextRect
.top
);
1004 if (infoPtr
->ThemeHandle
!= NULL
)
1006 INT BtnState
= CalculateCheckBoxStyle(Item
->State
& CIS_DENY
,
1007 Enabled
&& !(Item
->State
& CIS_DENYDISABLED
),
1008 (ItemHovered
&& infoPtr
->HoveredCheckItemBox
== CLB_DENY
),
1011 hDrawResult
= DrawThemeBackground(infoPtr
->ThemeHandle
,
1021 hDrawResult
= E_FAIL
;
1024 /* draw the standard checkbox if no themes are enabled or drawing the
1025 themeed control failed */
1026 if (FAILED(hDrawResult
))
1029 DrawFrameControl(hDC
,
1032 DFCS_BUTTONCHECK
| DFCS_FLAT
|
1033 ((Item
->State
& CIS_DENYDISABLED
) || !Enabled
? DFCS_INACTIVE
: 0) |
1034 ((Item
->State
& CIS_DENY
) ? DFCS_CHECKED
: 0) |
1035 (IsPushed
? DFCS_PUSHED
: 0));
1037 if (infoPtr
->HasFocus
&& infoPtr
->FocusVisible
&&
1038 Item
== infoPtr
->FocusedCheckItem
&&
1039 infoPtr
->FocusedCheckItemBox
== CLB_DENY
)
1041 RECT rcFocus
= CheckBox
;
1043 InflateRect (&rcFocus
,
1044 CI_TEXT_MARGIN_HEIGHT
,
1045 CI_TEXT_MARGIN_HEIGHT
);
1051 TextRect
.top
+= infoPtr
->ItemHeight
;
1052 ItemRect
.top
+= infoPtr
->ItemHeight
;
1069 ChangeCheckItemFocus(IN PCHECKLISTWND infoPtr
,
1070 IN PCHECKITEM NewFocus
,
1071 IN UINT NewFocusBox
)
1073 if (NewFocus
!= infoPtr
->FocusedCheckItem
)
1075 PCHECKITEM OldFocus
= infoPtr
->FocusedCheckItem
;
1076 infoPtr
->FocusedCheckItem
= NewFocus
;
1077 infoPtr
->FocusedCheckItemBox
= NewFocusBox
;
1079 if (OldFocus
!= NULL
)
1081 UpdateCheckItem(infoPtr
,
1087 infoPtr
->FocusedCheckItemBox
= NewFocusBox
;
1090 if (NewFocus
!= NULL
)
1092 MakeCheckItemVisible(infoPtr
,
1094 UpdateCheckItem(infoPtr
,
1100 UpdateCheckItemBox(IN PCHECKLISTWND infoPtr
,
1106 INT VisibleFirst
, VisibleItems
;
1107 INT Index
= CheckItemToIndex(infoPtr
,
1111 Style
= GetWindowLong(infoPtr
->hSelf
,
1114 if (Style
& WS_VSCROLL
)
1116 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
1124 if (Index
>= VisibleFirst
)
1126 GetClientRect(infoPtr
->hSelf
,
1129 VisibleItems
= ((rcClient
.bottom
- rcClient
.top
) + infoPtr
->ItemHeight
- 1) / infoPtr
->ItemHeight
;
1131 if (Index
<= VisibleFirst
+ VisibleItems
)
1135 rcUpdate
.left
= rcClient
.left
+ infoPtr
->CheckBoxLeft
[ItemBox
] - (infoPtr
->ItemHeight
/ 2);
1136 rcUpdate
.right
= rcUpdate
.left
+ infoPtr
->ItemHeight
;
1137 rcUpdate
.top
= ((Index
- VisibleFirst
) * infoPtr
->ItemHeight
);
1138 rcUpdate
.bottom
= rcUpdate
.top
+ infoPtr
->ItemHeight
;
1140 RedrawWindow(infoPtr
->hSelf
,
1143 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1151 ChangeCheckItemHotTrack(IN PCHECKLISTWND infoPtr
,
1152 IN PCHECKITEM NewHotTrack
,
1153 IN UINT NewHotTrackBox
)
1155 if (NewHotTrack
!= infoPtr
->HoveredCheckItem
)
1157 PCHECKITEM OldHotTrack
= infoPtr
->HoveredCheckItem
;
1158 UINT OldHotTrackBox
= infoPtr
->HoveredCheckItemBox
;
1160 infoPtr
->HoveredCheckItem
= NewHotTrack
;
1161 infoPtr
->HoveredCheckItemBox
= NewHotTrackBox
;
1163 if (OldHotTrack
!= NULL
)
1165 UpdateCheckItemBox(infoPtr
,
1172 infoPtr
->HoveredCheckItemBox
= NewHotTrackBox
;
1175 if (NewHotTrack
!= NULL
)
1177 UpdateCheckItemBox(infoPtr
,
1185 ChangeCheckBox(IN PCHECKLISTWND infoPtr
,
1186 IN PCHECKITEM CheckItem
,
1187 IN UINT CheckItemBox
)
1189 DWORD NewState
, OldState
= CheckItem
->State
;
1190 DWORD CheckedBit
= ((infoPtr
->FocusedCheckItemBox
== CLB_DENY
) ? CIS_DENY
: CIS_ALLOW
);
1191 BOOL Checked
= (CheckItem
->State
& CheckedBit
) != 0;
1193 NewState
= (Checked
? OldState
& ~CheckedBit
: OldState
| CheckedBit
);
1195 /* FIXME - send a notification message */
1197 CheckItem
->State
= NewState
;
1201 DisplayCaret(IN PCHECKLISTWND infoPtr
)
1203 if (IsWindowEnabled(infoPtr
->hSelf
) && !infoPtr
->ShowingCaret
)
1205 infoPtr
->ShowingCaret
= TRUE
;
1207 CreateCaret(infoPtr
->hSelf
,
1209 infoPtr
->CaretWidth
,
1210 infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
));
1212 ShowCaret(infoPtr
->hSelf
);
1217 RemoveCaret(IN PCHECKLISTWND infoPtr
)
1219 if (IsWindowEnabled(infoPtr
->hSelf
) && infoPtr
->ShowingCaret
)
1221 infoPtr
->ShowingCaret
= FALSE
;
1223 HideCaret(infoPtr
->hSelf
);
1229 KillQuickSearchTimers(IN PCHECKLISTWND infoPtr
)
1231 KillTimer(infoPtr
->hSelf
,
1232 TIMER_ID_SETHITFOCUS
);
1233 KillTimer(infoPtr
->hSelf
,
1234 TIMER_ID_RESETQUICKSEARCH
);
1238 MapItemToRect(IN PCHECKLISTWND infoPtr
,
1239 IN PCHECKITEM CheckItem
,
1242 INT Index
= CheckItemToIndex(infoPtr
,
1250 GetClientRect(infoPtr
->hSelf
, &rcClient
);
1252 Style
= GetWindowLong(infoPtr
->hSelf
,
1255 if (Style
& WS_VSCROLL
)
1257 VisibleFirst
= GetScrollPos(infoPtr
->hSelf
,
1265 prcItem
->left
= rcClient
.left
;
1266 prcItem
->right
= rcClient
.right
;
1267 prcItem
->top
= (Index
- VisibleFirst
) * infoPtr
->ItemHeight
;
1268 prcItem
->bottom
= prcItem
->top
+ infoPtr
->ItemHeight
;
1275 prcItem
->bottom
= 0;
1280 UpdateCaretPos(IN PCHECKLISTWND infoPtr
)
1282 if (infoPtr
->ShowingCaret
&& infoPtr
->QuickSearchHitItem
!= NULL
)
1284 HDC hDC
= GetDC(infoPtr
->hSelf
);
1288 HGDIOBJ hOldFont
= SelectObject(hDC
,
1294 if (infoPtr
->QuickSearchText
[0] == L
'\0' ||
1295 GetTextExtentPoint32(hDC
,
1296 infoPtr
->QuickSearchHitItem
->Name
,
1297 wcslen(infoPtr
->QuickSearchText
),
1302 MapItemToRect(infoPtr
,
1303 infoPtr
->QuickSearchHitItem
,
1306 /* actually change the caret position */
1307 SetCaretPos(rcItem
.left
+ CI_TEXT_MARGIN_WIDTH
+ TextSize
.cx
,
1308 rcItem
.top
+ CI_TEXT_MARGIN_HEIGHT
);
1314 ReleaseDC(infoPtr
->hSelf
,
1321 EscapeQuickSearch(IN PCHECKLISTWND infoPtr
)
1323 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
)
1325 PCHECKITEM OldHit
= infoPtr
->QuickSearchHitItem
;
1327 infoPtr
->QuickSearchHitItem
= NULL
;
1328 infoPtr
->QuickSearchText
[0] = L
'\0';
1330 /* scroll back to the focused item */
1331 if (infoPtr
->FocusedCheckItem
!= NULL
)
1333 MakeCheckItemVisible(infoPtr
,
1334 infoPtr
->FocusedCheckItem
);
1337 /* repaint the old search hit item if it's still visible */
1338 UpdateCheckItem(infoPtr
,
1341 KillQuickSearchTimers(infoPtr
);
1343 RemoveCaret(infoPtr
);
1348 ChangeSearchHit(IN PCHECKLISTWND infoPtr
,
1349 IN PCHECKITEM NewHit
)
1351 PCHECKITEM OldHit
= infoPtr
->QuickSearchHitItem
;
1353 infoPtr
->QuickSearchHitItem
= NewHit
;
1355 if (OldHit
!= NewHit
)
1357 /* scroll to the new search hit */
1358 MakeCheckItemVisible(infoPtr
,
1361 /* repaint the old hit if present and visible */
1364 UpdateCheckItem(infoPtr
,
1369 /* show the caret the first time we find an item */
1370 DisplayCaret(infoPtr
);
1374 UpdateCaretPos(infoPtr
);
1376 UpdateCheckItem(infoPtr
,
1379 /* kill the reset timer and restart the set hit focus timer */
1380 KillTimer(infoPtr
->hSelf
,
1381 TIMER_ID_RESETQUICKSEARCH
);
1382 if (infoPtr
->QuickSearchSetFocusDelay
!= 0)
1384 SetTimer(infoPtr
->hSelf
,
1385 TIMER_ID_SETHITFOCUS
,
1386 infoPtr
->QuickSearchSetFocusDelay
,
1392 QuickSearchFindHit(IN PCHECKLISTWND infoPtr
,
1395 if (infoPtr
->QuickSearchEnabled
)
1405 Ret
= infoPtr
->QuickSearchHitItem
!= NULL
;
1408 /* NOTE: QuickSearchHitItem definitely has at least one
1409 enabled check box, the user can't search for disabled
1412 ChangeCheckItemFocus(infoPtr
,
1413 infoPtr
->QuickSearchHitItem
,
1414 ((!(infoPtr
->QuickSearchHitItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
));
1416 EscapeQuickSearch(infoPtr
);
1423 if (infoPtr
->QuickSearchHitItem
!= NULL
)
1425 INT SearchLen
= wcslen(infoPtr
->QuickSearchText
);
1428 /* delete the last character */
1429 infoPtr
->QuickSearchText
[--SearchLen
] = L
'\0';
1434 NewHit
= FindCheckItem(infoPtr
,
1435 infoPtr
->QuickSearchText
);
1439 /* change the search hit */
1440 ChangeSearchHit(infoPtr
,
1450 EscapeQuickSearch(infoPtr
);
1458 INT SearchLen
= wcslen(infoPtr
->QuickSearchText
);
1459 if (SearchLen
< (sizeof(infoPtr
->QuickSearchText
) / sizeof(infoPtr
->QuickSearchText
[0])) - 1)
1461 infoPtr
->QuickSearchText
[SearchLen
++] = c
;
1462 infoPtr
->QuickSearchText
[SearchLen
] = L
'\0';
1464 NewHit
= FindCheckItem(infoPtr
,
1465 infoPtr
->QuickSearchText
);
1468 /* change the search hit */
1469 ChangeSearchHit(infoPtr
,
1476 /* reset the input */
1477 infoPtr
->QuickSearchText
[--SearchLen
] = L
'\0';
1489 static LRESULT CALLBACK
1490 CheckListWndProc(IN HWND hwnd
,
1495 PCHECKLISTWND infoPtr
;
1498 infoPtr
= (PCHECKLISTWND
)GetWindowLongPtr(hwnd
,
1501 if (infoPtr
== NULL
&& uMsg
!= WM_CREATE
)
1503 return DefWindowProc(hwnd
,
1519 if (GetUpdateRect(hwnd
,
1523 hdc
= (wParam
!= 0 ? (HDC
)wParam
: BeginPaint(hwnd
, &ps
));
1525 PaintControl(infoPtr
,
1542 HWND hWndCapture
= GetCapture();
1544 pt
.x
= (LONG
)LOWORD(lParam
);
1545 pt
.y
= (LONG
)HIWORD(lParam
);
1548 /* handle hovering checkboxes */
1549 if (hWndCapture
== NULL
&& infoPtr
->ThemeHandle
!= NULL
)
1551 TRACKMOUSEEVENT tme
;
1552 PCHECKITEM HotTrackItem
;
1553 UINT HotTrackItemBox
;
1555 HotTrackItem
= PtToCheckItemBox(infoPtr
,
1559 if (HotTrackItem
!= NULL
&& InCheckBox
)
1561 if (infoPtr
->HoveredCheckItem
!= HotTrackItem
||
1562 infoPtr
->HoveredCheckItemBox
!= HotTrackItemBox
)
1564 ChangeCheckItemHotTrack(infoPtr
,
1571 ChangeCheckItemHotTrack(infoPtr
,
1576 tme
.cbSize
= sizeof(tme
);
1577 tme
.dwFlags
= TME_LEAVE
;
1578 tme
.hwndTrack
= hwnd
;
1579 tme
.dwHoverTime
= infoPtr
->HoverTime
;
1581 TrackMouseEvent(&tme
);
1585 if (hWndCapture
== hwnd
&& infoPtr
->FocusedCheckItem
!= NULL
)
1591 PtItem
= PtToCheckItemBox(infoPtr
,
1596 OldPushed
= infoPtr
->FocusedPushed
;
1597 infoPtr
->FocusedPushed
= InCheckBox
&& infoPtr
->FocusedCheckItem
== PtItem
&&
1598 infoPtr
->FocusedCheckItemBox
== PtItemBox
;
1600 if (OldPushed
!= infoPtr
->FocusedPushed
)
1602 UpdateCheckItemBox(infoPtr
,
1603 infoPtr
->FocusedCheckItem
,
1604 infoPtr
->FocusedCheckItemBox
);
1613 SCROLLINFO ScrollInfo
;
1615 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
1616 ScrollInfo
.fMask
= SIF_RANGE
| SIF_POS
;
1618 if (GetScrollInfo(hwnd
,
1622 INT OldPos
= ScrollInfo
.nPos
;
1624 switch (LOWORD(wParam
))
1627 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1631 if (ScrollInfo
.nPos
< ScrollInfo
.nMax
)
1638 if (ScrollInfo
.nPos
> 0)
1649 /* don't use ScrollInfo.nPage because we should only scroll
1650 down by the number of completely visible list entries.
1651 nPage however also includes the partly cropped list
1652 item at the bottom of the control */
1654 GetClientRect(hwnd
, &rcClient
);
1655 ScrollLines
= max(1, (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
);
1657 if (ScrollInfo
.nPos
+ ScrollLines
<= ScrollInfo
.nMax
)
1659 ScrollInfo
.nPos
+= ScrollLines
;
1663 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1673 /* don't use ScrollInfo.nPage because we should only scroll
1674 down by the number of completely visible list entries.
1675 nPage however also includes the partly cropped list
1676 item at the bottom of the control */
1678 GetClientRect(hwnd
, &rcClient
);
1679 ScrollLines
= max(1, (rcClient
.bottom
- rcClient
.top
) / infoPtr
->ItemHeight
);
1681 if (ScrollInfo
.nPos
>= ScrollLines
)
1683 ScrollInfo
.nPos
-= ScrollLines
;
1687 ScrollInfo
.nPos
= 0;
1692 case SB_THUMBPOSITION
:
1695 ScrollInfo
.nPos
= HIWORD(wParam
);
1700 ScrollInfo
.nPos
= 0;
1704 if (OldPos
!= ScrollInfo
.nPos
)
1706 ScrollInfo
.fMask
= SIF_POS
;
1708 ScrollInfo
.nPos
= SetScrollInfo(hwnd
,
1713 if (OldPos
!= ScrollInfo
.nPos
)
1715 ScrollWindowEx(hwnd
,
1717 (OldPos
- ScrollInfo
.nPos
) * infoPtr
->ItemHeight
,
1722 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
1727 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1737 PCHECKITEM Item
= AddCheckItem(infoPtr
,
1743 UpdateControl(infoPtr
,
1745 Ret
= (LRESULT
)Index
;
1756 PCHECKITEM Item
= FindCheckItemByIndex(infoPtr
,
1760 Ret
= DeleteCheckItem(infoPtr
,
1764 UpdateControl(infoPtr
,
1775 case CLM_SETITEMSTATE
:
1777 PCHECKITEM Item
= FindCheckItemByIndex(infoPtr
,
1781 DWORD OldState
= Item
->State
;
1782 Item
->State
= (DWORD
)lParam
& CIS_MASK
;
1784 if (Item
->State
!= OldState
)
1786 /* revert the focus if the currently focused item is about
1788 if (Item
== infoPtr
->FocusedCheckItem
&&
1789 (Item
->State
& CIS_DISABLED
))
1791 if (infoPtr
->FocusedCheckItemBox
== CLB_DENY
)
1793 if (Item
->State
& CIS_DENYDISABLED
)
1795 infoPtr
->FocusedCheckItem
= NULL
;
1800 if (Item
->State
& CIS_ALLOWDISABLED
)
1802 infoPtr
->FocusedCheckItem
= NULL
;
1807 UpdateControl(infoPtr
,
1819 case CLM_GETITEMCOUNT
:
1821 Ret
= infoPtr
->CheckItemCount
;
1827 ClearCheckItems(infoPtr
);
1828 UpdateControl(infoPtr
,
1833 case CLM_SETCHECKBOXCOLUMN
:
1835 infoPtr
->CheckBoxLeft
[wParam
!= CLB_DENY
] = (UINT
)lParam
;
1840 case CLM_GETCHECKBOXCOLUMN
:
1842 Ret
= (LRESULT
)infoPtr
->CheckBoxLeft
[wParam
!= CLB_DENY
];
1846 case CLM_CLEARCHECKBOXES
:
1848 Ret
= (LRESULT
)ClearCheckBoxes(infoPtr
);
1851 UpdateControl(infoPtr
,
1857 case CLM_ENABLEQUICKSEARCH
:
1861 EscapeQuickSearch(infoPtr
);
1863 infoPtr
->QuickSearchEnabled
= (wParam
!= 0);
1867 case CLM_SETQUICKSEARCH_TIMEOUT_RESET
:
1869 infoPtr
->QuickSearchResetDelay
= (UINT
)wParam
;
1873 case CLM_SETQUICKSEARCH_TIMEOUT_SETFOCUS
:
1875 infoPtr
->QuickSearchSetFocusDelay
= (UINT
)wParam
;
1881 Ret
= (LRESULT
)RetChangeControlFont(infoPtr
,
1889 Ret
= (LRESULT
)infoPtr
->hFont
;
1893 case WM_STYLECHANGED
:
1895 LPSTYLESTRUCT Style
= (LPSTYLESTRUCT
)lParam
;
1897 if (wParam
== GWL_STYLE
)
1899 BOOL AllowChangeStyle
;
1901 /* don't allow the control to enable/disable the vertical scrollbar
1902 if this message was invoked due to such a window style change! */
1903 AllowChangeStyle
= ((Style
->styleNew
& WS_VSCROLL
) == (Style
->styleOld
& WS_VSCROLL
));
1905 UpdateControl(infoPtr
,
1913 EscapeQuickSearch(infoPtr
);
1915 UpdateControl(infoPtr
,
1923 UINT ScrollLines
= 3;
1925 SystemParametersInfo(SPI_GETWHEELSCROLLLINES
,
1929 ScrollDelta
= 0 - (SHORT
)HIWORD(wParam
);
1931 if (ScrollLines
!= 0 &&
1932 abs(ScrollDelta
) >= WHEEL_DELTA
)
1934 SCROLLINFO ScrollInfo
;
1936 ScrollInfo
.cbSize
= sizeof(ScrollInfo
);
1937 ScrollInfo
.fMask
= SIF_RANGE
| SIF_POS
;
1939 if (GetScrollInfo(hwnd
,
1943 INT OldPos
= ScrollInfo
.nPos
;
1945 ScrollInfo
.nPos
+= (ScrollDelta
/ WHEEL_DELTA
) * ScrollLines
;
1946 if (ScrollInfo
.nPos
< 0)
1947 ScrollInfo
.nPos
= 0;
1948 else if (ScrollInfo
.nPos
> ScrollInfo
.nMax
)
1949 ScrollInfo
.nPos
= ScrollInfo
.nMax
;
1951 if (OldPos
!= ScrollInfo
.nPos
)
1953 ScrollInfo
.fMask
= SIF_POS
;
1955 ScrollInfo
.nPos
= SetScrollInfo(hwnd
,
1960 if (OldPos
!= ScrollInfo
.nPos
)
1962 ScrollWindowEx(hwnd
,
1964 (OldPos
- ScrollInfo
.nPos
) * infoPtr
->ItemHeight
,
1969 SW_INVALIDATE
| SW_SCROLLCHILDREN
);
1974 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1984 infoPtr
->HasFocus
= TRUE
;
1986 if (infoPtr
->FocusedCheckItem
== NULL
)
1988 BOOL Shift
= GetKeyState(VK_SHIFT
) & 0x8000;
1989 infoPtr
->FocusedCheckItem
= FindEnabledCheckBox(infoPtr
,
1991 &infoPtr
->FocusedCheckItemBox
);
1993 if (infoPtr
->FocusedCheckItem
!= NULL
)
1995 MakeCheckItemVisible(infoPtr
,
1996 infoPtr
->FocusedCheckItem
);
1998 UpdateCheckItem(infoPtr
,
1999 infoPtr
->FocusedCheckItem
);
2006 EscapeQuickSearch(infoPtr
);
2008 infoPtr
->HasFocus
= FALSE
;
2009 if (infoPtr
->FocusedCheckItem
!= NULL
)
2011 infoPtr
->FocusedPushed
= FALSE
;
2013 UpdateCheckItem(infoPtr
,
2014 infoPtr
->FocusedCheckItem
);
2019 case WM_LBUTTONDBLCLK
:
2020 case WM_LBUTTONDOWN
:
2021 case WM_MBUTTONDOWN
:
2022 case WM_RBUTTONDOWN
:
2024 if (IsWindowEnabled(hwnd
))
2026 PCHECKITEM NewFocus
;
2027 INT NewFocusBox
= 0;
2030 BOOL ChangeFocus
, Capture
= FALSE
;
2032 pt
.x
= (LONG
)LOWORD(lParam
);
2033 pt
.y
= (LONG
)HIWORD(lParam
);
2035 NewFocus
= PtToCheckItemBox(infoPtr
,
2039 if (NewFocus
!= NULL
)
2041 if (NewFocus
->State
& ((NewFocusBox
!= CLB_DENY
) ? CIS_ALLOWDISABLED
: CIS_DENYDISABLED
))
2043 /* the user clicked on a disabled checkbox, try to set
2044 the focus to the other one or not change it at all */
2048 ChangeFocus
= ((NewFocus
->State
& CIS_DISABLED
) != CIS_DISABLED
);
2051 NewFocusBox
= ((NewFocusBox
!= CLB_DENY
) ? CLB_DENY
: CLB_ALLOW
);
2059 if (InCheckBox
&& ChangeFocus
&& GetCapture() == NULL
&&
2060 (uMsg
== WM_LBUTTONDOWN
|| uMsg
== WM_LBUTTONDBLCLK
))
2062 infoPtr
->FocusedPushed
= TRUE
;
2073 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
&&
2074 infoPtr
->QuickSearchHitItem
!= NewFocus
)
2076 EscapeQuickSearch(infoPtr
);
2079 ChangeCheckItemFocus(infoPtr
,
2084 if (!infoPtr
->HasFocus
)
2099 if (GetCapture() == hwnd
)
2101 if (infoPtr
->FocusedCheckItem
!= NULL
&& infoPtr
->FocusedPushed
)
2108 pt
.x
= (LONG
)LOWORD(lParam
);
2109 pt
.y
= (LONG
)HIWORD(lParam
);
2111 infoPtr
->FocusedPushed
= FALSE
;
2113 PtItem
= PtToCheckItemBox(infoPtr
,
2118 if (PtItem
== infoPtr
->FocusedCheckItem
&& InCheckBox
&&
2119 PtItemBox
== infoPtr
->FocusedCheckItemBox
)
2121 ChangeCheckBox(infoPtr
,
2126 UpdateCheckItemBox(infoPtr
,
2127 infoPtr
->FocusedCheckItem
,
2128 infoPtr
->FocusedCheckItemBox
);
2142 if (GetCapture() == NULL
&&
2143 !QuickSearchFindHit(infoPtr
,
2146 if (infoPtr
->FocusedCheckItem
!= NULL
&&
2147 (infoPtr
->QuickSearchHitItem
== NULL
||
2148 infoPtr
->QuickSearchHitItem
== infoPtr
->FocusedCheckItem
))
2150 BOOL OldPushed
= infoPtr
->FocusedPushed
;
2151 infoPtr
->FocusedPushed
= TRUE
;
2153 if (infoPtr
->FocusedPushed
!= OldPushed
)
2155 MakeCheckItemVisible(infoPtr
,
2156 infoPtr
->FocusedCheckItem
);
2158 UpdateCheckItemBox(infoPtr
,
2159 infoPtr
->FocusedCheckItem
,
2160 infoPtr
->FocusedCheckItemBox
);
2169 if (GetCapture() == NULL
&&
2170 !QuickSearchFindHit(infoPtr
,
2173 if (infoPtr
->FocusedCheckItem
!= NULL
&&
2174 infoPtr
->QuickSearchHitItem
== NULL
)
2176 MakeCheckItemVisible(infoPtr
,
2177 infoPtr
->FocusedCheckItem
);
2179 ChangeCheckBox(infoPtr
,
2180 infoPtr
->FocusedCheckItem
,
2181 infoPtr
->FocusedCheckItemBox
);
2183 UpdateCheckItemBox(infoPtr
,
2184 infoPtr
->FocusedCheckItem
,
2185 infoPtr
->FocusedCheckItemBox
);
2193 if (GetCapture() == NULL
)
2195 PCHECKITEM NewFocus
;
2196 UINT NewFocusBox
= 0;
2197 BOOL Shift
= GetKeyState(VK_SHIFT
) & 0x8000;
2199 EscapeQuickSearch(infoPtr
);
2201 NewFocus
= FindEnabledCheckBox(infoPtr
,
2205 if (!infoPtr
->FocusVisible
)
2207 /* change the UI status */
2208 SendMessage(GetAncestor(hwnd
, GA_ROOT
),
2210 MAKEWPARAM(UIS_INITIALIZE
, UISF_HIDEFOCUS
),
2214 ChangeCheckItemFocus(infoPtr
,
2223 Ret
= DefWindowProc(hwnd
,
2235 if (wParam
== VK_SPACE
&& IsWindowEnabled(hwnd
) &&
2236 infoPtr
->FocusedCheckItem
!= NULL
&&
2237 infoPtr
->FocusedPushed
)
2239 infoPtr
->FocusedPushed
= FALSE
;
2241 ChangeCheckBox(infoPtr
,
2242 infoPtr
->FocusedCheckItem
,
2243 infoPtr
->FocusedCheckItemBox
);
2245 UpdateCheckItemBox(infoPtr
,
2246 infoPtr
->FocusedCheckItem
,
2247 infoPtr
->FocusedCheckItemBox
);
2257 virtKey
= (lParam
!= 0 ? (INT
)((LPMSG
)lParam
)->wParam
: 0);
2262 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
)
2264 Ret
|= DLGC_WANTCHARS
| DLGC_WANTMESSAGE
;
2268 Ret
|= DLGC_WANTMESSAGE
;
2277 BOOL Shift
= GetKeyState(VK_SHIFT
) & 0x8000;
2279 EnabledBox
= FindEnabledCheckBox(infoPtr
,
2282 Ret
|= (EnabledBox
? DLGC_WANTTAB
: DLGC_WANTCHARS
);
2288 if (infoPtr
->QuickSearchEnabled
)
2290 Ret
|= DLGC_WANTCHARS
;
2300 QuickSearchFindHit(infoPtr
,
2305 case WM_SYSCOLORCHANGE
:
2307 infoPtr
->TextColor
[0] = GetSysColor(COLOR_GRAYTEXT
);
2308 infoPtr
->TextColor
[1] = GetSysColor(COLOR_WINDOWTEXT
);
2315 if (infoPtr
->HoveredCheckItem
!= NULL
)
2317 /* reset and repaint the hovered check item box */
2318 ChangeCheckItemHotTrack(infoPtr
,
2325 case WM_THEMECHANGED
:
2327 if (infoPtr
->ThemeHandle
!= NULL
)
2329 CloseThemeData(infoPtr
->ThemeHandle
);
2330 infoPtr
->ThemeHandle
= NULL
;
2334 infoPtr
->ThemeHandle
= OpenThemeData(infoPtr
->hSelf
,
2341 case WM_SETTINGCHANGE
:
2343 DWORD OldCaretWidth
= infoPtr
->CaretWidth
;
2346 /* update the hover time */
2347 if (!SystemParametersInfo(SPI_GETMOUSEHOVERTIME
,
2349 &infoPtr
->HoverTime
,
2352 infoPtr
->HoverTime
= HOVER_DEFAULT
;
2356 /* update the caret */
2357 if (!SystemParametersInfo(SPI_GETCARETWIDTH
,
2359 &infoPtr
->CaretWidth
,
2362 infoPtr
->CaretWidth
= 2;
2364 if (OldCaretWidth
!= infoPtr
->CaretWidth
&& infoPtr
->ShowingCaret
)
2369 infoPtr
->CaretWidth
,
2370 infoPtr
->ItemHeight
- (2 * CI_TEXT_MARGIN_HEIGHT
));
2377 UpdateControl(infoPtr
,
2382 case WM_UPDATEUISTATE
:
2384 if (HIWORD(wParam
) & UISF_HIDEFOCUS
)
2386 BOOL OldFocusVisible
= infoPtr
->FocusVisible
;
2388 infoPtr
->FocusVisible
= (LOWORD(wParam
) == UIS_CLEAR
);
2390 if (infoPtr
->FocusVisible
!= OldFocusVisible
&&
2391 infoPtr
->FocusedCheckItem
!= NULL
)
2393 UpdateCheckItemBox(infoPtr
,
2394 infoPtr
->FocusedCheckItem
,
2395 infoPtr
->FocusedCheckItemBox
);
2405 case TIMER_ID_SETHITFOCUS
:
2407 /* kill the timer */
2411 if (infoPtr
->QuickSearchEnabled
&& infoPtr
->QuickSearchHitItem
!= NULL
)
2413 /* change the focus to the hit item, this item has to have
2414 at least one enabled checkbox! */
2415 ChangeCheckItemFocus(infoPtr
,
2416 infoPtr
->QuickSearchHitItem
,
2417 ((!(infoPtr
->QuickSearchHitItem
->State
& CIS_ALLOWDISABLED
)) ? CLB_ALLOW
: CLB_DENY
));
2419 /* start the timer to reset quicksearch */
2420 if (infoPtr
->QuickSearchResetDelay
!= 0)
2423 TIMER_ID_RESETQUICKSEARCH
,
2424 infoPtr
->QuickSearchResetDelay
,
2430 case TIMER_ID_RESETQUICKSEARCH
:
2432 /* kill the timer */
2436 /* escape quick search */
2437 EscapeQuickSearch(infoPtr
);
2446 infoPtr
= HeapAlloc(GetProcessHeap(),
2448 sizeof(CHECKLISTWND
));
2449 if (infoPtr
!= NULL
)
2453 infoPtr
->hSelf
= hwnd
;
2454 infoPtr
->hNotify
= ((LPCREATESTRUCTW
)lParam
)->hwndParent
;
2456 SetWindowLongPtr(hwnd
,
2458 (DWORD_PTR
)infoPtr
);
2460 infoPtr
->CheckItemListHead
= NULL
;
2461 infoPtr
->CheckItemCount
= 0;
2463 if (!SystemParametersInfo(SPI_GETCARETWIDTH
,
2465 &infoPtr
->CaretWidth
,
2468 infoPtr
->CaretWidth
= 2;
2470 infoPtr
->ItemHeight
= 10;
2471 infoPtr
->ShowingCaret
= FALSE
;
2473 infoPtr
->HasFocus
= FALSE
;
2474 infoPtr
->FocusedCheckItem
= NULL
;
2475 infoPtr
->FocusedCheckItemBox
= 0;
2476 infoPtr
->FocusedPushed
= FALSE
;
2478 infoPtr
->TextColor
[0] = GetSysColor(COLOR_GRAYTEXT
);
2479 infoPtr
->TextColor
[1] = GetSysColor(COLOR_WINDOWTEXT
);
2481 GetClientRect(hwnd
, &rcClient
);
2483 infoPtr
->CheckBoxLeft
[0] = rcClient
.right
- 30;
2484 infoPtr
->CheckBoxLeft
[1] = rcClient
.right
- 15;
2486 infoPtr
->QuickSearchEnabled
= FALSE
;
2487 infoPtr
->QuickSearchText
[0] = L
'\0';
2489 infoPtr
->QuickSearchSetFocusDelay
= DEFAULT_QUICKSEARCH_SETFOCUS_DELAY
;
2490 infoPtr
->QuickSearchResetDelay
= DEFAULT_QUICKSEARCH_RESET_DELAY
;
2493 infoPtr
->HoveredCheckItem
= NULL
;
2494 infoPtr
->HoveredCheckItemBox
= 0;
2495 if (!SystemParametersInfo(SPI_GETMOUSEHOVERTIME
,
2497 &infoPtr
->HoverTime
,
2500 infoPtr
->HoverTime
= HOVER_DEFAULT
;
2505 infoPtr
->ThemeHandle
= OpenThemeData(infoPtr
->hSelf
,
2510 infoPtr
->ThemeHandle
= NULL
;
2514 infoPtr
->FocusVisible
= !(SendMessage(hwnd
,
2517 0) & UISF_HIDEFOCUS
);
2528 if (infoPtr
->ShowingCaret
)
2533 ClearCheckItems(infoPtr
);
2536 if (infoPtr
->ThemeHandle
!= NULL
)
2538 CloseThemeData(infoPtr
->ThemeHandle
);
2542 HeapFree(GetProcessHeap(),
2545 SetWindowLongPtr(hwnd
,
2553 Ret
= DefWindowProc(hwnd
,
2565 RegisterCheckListControl(HINSTANCE hInstance
)
2569 ZeroMemory(&wc
, sizeof(WNDCLASS
));
2571 wc
.style
= CS_DBLCLKS
;
2572 wc
.lpfnWndProc
= CheckListWndProc
;
2574 wc
.cbWndExtra
= sizeof(PCHECKLISTWND
);
2575 wc
.hInstance
= hInstance
;
2576 wc
.hCursor
= LoadCursor(0, (LPWSTR
)IDC_ARROW
);
2577 wc
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
2578 wc
.lpszClassName
= L
"CHECKLIST_ACLUI";
2580 return RegisterClass(&wc
) != 0;
2584 UnregisterCheckListControl(VOID
)
2586 UnregisterClass(L
"CHECKLIST_ACLUI",