Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenchecklist.c
Go to the documentation of this file.
00001 /* 00002 * ReactOS Access Control List Editor 00003 * Copyright (C) 2004-2005 ReactOS Team 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00018 */ 00019 /* $Id: checklist.c 43790 2009-10-27 10:34:16Z dgorbachev $ 00020 * 00021 * PROJECT: ReactOS Access Control List Editor 00022 * FILE: lib/aclui/checklist.c 00023 * PURPOSE: Access Control List Editor 00024 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com> 00025 * 00026 * UPDATE HISTORY: 00027 * 07/01/2005 Created 00028 */ 00029 #include <precomp.h> 00030 00031 #define NDEBUG 00032 #include <debug.h> 00033 00034 static const WCHAR szCheckListWndClass[] = L"CHECKLIST_ACLUI"; 00035 00036 #define CI_TEXT_MARGIN_WIDTH (8) 00037 #define CI_TEXT_MARGIN_HEIGHT (3) 00038 #define CI_TEXT_SELECTIONMARGIN (1) 00039 00040 #define TIMER_ID_SETHITFOCUS (1) 00041 #define TIMER_ID_RESETQUICKSEARCH (2) 00042 00043 #define DEFAULT_QUICKSEARCH_SETFOCUS_DELAY (2000) 00044 #define DEFAULT_QUICKSEARCH_RESET_DELAY (3000) 00045 00046 typedef struct _CHECKITEM 00047 { 00048 struct _CHECKITEM *Next; 00049 ACCESS_MASK AccessMask; 00050 DWORD State; 00051 WCHAR Name[1]; 00052 } CHECKITEM, *PCHECKITEM; 00053 00054 typedef struct _CHECKLISTWND 00055 { 00056 HWND hSelf; 00057 HWND hNotify; 00058 HFONT hFont; 00059 00060 PCHECKITEM CheckItemListHead; 00061 UINT CheckItemCount; 00062 00063 INT ItemHeight; 00064 00065 PCHECKITEM FocusedCheckItem; 00066 UINT FocusedCheckItemBox; 00067 00068 COLORREF TextColor[2]; 00069 INT CheckBoxLeft[2]; 00070 00071 PCHECKITEM QuickSearchHitItem; 00072 WCHAR QuickSearchText[65]; 00073 UINT QuickSearchSetFocusDelay; 00074 UINT QuickSearchResetDelay; 00075 00076 DWORD CaretWidth; 00077 00078 DWORD UIState; 00079 00080 #if SUPPORT_UXTHEME 00081 PCHECKITEM HoveredCheckItem; 00082 UINT HoveredCheckItemBox; 00083 UINT HoverTime; 00084 00085 HTHEME ThemeHandle; 00086 #endif 00087 00088 UINT HasFocus : 1; 00089 UINT FocusedPushed : 1; 00090 UINT QuickSearchEnabled : 1; 00091 UINT ShowingCaret : 1; 00092 } CHECKLISTWND, *PCHECKLISTWND; 00093 00094 static VOID EscapeQuickSearch(IN PCHECKLISTWND infoPtr); 00095 #if SUPPORT_UXTHEME 00096 static VOID ChangeCheckItemHotTrack(IN PCHECKLISTWND infoPtr, 00097 IN PCHECKITEM NewHotTrack, 00098 IN UINT NewHotTrackBox); 00099 #endif 00100 static VOID ChangeCheckItemFocus(IN PCHECKLISTWND infoPtr, 00101 IN PCHECKITEM NewFocus, 00102 IN UINT NewFocusBox); 00103 00104 /******************************************************************************/ 00105 00106 static LRESULT 00107 NotifyControlParent(IN PCHECKLISTWND infoPtr, 00108 IN UINT code, 00109 IN OUT PVOID data) 00110 { 00111 LRESULT Ret = 0; 00112 00113 if (infoPtr->hNotify != NULL) 00114 { 00115 LPNMHDR pnmh = (LPNMHDR)data; 00116 00117 pnmh->hwndFrom = infoPtr->hSelf; 00118 pnmh->idFrom = GetWindowLongPtr(infoPtr->hSelf, 00119 GWLP_ID); 00120 pnmh->code = code; 00121 00122 Ret = SendMessage(infoPtr->hNotify, 00123 WM_NOTIFY, 00124 (WPARAM)pnmh->idFrom, 00125 (LPARAM)pnmh); 00126 } 00127 00128 return Ret; 00129 } 00130 00131 static PCHECKITEM 00132 FindCheckItemByIndex(IN PCHECKLISTWND infoPtr, 00133 IN INT Index) 00134 { 00135 PCHECKITEM Item, Found = NULL; 00136 00137 if (Index >= 0) 00138 { 00139 for (Item = infoPtr->CheckItemListHead; 00140 Item != NULL; 00141 Item = Item->Next) 00142 { 00143 if (Index == 0) 00144 { 00145 Found = Item; 00146 break; 00147 } 00148 00149 Index--; 00150 } 00151 } 00152 00153 return Found; 00154 } 00155 00156 static INT 00157 FindCheckItemIndexByAccessMask(IN PCHECKLISTWND infoPtr, 00158 IN ACCESS_MASK AccessMask) 00159 { 00160 PCHECKITEM Item; 00161 INT Index = 0, Found = -1; 00162 00163 for (Item = infoPtr->CheckItemListHead; 00164 Item != NULL; 00165 Item = Item->Next) 00166 { 00167 if (Item->AccessMask == AccessMask) 00168 { 00169 Found = Index; 00170 break; 00171 } 00172 00173 Index++; 00174 } 00175 00176 return Found; 00177 } 00178 00179 static INT 00180 CheckItemToIndex(IN PCHECKLISTWND infoPtr, 00181 IN PCHECKITEM Item) 00182 { 00183 PCHECKITEM CurItem; 00184 INT Index; 00185 00186 for (CurItem = infoPtr->CheckItemListHead, Index = 0; 00187 CurItem != NULL; 00188 CurItem = CurItem->Next, Index++) 00189 { 00190 if (CurItem == Item) 00191 { 00192 return Index; 00193 } 00194 } 00195 00196 return -1; 00197 } 00198 00199 static PCHECKITEM 00200 FindCheckItem(IN PCHECKLISTWND infoPtr, 00201 IN LPWSTR SearchText) 00202 { 00203 PCHECKITEM CurItem; 00204 SIZE_T Count = wcslen(SearchText); 00205 00206 for (CurItem = infoPtr->CheckItemListHead; 00207 CurItem != NULL; 00208 CurItem = CurItem->Next) 00209 { 00210 if ((CurItem->State & CIS_DISABLED) != CIS_DISABLED && 00211 !_wcsnicmp(CurItem->Name, 00212 SearchText, Count)) 00213 { 00214 break; 00215 } 00216 } 00217 00218 return CurItem; 00219 } 00220 00221 static PCHECKITEM 00222 FindFirstEnabledCheckBox(IN PCHECKLISTWND infoPtr, 00223 OUT UINT *CheckBox) 00224 { 00225 PCHECKITEM CurItem; 00226 00227 for (CurItem = infoPtr->CheckItemListHead; 00228 CurItem != NULL; 00229 CurItem = CurItem->Next) 00230 { 00231 if ((CurItem->State & CIS_DISABLED) != CIS_DISABLED) 00232 { 00233 /* return the Allow checkbox in case both check boxes are enabled! */ 00234 *CheckBox = ((!(CurItem->State & CIS_ALLOWDISABLED)) ? CLB_ALLOW : CLB_DENY); 00235 break; 00236 } 00237 } 00238 00239 return CurItem; 00240 } 00241 00242 static PCHECKITEM 00243 FindLastEnabledCheckBox(IN PCHECKLISTWND infoPtr, 00244 OUT UINT *CheckBox) 00245 { 00246 PCHECKITEM CurItem; 00247 PCHECKITEM LastEnabledItem = NULL; 00248 00249 for (CurItem = infoPtr->CheckItemListHead; 00250 CurItem != NULL; 00251 CurItem = CurItem->Next) 00252 { 00253 if ((CurItem->State & CIS_DISABLED) != CIS_DISABLED) 00254 { 00255 LastEnabledItem = CurItem; 00256 } 00257 } 00258 00259 if (LastEnabledItem != NULL) 00260 { 00261 /* return the Deny checkbox in case both check boxes are enabled! */ 00262 *CheckBox = ((!(LastEnabledItem->State & CIS_DENYDISABLED)) ? CLB_DENY : CLB_ALLOW); 00263 } 00264 00265 return LastEnabledItem; 00266 } 00267 00268 static PCHECKITEM 00269 FindPreviousEnabledCheckBox(IN PCHECKLISTWND infoPtr, 00270 OUT UINT *CheckBox) 00271 { 00272 PCHECKITEM Item; 00273 00274 if (infoPtr->FocusedCheckItem != NULL) 00275 { 00276 Item = infoPtr->FocusedCheckItem; 00277 00278 if (infoPtr->FocusedCheckItemBox == CLB_DENY && 00279 !(Item->State & CIS_ALLOWDISABLED)) 00280 { 00281 /* currently an Deny checkbox is focused. return the Allow checkbox 00282 if it's enabled */ 00283 *CheckBox = CLB_ALLOW; 00284 } 00285 else 00286 { 00287 PCHECKITEM CurItem; 00288 00289 Item = NULL; 00290 00291 for (CurItem = infoPtr->CheckItemListHead; 00292 CurItem != infoPtr->FocusedCheckItem; 00293 CurItem = CurItem->Next) 00294 { 00295 if ((CurItem->State & CIS_DISABLED) != CIS_DISABLED) 00296 { 00297 Item = CurItem; 00298 } 00299 } 00300 00301 if (Item != NULL) 00302 { 00303 /* return the Deny checkbox in case both check boxes are enabled! */ 00304 *CheckBox = ((!(Item->State & CIS_DENYDISABLED)) ? CLB_DENY : CLB_ALLOW); 00305 } 00306 } 00307 } 00308 else 00309 { 00310 Item = FindLastEnabledCheckBox(infoPtr, 00311 CheckBox); 00312 } 00313 00314 return Item; 00315 } 00316 00317 static PCHECKITEM 00318 FindNextEnabledCheckBox(IN PCHECKLISTWND infoPtr, 00319 OUT UINT *CheckBox) 00320 { 00321 PCHECKITEM Item; 00322 00323 if (infoPtr->FocusedCheckItem != NULL) 00324 { 00325 Item = infoPtr->FocusedCheckItem; 00326 00327 if (infoPtr->FocusedCheckItemBox != CLB_DENY && 00328 !(Item->State & CIS_DENYDISABLED)) 00329 { 00330 /* currently an Allow checkbox is focused. return the Deny checkbox 00331 if it's enabled */ 00332 *CheckBox = CLB_DENY; 00333 } 00334 else 00335 { 00336 Item = Item->Next; 00337 00338 while (Item != NULL) 00339 { 00340 if ((Item->State & CIS_DISABLED) != CIS_DISABLED) 00341 { 00342 /* return the Allow checkbox in case both check boxes are enabled! */ 00343 *CheckBox = ((!(Item->State & CIS_ALLOWDISABLED)) ? CLB_ALLOW : CLB_DENY); 00344 break; 00345 } 00346 00347 Item = Item->Next; 00348 } 00349 } 00350 } 00351 else 00352 { 00353 Item = FindFirstEnabledCheckBox(infoPtr, 00354 CheckBox); 00355 } 00356 00357 return Item; 00358 } 00359 00360 static PCHECKITEM 00361 FindEnabledCheckBox(IN PCHECKLISTWND infoPtr, 00362 IN BOOL ReverseSearch, 00363 OUT UINT *CheckBox) 00364 { 00365 PCHECKITEM Item; 00366 00367 if (ReverseSearch) 00368 { 00369 Item = FindPreviousEnabledCheckBox(infoPtr, 00370 CheckBox); 00371 } 00372 else 00373 { 00374 Item = FindNextEnabledCheckBox(infoPtr, 00375 CheckBox); 00376 } 00377 00378 return Item; 00379 } 00380 00381 static PCHECKITEM 00382 PtToCheckItemBox(IN PCHECKLISTWND infoPtr, 00383 IN PPOINT ppt, 00384 OUT UINT *CheckBox, 00385 OUT BOOL *DirectlyInCheckBox) 00386 { 00387 INT FirstVisible, Index; 00388 PCHECKITEM Item; 00389 00390 FirstVisible = GetScrollPos(infoPtr->hSelf, 00391 SB_VERT); 00392 00393 Index = FirstVisible + (ppt->y / infoPtr->ItemHeight); 00394 00395 Item = FindCheckItemByIndex(infoPtr, 00396 Index); 00397 if (Item != NULL) 00398 { 00399 INT cx; 00400 00401 cx = infoPtr->CheckBoxLeft[CLB_ALLOW] + 00402 ((infoPtr->CheckBoxLeft[CLB_DENY] - infoPtr->CheckBoxLeft[CLB_ALLOW]) / 2); 00403 00404 *CheckBox = ((ppt->x <= cx) ? CLB_ALLOW : CLB_DENY); 00405 00406 if (DirectlyInCheckBox != NULL) 00407 { 00408 INT y = ppt->y % infoPtr->ItemHeight; 00409 INT cxBox = infoPtr->ItemHeight - (2 * CI_TEXT_MARGIN_HEIGHT); 00410 00411 if ((y >= CI_TEXT_MARGIN_HEIGHT && 00412 y < infoPtr->ItemHeight - CI_TEXT_MARGIN_HEIGHT) && 00413 00414 (((ppt->x >= (infoPtr->CheckBoxLeft[CLB_ALLOW] - (cxBox / 2))) && 00415 (ppt->x < (infoPtr->CheckBoxLeft[CLB_ALLOW] - (cxBox / 2) + cxBox))) 00416 || 00417 ((ppt->x >= (infoPtr->CheckBoxLeft[CLB_DENY] - (cxBox / 2))) && 00418 (ppt->x < (infoPtr->CheckBoxLeft[CLB_DENY] - (cxBox / 2) + cxBox))))) 00419 { 00420 *DirectlyInCheckBox = TRUE; 00421 } 00422 else 00423 { 00424 *DirectlyInCheckBox = FALSE; 00425 } 00426 } 00427 } 00428 00429 return Item; 00430 } 00431 00432 static VOID 00433 ClearCheckItems(IN PCHECKLISTWND infoPtr) 00434 { 00435 PCHECKITEM CurItem, NextItem; 00436 00437 CurItem = infoPtr->CheckItemListHead; 00438 while (CurItem != NULL) 00439 { 00440 NextItem = CurItem->Next; 00441 HeapFree(GetProcessHeap(), 00442 0, 00443 CurItem); 00444 CurItem = NextItem; 00445 } 00446 00447 infoPtr->CheckItemListHead = NULL; 00448 infoPtr->CheckItemCount = 0; 00449 } 00450 00451 static BOOL 00452 DeleteCheckItem(IN PCHECKLISTWND infoPtr, 00453 IN PCHECKITEM Item) 00454 { 00455 PCHECKITEM CurItem; 00456 PCHECKITEM *PrevPtr = &infoPtr->CheckItemListHead; 00457 00458 for (CurItem = infoPtr->CheckItemListHead; 00459 CurItem != NULL; 00460 CurItem = CurItem->Next) 00461 { 00462 if (CurItem == Item) 00463 { 00464 if (Item == infoPtr->QuickSearchHitItem && infoPtr->QuickSearchEnabled) 00465 { 00466 EscapeQuickSearch(infoPtr); 00467 } 00468 00469 #if SUPPORT_UXTHEME 00470 if (Item == infoPtr->HoveredCheckItem) 00471 { 00472 ChangeCheckItemHotTrack(infoPtr, 00473 NULL, 00474 0); 00475 } 00476 #endif 00477 00478 if (Item == infoPtr->FocusedCheckItem) 00479 { 00480 ChangeCheckItemFocus(infoPtr, 00481 NULL, 00482 0); 00483 } 00484 00485 *PrevPtr = CurItem->Next; 00486 HeapFree(GetProcessHeap(), 00487 0, 00488 CurItem); 00489 infoPtr->CheckItemCount--; 00490 return TRUE; 00491 } 00492 00493 PrevPtr = &CurItem->Next; 00494 } 00495 00496 return FALSE; 00497 } 00498 00499 static PCHECKITEM 00500 AddCheckItem(IN PCHECKLISTWND infoPtr, 00501 IN LPWSTR Name, 00502 IN DWORD State, 00503 IN ACCESS_MASK AccessMask, 00504 OUT INT *Index) 00505 { 00506 PCHECKITEM CurItem; 00507 INT i; 00508 PCHECKITEM *PrevPtr = &infoPtr->CheckItemListHead; 00509 PCHECKITEM Item = HeapAlloc(GetProcessHeap(), 00510 0, 00511 sizeof(CHECKITEM) + (wcslen(Name) * sizeof(WCHAR))); 00512 if (Item != NULL) 00513 { 00514 for (CurItem = infoPtr->CheckItemListHead, i = 0; 00515 CurItem != NULL; 00516 CurItem = CurItem->Next) 00517 { 00518 PrevPtr = &CurItem->Next; 00519 i++; 00520 } 00521 00522 Item->Next = NULL; 00523 Item->AccessMask = AccessMask; 00524 Item->State = State & CIS_MASK; 00525 wcscpy(Item->Name, 00526 Name); 00527 00528 *PrevPtr = Item; 00529 infoPtr->CheckItemCount++; 00530 00531 if (Index != NULL) 00532 { 00533 *Index = i; 00534 } 00535 } 00536 00537 return Item; 00538 } 00539 00540 static UINT 00541 ClearCheckBoxes(IN PCHECKLISTWND infoPtr) 00542 { 00543 PCHECKITEM CurItem; 00544 UINT nUpdated = 0; 00545 00546 for (CurItem = infoPtr->CheckItemListHead; 00547 CurItem != NULL; 00548 CurItem = CurItem->Next) 00549 { 00550 if (CurItem->State & (CIS_ALLOW | CIS_DENY)) 00551 { 00552 CurItem->State &= ~(CIS_ALLOW | CIS_DENY); 00553 nUpdated++; 00554 } 00555 } 00556 00557 return nUpdated; 00558 } 00559 00560 static VOID 00561 UpdateControl(IN PCHECKLISTWND infoPtr) 00562 { 00563 RECT rcClient; 00564 SCROLLINFO ScrollInfo; 00565 INT VisibleItems; 00566 00567 GetClientRect(infoPtr->hSelf, 00568 &rcClient); 00569 00570 ScrollInfo.cbSize = sizeof(ScrollInfo); 00571 ScrollInfo.fMask = SIF_PAGE | SIF_RANGE; 00572 ScrollInfo.nMin = 0; 00573 ScrollInfo.nMax = infoPtr->CheckItemCount; 00574 ScrollInfo.nPage = ((rcClient.bottom - rcClient.top) + infoPtr->ItemHeight - 1) / infoPtr->ItemHeight; 00575 ScrollInfo.nPos = 0; 00576 ScrollInfo.nTrackPos = 0; 00577 00578 VisibleItems = (rcClient.bottom - rcClient.top) / infoPtr->ItemHeight; 00579 00580 if (ScrollInfo.nPage == (UINT)VisibleItems && ScrollInfo.nMax > 0) 00581 { 00582 ScrollInfo.nMax--; 00583 } 00584 00585 SetScrollInfo(infoPtr->hSelf, 00586 SB_VERT, 00587 &ScrollInfo, 00588 TRUE); 00589 00590 RedrawWindow(infoPtr->hSelf, 00591 NULL, 00592 NULL, 00593 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN); 00594 } 00595 00596 static VOID 00597 UpdateCheckItem(IN PCHECKLISTWND infoPtr, 00598 IN PCHECKITEM Item) 00599 { 00600 RECT rcClient; 00601 INT VisibleFirst, VisibleItems; 00602 INT Index = CheckItemToIndex(infoPtr, 00603 Item); 00604 if (Index != -1) 00605 { 00606 VisibleFirst = GetScrollPos(infoPtr->hSelf, 00607 SB_VERT); 00608 00609 if (Index >= VisibleFirst) 00610 { 00611 GetClientRect(infoPtr->hSelf, 00612 &rcClient); 00613 00614 VisibleItems = ((rcClient.bottom - rcClient.top) + infoPtr->ItemHeight - 1) / infoPtr->ItemHeight; 00615 00616 if (Index <= VisibleFirst + VisibleItems) 00617 { 00618 RECT rcUpdate; 00619 00620 rcUpdate.left = rcClient.left; 00621 rcUpdate.right = rcClient.right; 00622 rcUpdate.top = (Index - VisibleFirst) * infoPtr->ItemHeight; 00623 rcUpdate.bottom = rcUpdate.top + infoPtr->ItemHeight; 00624 00625 RedrawWindow(infoPtr->hSelf, 00626 &rcUpdate, 00627 NULL, 00628 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN); 00629 } 00630 } 00631 } 00632 } 00633 00634 static VOID 00635 MakeCheckItemVisible(IN PCHECKLISTWND infoPtr, 00636 IN PCHECKITEM Item) 00637 { 00638 RECT rcClient; 00639 INT VisibleFirst, VisibleItems, NewPos; 00640 INT Index = CheckItemToIndex(infoPtr, 00641 Item); 00642 if (Index != -1) 00643 { 00644 VisibleFirst = GetScrollPos(infoPtr->hSelf, 00645 SB_VERT); 00646 00647 if (Index <= VisibleFirst) 00648 { 00649 NewPos = Index; 00650 } 00651 else 00652 { 00653 GetClientRect(infoPtr->hSelf, 00654 &rcClient); 00655 00656 VisibleItems = (rcClient.bottom - rcClient.top) / infoPtr->ItemHeight; 00657 if (Index - VisibleItems + 1 > VisibleFirst) 00658 { 00659 NewPos = Index - VisibleItems + 1; 00660 } 00661 else 00662 { 00663 NewPos = VisibleFirst; 00664 } 00665 } 00666 00667 if (VisibleFirst != NewPos) 00668 { 00669 SCROLLINFO ScrollInfo; 00670 00671 ScrollInfo.cbSize = sizeof(ScrollInfo); 00672 ScrollInfo.fMask = SIF_POS; 00673 ScrollInfo.nPos = NewPos; 00674 NewPos = SetScrollInfo(infoPtr->hSelf, 00675 SB_VERT, 00676 &ScrollInfo, 00677 TRUE); 00678 00679 if (VisibleFirst != NewPos) 00680 { 00681 ScrollWindowEx(infoPtr->hSelf, 00682 0, 00683 (NewPos - VisibleFirst) * infoPtr->ItemHeight, 00684 NULL, 00685 NULL, 00686 NULL, 00687 NULL, 00688 SW_INVALIDATE | SW_SCROLLCHILDREN); 00689 00690 RedrawWindow(infoPtr->hSelf, 00691 NULL, 00692 NULL, 00693 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN); 00694 } 00695 } 00696 } 00697 } 00698 00699 static UINT 00700 GetIdealItemHeight(IN PCHECKLISTWND infoPtr) 00701 { 00702 HDC hdc = GetDC(infoPtr->hSelf); 00703 if(hdc != NULL) 00704 { 00705 UINT height; 00706 TEXTMETRIC tm; 00707 HGDIOBJ hOldFont = SelectObject(hdc, 00708 infoPtr->hFont); 00709 00710 if(GetTextMetrics(hdc, 00711 &tm)) 00712 { 00713 height = tm.tmHeight; 00714 } 00715 else 00716 { 00717 height = 2; 00718 } 00719 00720 SelectObject(hdc, 00721 hOldFont); 00722 00723 ReleaseDC(infoPtr->hSelf, 00724 hdc); 00725 00726 return height; 00727 } 00728 return 0; 00729 } 00730 00731 static HFONT 00732 RetChangeControlFont(IN PCHECKLISTWND infoPtr, 00733 IN HFONT hFont, 00734 IN BOOL Redraw) 00735 { 00736 HFONT hOldFont = infoPtr->hFont; 00737 infoPtr->hFont = hFont; 00738 00739 if (hOldFont != hFont) 00740 { 00741 infoPtr->ItemHeight = (2 * CI_TEXT_MARGIN_HEIGHT) + GetIdealItemHeight(infoPtr); 00742 } 00743 00744 if (infoPtr->ShowingCaret) 00745 { 00746 DestroyCaret(); 00747 CreateCaret(infoPtr->hSelf, 00748 NULL, 00749 0, 00750 infoPtr->ItemHeight - (2 * CI_TEXT_MARGIN_HEIGHT)); 00751 } 00752 00753 UpdateControl(infoPtr); 00754 00755 return hOldFont; 00756 } 00757 00758 #if SUPPORT_UXTHEME 00759 static INT 00760 CalculateCheckBoxStyle(IN BOOL Checked, 00761 IN BOOL Enabled, 00762 IN BOOL HotTrack, 00763 IN BOOL Pushed) 00764 { 00765 INT BtnState; 00766 00767 if (Checked) 00768 { 00769 BtnState = (Enabled ? 00770 (Pushed ? CBS_CHECKEDPRESSED : (HotTrack ? CBS_CHECKEDHOT : CBS_CHECKEDNORMAL)) : 00771 CBS_CHECKEDDISABLED); 00772 } 00773 else 00774 { 00775 BtnState = (Enabled ? 00776 (Pushed ? CBS_UNCHECKEDPRESSED : (HotTrack ? CBS_UNCHECKEDHOT : CBS_UNCHECKEDNORMAL)) : 00777 CBS_UNCHECKEDDISABLED); 00778 } 00779 00780 return BtnState; 00781 } 00782 #endif 00783 00784 static VOID 00785 PaintControl(IN PCHECKLISTWND infoPtr, 00786 IN HDC hDC, 00787 IN PRECT rcUpdate) 00788 { 00789 INT ScrollPos; 00790 PCHECKITEM FirstItem, Item; 00791 RECT rcClient; 00792 UINT VisibleFirstIndex = rcUpdate->top / infoPtr->ItemHeight; 00793 UINT LastTouchedIndex = rcUpdate->bottom / infoPtr->ItemHeight; 00794 00795 FillRect(hDC, 00796 rcUpdate, 00797 (HBRUSH)(COLOR_WINDOW + 1)); 00798 00799 GetClientRect(infoPtr->hSelf, 00800 &rcClient); 00801 00802 ScrollPos = GetScrollPos(infoPtr->hSelf, 00803 SB_VERT); 00804 00805 FirstItem = FindCheckItemByIndex(infoPtr, 00806 ScrollPos + VisibleFirstIndex); 00807 if (FirstItem != NULL) 00808 { 00809 RECT TextRect, ItemRect, CheckBox; 00810 HFONT hOldFont; 00811 DWORD CurrentIndex; 00812 COLORREF OldTextColor; 00813 BOOL Enabled, PrevEnabled, IsPushed; 00814 POINT hOldBrushOrg; 00815 #if SUPPORT_UXTHEME 00816 HRESULT hDrawResult; 00817 BOOL ItemHovered; 00818 #endif 00819 00820 Enabled = IsWindowEnabled(infoPtr->hSelf); 00821 PrevEnabled = Enabled; 00822 00823 ItemRect.left = 0; 00824 ItemRect.right = rcClient.right; 00825 ItemRect.top = VisibleFirstIndex * infoPtr->ItemHeight; 00826 00827 TextRect.left = ItemRect.left + CI_TEXT_MARGIN_WIDTH; 00828 TextRect.right = ItemRect.right - CI_TEXT_MARGIN_WIDTH; 00829 TextRect.top = ItemRect.top + CI_TEXT_MARGIN_HEIGHT; 00830 00831 SetBrushOrgEx(hDC, 00832 ItemRect.left, 00833 ItemRect.top, 00834 &hOldBrushOrg); 00835 00836 OldTextColor = SetTextColor(hDC, 00837 infoPtr->TextColor[Enabled]); 00838 00839 hOldFont = SelectObject(hDC, 00840 infoPtr->hFont); 00841 00842 for (Item = FirstItem, CurrentIndex = VisibleFirstIndex; 00843 Item != NULL && CurrentIndex <= LastTouchedIndex; 00844 Item = Item->Next, CurrentIndex++) 00845 { 00846 TextRect.bottom = TextRect.top + infoPtr->ItemHeight - (2 * CI_TEXT_MARGIN_HEIGHT); 00847 ItemRect.bottom = ItemRect.top + infoPtr->ItemHeight; 00848 00849 SetBrushOrgEx(hDC, 00850 ItemRect.left, 00851 ItemRect.top, 00852 NULL); 00853 00854 if (Enabled && PrevEnabled != ((Item->State & CIS_DISABLED) != CIS_DISABLED)) 00855 { 00856 PrevEnabled = ((Item->State & CIS_DISABLED) != CIS_DISABLED); 00857 00858 SetTextColor(hDC, 00859 infoPtr->TextColor[PrevEnabled]); 00860 } 00861 00862 #if SUPPORT_UXTHEME 00863 ItemHovered = (Enabled && infoPtr->HoveredCheckItem == Item); 00864 #endif 00865 00866 if (infoPtr->QuickSearchHitItem == Item) 00867 { 00868 COLORREF OldBkColor, OldFgColor; 00869 SIZE TextSize; 00870 SIZE_T TextLen, HighlightLen = wcslen(infoPtr->QuickSearchText); 00871 00872 /* highlight the quicksearch text */ 00873 if (GetTextExtentPoint32(hDC, 00874 Item->Name, 00875 HighlightLen, 00876 &TextSize)) 00877 { 00878 COLORREF HighlightTextColor, HighlightBackground; 00879 RECT rcHighlight = TextRect; 00880 00881 HighlightTextColor = GetSysColor(COLOR_HIGHLIGHTTEXT); 00882 HighlightBackground = GetSysColor(COLOR_HIGHLIGHT); 00883 00884 rcHighlight.right = rcHighlight.left + TextSize.cx; 00885 00886 InflateRect(&rcHighlight, 00887 0, 00888 CI_TEXT_SELECTIONMARGIN); 00889 00890 OldBkColor = SetBkColor(hDC, 00891 HighlightBackground); 00892 OldFgColor = SetTextColor(hDC, 00893 HighlightTextColor); 00894 00895 /* draw the highlighted text */ 00896 DrawText(hDC, 00897 Item->Name, 00898 HighlightLen, 00899 &rcHighlight, 00900 DT_LEFT | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER); 00901 00902 SetBkColor(hDC, 00903 OldBkColor); 00904 SetTextColor(hDC, 00905 OldFgColor); 00906 00907 /* draw the remaining part of the text */ 00908 TextLen = wcslen(Item->Name); 00909 if (HighlightLen < TextLen) 00910 { 00911 rcHighlight.left = rcHighlight.right; 00912 rcHighlight.right = TextRect.right; 00913 00914 DrawText(hDC, 00915 Item->Name + HighlightLen, 00916 -1, 00917 &rcHighlight, 00918 DT_LEFT | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER); 00919 } 00920 } 00921 } 00922 else 00923 { 00924 /* draw the text */ 00925 DrawText(hDC, 00926 Item->Name, 00927 -1, 00928 &TextRect, 00929 DT_LEFT | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER); 00930 } 00931 00932 CheckBox.top = TextRect.top; 00933 CheckBox.bottom = TextRect.bottom; 00934 00935 /* draw the Allow checkbox */ 00936 IsPushed = (Enabled && Item == infoPtr->FocusedCheckItem && infoPtr->HasFocus && 00937 !(Item->State & CIS_ALLOWDISABLED) && infoPtr->FocusedCheckItemBox != CLB_DENY && 00938 infoPtr->FocusedPushed); 00939 00940 CheckBox.left = infoPtr->CheckBoxLeft[CLB_ALLOW] - ((TextRect.bottom - TextRect.top) / 2); 00941 CheckBox.right = CheckBox.left + (TextRect.bottom - TextRect.top); 00942 #if SUPPORT_UXTHEME 00943 if (infoPtr->ThemeHandle != NULL) 00944 { 00945 INT BtnState = CalculateCheckBoxStyle(Item->State & CIS_ALLOW, 00946 Enabled && !(Item->State & CIS_ALLOWDISABLED), 00947 (ItemHovered && infoPtr->HoveredCheckItemBox != CLB_DENY), 00948 IsPushed); 00949 00950 00951 hDrawResult = DrawThemeBackground(infoPtr->ThemeHandle, 00952 hDC, 00953 BP_CHECKBOX, 00954 BtnState, 00955 &CheckBox, 00956 NULL); 00957 00958 } 00959 else 00960 { 00961 hDrawResult = E_FAIL; 00962 } 00963 00964 /* draw the standard checkbox if no themes are enabled or drawing the 00965 themeed control failed */ 00966 if (FAILED(hDrawResult)) 00967 #endif 00968 { 00969 DrawFrameControl(hDC, 00970 &CheckBox, 00971 DFC_BUTTON, 00972 DFCS_BUTTONCHECK | DFCS_FLAT | 00973 ((Item->State & CIS_ALLOWDISABLED) || !Enabled ? DFCS_INACTIVE : 0) | 00974 ((Item->State & CIS_ALLOW) ? DFCS_CHECKED : 0) | 00975 (IsPushed ? DFCS_PUSHED : 0)); 00976 } 00977 if (Item == infoPtr->FocusedCheckItem && !(infoPtr->UIState & UISF_HIDEFOCUS) && 00978 infoPtr->HasFocus && 00979 infoPtr->FocusedCheckItemBox != CLB_DENY) 00980 { 00981 RECT rcFocus = CheckBox; 00982 00983 InflateRect (&rcFocus, 00984 CI_TEXT_MARGIN_HEIGHT, 00985 CI_TEXT_MARGIN_HEIGHT); 00986 00987 DrawFocusRect(hDC, 00988 &rcFocus); 00989 } 00990 00991 /* draw the Deny checkbox */ 00992 IsPushed = (Enabled && Item == infoPtr->FocusedCheckItem && infoPtr->HasFocus && 00993 !(Item->State & CIS_DENYDISABLED) && infoPtr->FocusedCheckItemBox == CLB_DENY && 00994 infoPtr->FocusedPushed); 00995 00996 CheckBox.left = infoPtr->CheckBoxLeft[CLB_DENY] - ((TextRect.bottom - TextRect.top) / 2); 00997 CheckBox.right = CheckBox.left + (TextRect.bottom - TextRect.top); 00998 #if SUPPORT_UXTHEME 00999 if (infoPtr->ThemeHandle != NULL) 01000 { 01001 INT BtnState = CalculateCheckBoxStyle(Item->State & CIS_DENY, 01002 Enabled && !(Item->State & CIS_DENYDISABLED), 01003 (ItemHovered && infoPtr->HoveredCheckItemBox == CLB_DENY), 01004 IsPushed); 01005 01006 hDrawResult = DrawThemeBackground(infoPtr->ThemeHandle, 01007 hDC, 01008 BP_CHECKBOX, 01009 BtnState, 01010 &CheckBox, 01011 NULL); 01012 01013 } 01014 else 01015 { 01016 hDrawResult = E_FAIL; 01017 } 01018 01019 /* draw the standard checkbox if no themes are enabled or drawing the 01020 themeed control failed */ 01021 if (FAILED(hDrawResult)) 01022 #endif 01023 { 01024 DrawFrameControl(hDC, 01025 &CheckBox, 01026 DFC_BUTTON, 01027 DFCS_BUTTONCHECK | DFCS_FLAT | 01028 ((Item->State & CIS_DENYDISABLED) || !Enabled ? DFCS_INACTIVE : 0) | 01029 ((Item->State & CIS_DENY) ? DFCS_CHECKED : 0) | 01030 (IsPushed ? DFCS_PUSHED : 0)); 01031 } 01032 if (infoPtr->HasFocus && !(infoPtr->UIState & UISF_HIDEFOCUS) && 01033 Item == infoPtr->FocusedCheckItem && 01034 infoPtr->FocusedCheckItemBox == CLB_DENY) 01035 { 01036 RECT rcFocus = CheckBox; 01037 01038 InflateRect (&rcFocus, 01039 CI_TEXT_MARGIN_HEIGHT, 01040 CI_TEXT_MARGIN_HEIGHT); 01041 01042 DrawFocusRect(hDC, 01043 &rcFocus); 01044 } 01045 01046 TextRect.top += infoPtr->ItemHeight; 01047 ItemRect.top += infoPtr->ItemHeight; 01048 } 01049 01050 SelectObject(hDC, 01051 hOldFont); 01052 01053 SetTextColor(hDC, 01054 OldTextColor); 01055 01056 SetBrushOrgEx(hDC, 01057 hOldBrushOrg.x, 01058 hOldBrushOrg.y, 01059 NULL); 01060 } 01061 } 01062 01063 static VOID 01064 ChangeCheckItemFocus(IN PCHECKLISTWND infoPtr, 01065 IN PCHECKITEM NewFocus, 01066 IN UINT NewFocusBox) 01067 { 01068 if (NewFocus != infoPtr->FocusedCheckItem) 01069 { 01070 PCHECKITEM OldFocus = infoPtr->FocusedCheckItem; 01071 infoPtr->FocusedCheckItem = NewFocus; 01072 infoPtr->FocusedCheckItemBox = NewFocusBox; 01073 01074 if (OldFocus != NULL) 01075 { 01076 UpdateCheckItem(infoPtr, 01077 OldFocus); 01078 } 01079 } 01080 else 01081 { 01082 infoPtr->FocusedCheckItemBox = NewFocusBox; 01083 } 01084 01085 if (NewFocus != NULL) 01086 { 01087 MakeCheckItemVisible(infoPtr, 01088 NewFocus); 01089 UpdateCheckItem(infoPtr, 01090 NewFocus); 01091 } 01092 } 01093 01094 static VOID 01095 UpdateCheckItemBox(IN PCHECKLISTWND infoPtr, 01096 IN PCHECKITEM Item, 01097 IN UINT ItemBox) 01098 { 01099 RECT rcClient; 01100 INT VisibleFirst, VisibleItems; 01101 INT Index = CheckItemToIndex(infoPtr, 01102 Item); 01103 if (Index != -1) 01104 { 01105 VisibleFirst = GetScrollPos(infoPtr->hSelf, 01106 SB_VERT); 01107 01108 if (Index >= VisibleFirst) 01109 { 01110 GetClientRect(infoPtr->hSelf, 01111 &rcClient); 01112 01113 VisibleItems = ((rcClient.bottom - rcClient.top) + infoPtr->ItemHeight - 1) / infoPtr->ItemHeight; 01114 01115 if (Index <= VisibleFirst + VisibleItems) 01116 { 01117 RECT rcUpdate; 01118 01119 rcUpdate.left = rcClient.left + infoPtr->CheckBoxLeft[ItemBox] - (infoPtr->ItemHeight / 2); 01120 rcUpdate.right = rcUpdate.left + infoPtr->ItemHeight; 01121 rcUpdate.top = ((Index - VisibleFirst) * infoPtr->ItemHeight); 01122 rcUpdate.bottom = rcUpdate.top + infoPtr->ItemHeight; 01123 01124 RedrawWindow(infoPtr->hSelf, 01125 &rcUpdate, 01126 NULL, 01127 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN); 01128 } 01129 } 01130 } 01131 } 01132 01133 #if SUPPORT_UXTHEME 01134 static VOID 01135 ChangeCheckItemHotTrack(IN PCHECKLISTWND infoPtr, 01136 IN PCHECKITEM NewHotTrack, 01137 IN UINT NewHotTrackBox) 01138 { 01139 if (NewHotTrack != infoPtr->HoveredCheckItem) 01140 { 01141 PCHECKITEM OldHotTrack = infoPtr->HoveredCheckItem; 01142 UINT OldHotTrackBox = infoPtr->HoveredCheckItemBox; 01143 01144 infoPtr->HoveredCheckItem = NewHotTrack; 01145 infoPtr->HoveredCheckItemBox = NewHotTrackBox; 01146 01147 if (OldHotTrack != NULL) 01148 { 01149 UpdateCheckItemBox(infoPtr, 01150 OldHotTrack, 01151 OldHotTrackBox); 01152 } 01153 } 01154 else 01155 { 01156 infoPtr->HoveredCheckItemBox = NewHotTrackBox; 01157 } 01158 01159 if (NewHotTrack != NULL) 01160 { 01161 UpdateCheckItemBox(infoPtr, 01162 NewHotTrack, 01163 NewHotTrackBox); 01164 } 01165 } 01166 #endif 01167 01168 static BOOL 01169 ChangeCheckBox(IN PCHECKLISTWND infoPtr, 01170 IN PCHECKITEM CheckItem, 01171 IN UINT CheckItemBox) 01172 { 01173 NMCHANGEITEMCHECKBOX CheckData; 01174 DWORD OldState = CheckItem->State; 01175 DWORD CheckedBit = ((infoPtr->FocusedCheckItemBox == CLB_DENY) ? CIS_DENY : CIS_ALLOW); 01176 BOOL Checked = (CheckItem->State & CheckedBit) != 0; 01177 01178 CheckData.OldState = OldState; 01179 CheckData.NewState = (Checked ? OldState & ~CheckedBit : OldState | CheckedBit); 01180 CheckData.CheckBox = infoPtr->FocusedCheckItemBox; 01181 CheckData.Checked = !Checked; 01182 01183 if (NotifyControlParent(infoPtr, 01184 CLN_CHANGINGITEMCHECKBOX, 01185 &CheckData) != (LRESULT)-1) 01186 { 01187 CheckItem->State = CheckData.NewState; 01188 } 01189 01190 return (CheckItem->State != OldState); 01191 } 01192 01193 static VOID 01194 DisplayCaret(IN PCHECKLISTWND infoPtr) 01195 { 01196 if (IsWindowEnabled(infoPtr->hSelf) && !infoPtr->ShowingCaret) 01197 { 01198 infoPtr->ShowingCaret = TRUE; 01199 01200 CreateCaret(infoPtr->hSelf, 01201 NULL, 01202 infoPtr->CaretWidth, 01203 infoPtr->ItemHeight - (2 * CI_TEXT_MARGIN_HEIGHT)); 01204 01205 ShowCaret(infoPtr->hSelf); 01206 } 01207 } 01208 01209 static VOID 01210 RemoveCaret(IN PCHECKLISTWND infoPtr) 01211 { 01212 if (IsWindowEnabled(infoPtr->hSelf) && infoPtr->ShowingCaret) 01213 { 01214 infoPtr->ShowingCaret = FALSE; 01215 01216 HideCaret(infoPtr->hSelf); 01217 DestroyCaret(); 01218 } 01219 } 01220 01221 static VOID 01222 KillQuickSearchTimers(IN PCHECKLISTWND infoPtr) 01223 { 01224 KillTimer(infoPtr->hSelf, 01225 TIMER_ID_SETHITFOCUS); 01226 KillTimer(infoPtr->hSelf, 01227 TIMER_ID_RESETQUICKSEARCH); 01228 } 01229 01230 static VOID 01231 MapItemToRect(IN PCHECKLISTWND infoPtr, 01232 IN PCHECKITEM CheckItem, 01233 OUT RECT *prcItem) 01234 { 01235 INT Index = CheckItemToIndex(infoPtr, 01236 CheckItem); 01237 if (Index != -1) 01238 { 01239 RECT rcClient; 01240 INT VisibleFirst; 01241 01242 GetClientRect(infoPtr->hSelf, 01243 &rcClient); 01244 01245 VisibleFirst = GetScrollPos(infoPtr->hSelf, 01246 SB_VERT); 01247 01248 prcItem->left = rcClient.left; 01249 prcItem->right = rcClient.right; 01250 prcItem->top = (Index - VisibleFirst) * infoPtr->ItemHeight; 01251 prcItem->bottom = prcItem->top + infoPtr->ItemHeight; 01252 } 01253 else 01254 { 01255 prcItem->left = 0; 01256 prcItem->top = 0; 01257 prcItem->right = 0; 01258 prcItem->bottom = 0; 01259 } 01260 } 01261 01262 static VOID 01263 UpdateCaretPos(IN PCHECKLISTWND infoPtr) 01264 { 01265 if (infoPtr->ShowingCaret && infoPtr->QuickSearchHitItem != NULL) 01266 { 01267 HDC hDC = GetDC(infoPtr->hSelf); 01268 if (hDC != NULL) 01269 { 01270 SIZE TextSize; 01271 HGDIOBJ hOldFont = SelectObject(hDC, 01272 infoPtr->hFont); 01273 01274 TextSize.cx = 0; 01275 TextSize.cy = 0; 01276 01277 if (infoPtr->QuickSearchText[0] == L'\0' || 01278 GetTextExtentPoint32(hDC, 01279 infoPtr->QuickSearchHitItem->Name, 01280 wcslen(infoPtr->QuickSearchText), 01281 &TextSize)) 01282 { 01283 RECT rcItem; 01284 01285 MapItemToRect(infoPtr, 01286 infoPtr->QuickSearchHitItem, 01287 &rcItem); 01288 01289 /* actually change the caret position */ 01290 SetCaretPos(rcItem.left + CI_TEXT_MARGIN_WIDTH + TextSize.cx, 01291 rcItem.top + CI_TEXT_MARGIN_HEIGHT); 01292 } 01293 01294 SelectObject(hDC, 01295 hOldFont); 01296 01297 ReleaseDC(infoPtr->hSelf, 01298 hDC); 01299 } 01300 } 01301 } 01302 01303 static VOID 01304 EscapeQuickSearch(IN PCHECKLISTWND infoPtr) 01305 { 01306 if (infoPtr->QuickSearchEnabled && infoPtr->QuickSearchHitItem != NULL) 01307 { 01308 PCHECKITEM OldHit = infoPtr->QuickSearchHitItem; 01309 01310 infoPtr->QuickSearchHitItem = NULL; 01311 infoPtr->QuickSearchText[0] = L'\0'; 01312 01313 /* scroll back to the focused item */ 01314 if (infoPtr->FocusedCheckItem != NULL) 01315 { 01316 MakeCheckItemVisible(infoPtr, 01317 infoPtr->FocusedCheckItem); 01318 } 01319 01320 /* repaint the old search hit item if it's still visible */ 01321 UpdateCheckItem(infoPtr, 01322 OldHit); 01323 01324 KillQuickSearchTimers(infoPtr); 01325 01326 RemoveCaret(infoPtr); 01327 } 01328 } 01329 01330 static VOID 01331 ChangeSearchHit(IN PCHECKLISTWND infoPtr, 01332 IN PCHECKITEM NewHit) 01333 { 01334 PCHECKITEM OldHit = infoPtr->QuickSearchHitItem; 01335 01336 infoPtr->QuickSearchHitItem = NewHit; 01337 01338 if (OldHit != NewHit) 01339 { 01340 /* scroll to the new search hit */ 01341 MakeCheckItemVisible(infoPtr, 01342 NewHit); 01343 01344 /* repaint the old hit if present and visible */ 01345 if (OldHit != NULL) 01346 { 01347 UpdateCheckItem(infoPtr, 01348 OldHit); 01349 } 01350 else 01351 { 01352 /* show the caret the first time we find an item */ 01353 DisplayCaret(infoPtr); 01354 } 01355 } 01356 01357 UpdateCaretPos(infoPtr); 01358 01359 UpdateCheckItem(infoPtr, 01360 NewHit); 01361 01362 /* kill the reset timer and restart the set hit focus timer */ 01363 KillTimer(infoPtr->hSelf, 01364 TIMER_ID_RESETQUICKSEARCH); 01365 if (infoPtr->QuickSearchSetFocusDelay != 0) 01366 { 01367 SetTimer(infoPtr->hSelf, 01368 TIMER_ID_SETHITFOCUS, 01369 infoPtr->QuickSearchSetFocusDelay, 01370 NULL); 01371 } 01372 } 01373 01374 static BOOL 01375 QuickSearchFindHit(IN PCHECKLISTWND infoPtr, 01376 IN WCHAR c) 01377 { 01378 if (infoPtr->QuickSearchEnabled) 01379 { 01380 BOOL Ret = FALSE; 01381 PCHECKITEM NewHit; 01382 01383 switch (c) 01384 { 01385 case '\r': 01386 case '\n': 01387 { 01388 Ret = infoPtr->QuickSearchHitItem != NULL; 01389 if (Ret) 01390 { 01391 /* NOTE: QuickSearchHitItem definitely has at least one 01392 enabled check box, the user can't search for disabled 01393 check items */ 01394 01395 ChangeCheckItemFocus(infoPtr, 01396 infoPtr->QuickSearchHitItem, 01397 ((!(infoPtr->QuickSearchHitItem->State & CIS_ALLOWDISABLED)) ? CLB_ALLOW : CLB_DENY)); 01398 01399 EscapeQuickSearch(infoPtr); 01400 } 01401 break; 01402 } 01403 01404 case VK_BACK: 01405 { 01406 if (infoPtr->QuickSearchHitItem != NULL) 01407 { 01408 INT SearchLen = wcslen(infoPtr->QuickSearchText); 01409 if (SearchLen > 0) 01410 { 01411 /* delete the last character */ 01412 infoPtr->QuickSearchText[--SearchLen] = L'\0'; 01413 01414 if (SearchLen > 0) 01415 { 01416 /* search again */ 01417 NewHit = FindCheckItem(infoPtr, 01418 infoPtr->QuickSearchText); 01419 01420 if (NewHit != NULL) 01421 { 01422 /* change the search hit */ 01423 ChangeSearchHit(infoPtr, 01424 NewHit); 01425 01426 Ret = TRUE; 01427 } 01428 } 01429 } 01430 01431 if (!Ret) 01432 { 01433 EscapeQuickSearch(infoPtr); 01434 } 01435 } 01436 break; 01437 } 01438 01439 default: 01440 { 01441 INT SearchLen = wcslen(infoPtr->QuickSearchText); 01442 if (SearchLen < (INT)(sizeof(infoPtr->QuickSearchText) / sizeof(infoPtr->QuickSearchText[0])) - 1) 01443 { 01444 infoPtr->QuickSearchText[SearchLen++] = c; 01445 infoPtr->QuickSearchText[SearchLen] = L'\0'; 01446 01447 NewHit = FindCheckItem(infoPtr, 01448 infoPtr->QuickSearchText); 01449 if (NewHit != NULL) 01450 { 01451 /* change the search hit */ 01452 ChangeSearchHit(infoPtr, 01453 NewHit); 01454 01455 Ret = TRUE; 01456 } 01457 else 01458 { 01459 /* reset the input */ 01460 infoPtr->QuickSearchText[--SearchLen] = L'\0'; 01461 } 01462 } 01463 break; 01464 } 01465 } 01466 return Ret; 01467 } 01468 01469 return FALSE; 01470 } 01471 01472 static LRESULT CALLBACK 01473 CheckListWndProc(IN HWND hwnd, 01474 IN UINT uMsg, 01475 IN WPARAM wParam, 01476 IN LPARAM lParam) 01477 { 01478 PCHECKLISTWND infoPtr; 01479 LRESULT Ret; 01480 01481 infoPtr = (PCHECKLISTWND)GetWindowLongPtr(hwnd, 01482 0); 01483 01484 if (infoPtr == NULL && uMsg != WM_CREATE) 01485 { 01486 goto HandleDefaultMessage; 01487 } 01488 01489 Ret = 0; 01490 01491 switch (uMsg) 01492 { 01493 case WM_PAINT: 01494 { 01495 HDC hdc; 01496 RECT rcUpdate; 01497 PAINTSTRUCT ps; 01498 01499 if (GetUpdateRect(hwnd, 01500 &rcUpdate, 01501 FALSE)) 01502 { 01503 hdc = (wParam != 0 ? (HDC)wParam : BeginPaint(hwnd, &ps)); 01504 01505 if (hdc != NULL) 01506 { 01507 PaintControl(infoPtr, 01508 hdc, 01509 &rcUpdate); 01510 01511 if (wParam == 0) 01512 { 01513 EndPaint(hwnd, 01514 &ps); 01515 } 01516 } 01517 } 01518 break; 01519 } 01520 01521 case WM_MOUSEMOVE: 01522 { 01523 POINT pt; 01524 BOOL InCheckBox; 01525 HWND hWndCapture = GetCapture(); 01526 01527 pt.x = (LONG)LOWORD(lParam); 01528 pt.y = (LONG)HIWORD(lParam); 01529 01530 #if SUPPORT_UXTHEME 01531 /* handle hovering checkboxes */ 01532 if (hWndCapture == NULL && infoPtr->ThemeHandle != NULL) 01533 { 01534 TRACKMOUSEEVENT tme; 01535 PCHECKITEM HotTrackItem; 01536 UINT HotTrackItemBox; 01537 01538 HotTrackItem = PtToCheckItemBox(infoPtr, 01539 &pt, 01540 &HotTrackItemBox, 01541 &InCheckBox); 01542 if (HotTrackItem != NULL && InCheckBox) 01543 { 01544 if (infoPtr->HoveredCheckItem != HotTrackItem || 01545 infoPtr->HoveredCheckItemBox != HotTrackItemBox) 01546 { 01547 ChangeCheckItemHotTrack(infoPtr, 01548 HotTrackItem, 01549 HotTrackItemBox); 01550 } 01551 } 01552 else 01553 { 01554 ChangeCheckItemHotTrack(infoPtr, 01555 NULL, 01556 0); 01557 } 01558 01559 tme.cbSize = sizeof(tme); 01560 tme.dwFlags = TME_LEAVE; 01561 tme.hwndTrack = hwnd; 01562 tme.dwHoverTime = infoPtr->HoverTime; 01563 01564 TrackMouseEvent(&tme); 01565 } 01566 #endif 01567 01568 if (hWndCapture == hwnd && infoPtr->FocusedCheckItem != NULL) 01569 { 01570 PCHECKITEM PtItem; 01571 UINT PtItemBox; 01572 UINT OldPushed; 01573 01574 PtItem = PtToCheckItemBox(infoPtr, 01575 &pt, 01576 &PtItemBox, 01577 &InCheckBox); 01578 01579 OldPushed = infoPtr->FocusedPushed; 01580 infoPtr->FocusedPushed = InCheckBox && infoPtr->FocusedCheckItem == PtItem && 01581 infoPtr->FocusedCheckItemBox == PtItemBox; 01582 01583 if (OldPushed != infoPtr->FocusedPushed) 01584 { 01585 UpdateCheckItemBox(infoPtr, 01586 infoPtr->FocusedCheckItem, 01587 infoPtr->FocusedCheckItemBox); 01588 } 01589 } 01590 01591 break; 01592 } 01593 01594 case WM_VSCROLL: 01595 { 01596 SCROLLINFO ScrollInfo; 01597 01598 ScrollInfo.cbSize = sizeof(ScrollInfo); 01599 ScrollInfo.fMask = SIF_RANGE | SIF_POS; 01600 01601 if (GetScrollInfo(hwnd, 01602 SB_VERT, 01603 &ScrollInfo)) 01604 { 01605 INT OldPos = ScrollInfo.nPos; 01606 01607 switch (LOWORD(wParam)) 01608 { 01609 case SB_BOTTOM: 01610 ScrollInfo.nPos = ScrollInfo.nMax; 01611 break; 01612 01613 case SB_LINEDOWN: 01614 if (ScrollInfo.nPos < ScrollInfo.nMax) 01615 { 01616 ScrollInfo.nPos++; 01617 } 01618 break; 01619 01620 case SB_LINEUP: 01621 if (ScrollInfo.nPos > 0) 01622 { 01623 ScrollInfo.nPos--; 01624 } 01625 break; 01626 01627 case SB_PAGEDOWN: 01628 { 01629 RECT rcClient; 01630 INT ScrollLines; 01631 01632 /* don't use ScrollInfo.nPage because we should only scroll 01633 down by the number of completely visible list entries. 01634 nPage however also includes the partly cropped list 01635 item at the bottom of the control */ 01636 01637 GetClientRect(hwnd, 01638 &rcClient); 01639 01640 ScrollLines = max(1, 01641 (rcClient.bottom - rcClient.top) / infoPtr->ItemHeight); 01642 01643 if (ScrollInfo.nPos + ScrollLines <= ScrollInfo.nMax) 01644 { 01645 ScrollInfo.nPos += ScrollLines; 01646 } 01647 else 01648 { 01649 ScrollInfo.nPos = ScrollInfo.nMax; 01650 } 01651 break; 01652 } 01653 01654 case SB_PAGEUP: 01655 { 01656 RECT rcClient; 01657 INT ScrollLines; 01658 01659 /* don't use ScrollInfo.nPage because we should only scroll 01660 down by the number of completely visible list entries. 01661 nPage however also includes the partly cropped list 01662 item at the bottom of the control */ 01663 01664 GetClientRect(hwnd, 01665 &rcClient); 01666 01667 ScrollLines = max(1, 01668 (rcClient.bottom - rcClient.top) / infoPtr->ItemHeight); 01669 01670 if (ScrollInfo.nPos >= ScrollLines) 01671 { 01672 ScrollInfo.nPos -= ScrollLines; 01673 } 01674 else 01675 { 01676 ScrollInfo.nPos = 0; 01677 } 01678 break; 01679 } 01680 01681 case SB_THUMBPOSITION: 01682 case SB_THUMBTRACK: 01683 { 01684 ScrollInfo.nPos = HIWORD(wParam); 01685 break; 01686 } 01687 01688 case SB_TOP: 01689 ScrollInfo.nPos = 0; 01690 break; 01691 } 01692 01693 if (OldPos != ScrollInfo.nPos) 01694 { 01695 ScrollInfo.fMask = SIF_POS; 01696 01697 ScrollInfo.nPos = SetScrollInfo(hwnd, 01698 SB_VERT, 01699 &ScrollInfo, 01700 TRUE); 01701 01702 if (OldPos != ScrollInfo.nPos) 01703 { 01704 ScrollWindowEx(hwnd, 01705 0, 01706 (OldPos - ScrollInfo.nPos) * infoPtr->ItemHeight, 01707 NULL, 01708 NULL, 01709 NULL, 01710 NULL, 01711 SW_INVALIDATE | SW_SCROLLCHILDREN); 01712 01713 RedrawWindow(hwnd, 01714 NULL, 01715 NULL, 01716 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN); 01717 } 01718 } 01719 } 01720 break; 01721 } 01722 01723 case CLM_ADDITEM: 01724 { 01725 INT Index = -1; 01726 PCHECKITEM Item = AddCheckItem(infoPtr, 01727 (LPWSTR)lParam, 01728 CIS_NONE, 01729 (ACCESS_MASK)wParam, 01730 &Index); 01731 if (Item != NULL) 01732 { 01733 UpdateControl(infoPtr); 01734 Ret = (LRESULT)Index; 01735 } 01736 else 01737 { 01738 Ret = (LRESULT)-1; 01739 } 01740 break; 01741 } 01742 01743 case CLM_DELITEM: 01744 { 01745 PCHECKITEM Item = FindCheckItemByIndex(infoPtr, 01746 wParam); 01747 if (Item != NULL) 01748 { 01749 Ret = DeleteCheckItem(infoPtr, 01750 Item); 01751 if (Ret) 01752 { 01753 UpdateControl(infoPtr); 01754 } 01755 } 01756 else 01757 { 01758 Ret = FALSE; 01759 } 01760 break; 01761 } 01762 01763 case CLM_SETITEMSTATE: 01764 { 01765 PCHECKITEM Item = FindCheckItemByIndex(infoPtr, 01766 wParam); 01767 if (Item != NULL) 01768 { 01769 DWORD OldState = Item->State; 01770 Item->State = (DWORD)lParam & CIS_MASK; 01771 01772 if (Item->State != OldState) 01773 { 01774 /* revert the focus if the currently focused item is about 01775 to be disabled */ 01776 if (Item == infoPtr->FocusedCheckItem && 01777 (Item->State & CIS_DISABLED)) 01778 { 01779 if (infoPtr->FocusedCheckItemBox == CLB_DENY) 01780 { 01781 if (Item->State & CIS_DENYDISABLED) 01782 { 01783 infoPtr->FocusedCheckItem = NULL; 01784 } 01785 } 01786 else 01787 { 01788 if (Item->State & CIS_ALLOWDISABLED) 01789 { 01790 infoPtr->FocusedCheckItem = NULL; 01791 } 01792 } 01793 } 01794 01795 UpdateControl(infoPtr); 01796 } 01797 Ret = TRUE; 01798 } 01799 break; 01800 } 01801 01802 case CLM_GETITEMCOUNT: 01803 { 01804 Ret = infoPtr->CheckItemCount; 01805 break; 01806 } 01807 01808 case CLM_CLEAR: 01809 { 01810 ClearCheckItems(infoPtr); 01811 UpdateControl(infoPtr); 01812 break; 01813 } 01814 01815 case CLM_SETCHECKBOXCOLUMN: 01816 { 01817 infoPtr->CheckBoxLeft[wParam != CLB_DENY] = (INT)lParam; 01818 UpdateControl(infoPtr); 01819 Ret = 1; 01820 break; 01821 } 01822 01823 case CLM_GETCHECKBOXCOLUMN: 01824 { 01825 Ret = (LRESULT)infoPtr->CheckBoxLeft[wParam != CLB_DENY]; 01826 break; 01827 } 01828 01829 case CLM_CLEARCHECKBOXES: 01830 { 01831 Ret = (LRESULT)ClearCheckBoxes(infoPtr); 01832 if (Ret) 01833 { 01834 UpdateControl(infoPtr); 01835 } 01836 break; 01837 } 01838 01839 case CLM_ENABLEQUICKSEARCH: 01840 { 01841 if (wParam == 0) 01842 { 01843 EscapeQuickSearch(infoPtr); 01844 } 01845 infoPtr->QuickSearchEnabled = (wParam != 0); 01846 break; 01847 } 01848 01849 case CLM_SETQUICKSEARCH_TIMEOUT_RESET: 01850 { 01851 infoPtr->QuickSearchResetDelay = (UINT)wParam; 01852 break; 01853 } 01854 01855 case CLM_SETQUICKSEARCH_TIMEOUT_SETFOCUS: 01856 { 01857 infoPtr->QuickSearchSetFocusDelay = (UINT)wParam; 01858 break; 01859 } 01860 01861 case CLM_FINDITEMBYACCESSMASK: 01862 { 01863 Ret = (LRESULT)FindCheckItemIndexByAccessMask(infoPtr, 01864 (ACCESS_MASK)wParam); 01865 break; 01866 } 01867 01868 case WM_SETFONT: 01869 { 01870 Ret = (LRESULT)RetChangeControlFont(infoPtr, 01871 (HFONT)wParam, 01872 (BOOL)LOWORD(lParam)); 01873 break; 01874 } 01875 01876 case WM_GETFONT: 01877 { 01878 Ret = (LRESULT)infoPtr->hFont; 01879 break; 01880 } 01881 01882 case WM_STYLECHANGED: 01883 { 01884 if (wParam == (WPARAM)GWL_STYLE) 01885 { 01886 UpdateControl(infoPtr); 01887 } 01888 break; 01889 } 01890 01891 case WM_ENABLE: 01892 { 01893 EscapeQuickSearch(infoPtr); 01894 01895 UpdateControl(infoPtr); 01896 break; 01897 } 01898 01899 case WM_MOUSEWHEEL: 01900 { 01901 SHORT ScrollDelta; 01902 UINT ScrollLines = 3; 01903 01904 SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 01905 0, 01906 &ScrollLines, 01907 0); 01908 ScrollDelta = 0 - (SHORT)HIWORD(wParam); 01909 01910 if (ScrollLines != 0 && 01911 abs(ScrollDelta) >= WHEEL_DELTA) 01912 { 01913 SCROLLINFO ScrollInfo; 01914 01915 ScrollInfo.cbSize = sizeof(ScrollInfo); 01916 ScrollInfo.fMask = SIF_RANGE | SIF_POS; 01917 01918 if (GetScrollInfo(hwnd, 01919 SB_VERT, 01920 &ScrollInfo)) 01921 { 01922 INT OldPos = ScrollInfo.nPos; 01923 01924 ScrollInfo.nPos += (ScrollDelta / WHEEL_DELTA) * ScrollLines; 01925 if (ScrollInfo.nPos < 0) 01926 ScrollInfo.nPos = 0; 01927 else if (ScrollInfo.nPos > ScrollInfo.nMax) 01928 ScrollInfo.nPos = ScrollInfo.nMax; 01929 01930 if (OldPos != ScrollInfo.nPos) 01931 { 01932 ScrollInfo.fMask = SIF_POS; 01933 01934 ScrollInfo.nPos = SetScrollInfo(hwnd, 01935 SB_VERT, 01936 &ScrollInfo, 01937 TRUE); 01938 01939 if (OldPos != ScrollInfo.nPos) 01940 { 01941 ScrollWindowEx(hwnd, 01942 0, 01943 (OldPos - ScrollInfo.nPos) * infoPtr->ItemHeight, 01944 NULL, 01945 NULL, 01946 NULL, 01947 NULL, 01948 SW_INVALIDATE | SW_SCROLLCHILDREN); 01949 01950 RedrawWindow(hwnd, 01951 NULL, 01952 NULL, 01953 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN); 01954 } 01955 } 01956 } 01957 } 01958 break; 01959 } 01960 01961 case WM_SETFOCUS: 01962 { 01963 infoPtr->HasFocus = TRUE; 01964 01965 if (infoPtr->FocusedCheckItem == NULL) 01966 { 01967 BOOL Shift = GetKeyState(VK_SHIFT) & 0x8000; 01968 infoPtr->FocusedCheckItem = FindEnabledCheckBox(infoPtr, 01969 Shift, 01970 &infoPtr->FocusedCheckItemBox); 01971 } 01972 if (infoPtr->FocusedCheckItem != NULL) 01973 { 01974 MakeCheckItemVisible(infoPtr, 01975 infoPtr->FocusedCheckItem); 01976 01977 UpdateCheckItem(infoPtr, 01978 infoPtr->FocusedCheckItem); 01979 } 01980 break; 01981 } 01982 01983 case WM_KILLFOCUS: 01984 { 01985 EscapeQuickSearch(infoPtr); 01986 01987 infoPtr->HasFocus = FALSE; 01988 if (infoPtr->FocusedCheckItem != NULL) 01989 { 01990 infoPtr->FocusedPushed = FALSE; 01991 01992 UpdateCheckItem(infoPtr, 01993 infoPtr->FocusedCheckItem); 01994 } 01995 break; 01996 } 01997 01998 case WM_LBUTTONDBLCLK: 01999 case WM_LBUTTONDOWN: 02000 case WM_MBUTTONDOWN: 02001 case WM_RBUTTONDOWN: 02002 { 02003 if (IsWindowEnabled(hwnd)) 02004 { 02005 PCHECKITEM NewFocus; 02006 UINT NewFocusBox = 0; 02007 BOOL InCheckBox; 02008 POINT pt; 02009 BOOL ChangeFocus, Capture = FALSE; 02010 02011 pt.x = (LONG)LOWORD(lParam); 02012 pt.y = (LONG)HIWORD(lParam); 02013 02014 NewFocus = PtToCheckItemBox(infoPtr, 02015 &pt, 02016 &NewFocusBox, 02017 &InCheckBox); 02018 if (NewFocus != NULL) 02019 { 02020 if (NewFocus->State & ((NewFocusBox != CLB_DENY) ? CIS_ALLOWDISABLED : CIS_DENYDISABLED)) 02021 { 02022 /* the user clicked on a disabled checkbox, try to set 02023 the focus to the other one or not change it at all */ 02024 02025 InCheckBox = FALSE; 02026 02027 ChangeFocus = ((NewFocus->State & CIS_DISABLED) != CIS_DISABLED); 02028 if (ChangeFocus) 02029 { 02030 NewFocusBox = ((NewFocusBox != CLB_DENY) ? CLB_DENY : CLB_ALLOW); 02031 } 02032 } 02033 else 02034 { 02035 ChangeFocus = TRUE; 02036 } 02037 02038 if (InCheckBox && ChangeFocus && GetCapture() == NULL && 02039 (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK)) 02040 { 02041 infoPtr->FocusedPushed = TRUE; 02042 Capture = TRUE; 02043 } 02044 } 02045 else 02046 { 02047 ChangeFocus = TRUE; 02048 } 02049 02050 if (ChangeFocus) 02051 { 02052 if (infoPtr->QuickSearchEnabled && infoPtr->QuickSearchHitItem != NULL && 02053 infoPtr->QuickSearchHitItem != NewFocus) 02054 { 02055 EscapeQuickSearch(infoPtr); 02056 } 02057 02058 ChangeCheckItemFocus(infoPtr, 02059 NewFocus, 02060 NewFocusBox); 02061 } 02062 02063 if (!infoPtr->HasFocus) 02064 { 02065 SetFocus(hwnd); 02066 } 02067 02068 if (Capture) 02069 { 02070 SetCapture(hwnd); 02071 } 02072 } 02073 break; 02074 } 02075 02076 case WM_LBUTTONUP: 02077 { 02078 if (GetCapture() == hwnd) 02079 { 02080 if (infoPtr->FocusedCheckItem != NULL && infoPtr->FocusedPushed) 02081 { 02082 PCHECKITEM PtItem; 02083 UINT PtItemBox; 02084 BOOL InCheckBox; 02085 POINT pt; 02086 02087 pt.x = (LONG)LOWORD(lParam); 02088 pt.y = (LONG)HIWORD(lParam); 02089 02090 infoPtr->FocusedPushed = FALSE; 02091 02092 PtItem = PtToCheckItemBox(infoPtr, 02093 &pt, 02094 &PtItemBox, 02095 &InCheckBox); 02096 02097 if (PtItem == infoPtr->FocusedCheckItem && InCheckBox && 02098 PtItemBox == infoPtr->FocusedCheckItemBox) 02099 { 02100 UINT OtherBox = ((PtItemBox == CLB_ALLOW) ? CLB_DENY : CLB_ALLOW); 02101 DWORD OtherStateMask = ((OtherBox == CLB_ALLOW) ? 02102 (CIS_ALLOW | CIS_ALLOWDISABLED) : 02103 (CIS_DENY | CIS_DENYDISABLED)); 02104 DWORD OtherStateOld = PtItem->State & OtherStateMask; 02105 if (ChangeCheckBox(infoPtr, 02106 PtItem, 02107 PtItemBox) && 02108 ((PtItem->State & OtherStateMask) != OtherStateOld)) 02109 { 02110 UpdateCheckItemBox(infoPtr, 02111 infoPtr->FocusedCheckItem, 02112 OtherBox); 02113 } 02114 } 02115 02116 UpdateCheckItemBox(infoPtr, 02117 infoPtr->FocusedCheckItem, 02118 infoPtr->FocusedCheckItemBox); 02119 } 02120 02121 ReleaseCapture(); 02122 } 02123 break; 02124 } 02125 02126 case WM_KEYDOWN: 02127 { 02128 switch (wParam) 02129 { 02130 case VK_SPACE: 02131 { 02132 if (GetCapture() == NULL && 02133 !QuickSearchFindHit(infoPtr, 02134 L' ')) 02135 { 02136 if (infoPtr->FocusedCheckItem != NULL && 02137 (infoPtr->QuickSearchHitItem == NULL || 02138 infoPtr->QuickSearchHitItem == infoPtr->FocusedCheckItem)) 02139 { 02140 UINT OldPushed = infoPtr->FocusedPushed; 02141 infoPtr->FocusedPushed = TRUE; 02142 02143 if (infoPtr->FocusedPushed != OldPushed) 02144 { 02145 MakeCheckItemVisible(infoPtr, 02146 infoPtr->FocusedCheckItem); 02147 02148 UpdateCheckItemBox(infoPtr, 02149 infoPtr->FocusedCheckItem, 02150 infoPtr->FocusedCheckItemBox); 02151 } 02152 } 02153 } 02154 break; 02155 } 02156 02157 case VK_RETURN: 02158 { 02159 if (GetCapture() == NULL && 02160 !QuickSearchFindHit(infoPtr, 02161 L'\n')) 02162 { 02163 if (infoPtr->FocusedCheckItem != NULL && 02164 infoPtr->QuickSearchHitItem == NULL) 02165 { 02166 UINT OtherBox; 02167 DWORD OtherStateMask; 02168 DWORD OtherStateOld; 02169 02170 MakeCheckItemVisible(infoPtr, 02171 infoPtr->FocusedCheckItem); 02172 02173 OtherBox = ((infoPtr->FocusedCheckItemBox == CLB_ALLOW) ? CLB_DENY : CLB_ALLOW); 02174 OtherStateMask = ((OtherBox == CLB_ALLOW) ? 02175 (CIS_ALLOW | CIS_ALLOWDISABLED) : 02176 (CIS_DENY | CIS_DENYDISABLED)); 02177 OtherStateOld = infoPtr->FocusedCheckItem->State & OtherStateMask; 02178 if (ChangeCheckBox(infoPtr, 02179 infoPtr->FocusedCheckItem, 02180 infoPtr->FocusedCheckItemBox)) 02181 { 02182 UpdateCheckItemBox(infoPtr, 02183 infoPtr->FocusedCheckItem, 02184 infoPtr->FocusedCheckItemBox); 02185 if ((infoPtr->FocusedCheckItem->State & OtherStateMask) != OtherStateOld) 02186 { 02187 UpdateCheckItemBox(infoPtr, 02188 infoPtr->FocusedCheckItem, 02189 OtherBox); 02190 } 02191 } 02192 } 02193 } 02194 break; 02195 } 02196 02197 case VK_TAB: 02198 { 02199 if (GetCapture() == NULL) 02200 { 02201 PCHECKITEM NewFocus; 02202 UINT NewFocusBox = 0; 02203 BOOL Shift = GetKeyState(VK_SHIFT) & 0x8000; 02204 02205 EscapeQuickSearch(infoPtr); 02206 02207 NewFocus = FindEnabledCheckBox(infoPtr, 02208 Shift, 02209 &NewFocusBox); 02210 02211 /* update the UI status */ 02212 SendMessage(GetAncestor(hwnd, 02213 GA_PARENT), 02214 WM_CHANGEUISTATE, 02215 MAKEWPARAM(UIS_INITIALIZE, 02216 0), 02217 0); 02218 02219 ChangeCheckItemFocus(infoPtr, 02220 NewFocus, 02221 NewFocusBox); 02222 } 02223 break; 02224 } 02225 02226 default: 02227 { 02228 goto HandleDefaultMessage; 02229 } 02230 } 02231 break; 02232 } 02233 02234 case WM_KEYUP: 02235 { 02236 if (wParam == VK_SPACE && IsWindowEnabled(hwnd) && 02237 infoPtr->FocusedCheckItem != NULL && 02238 infoPtr->FocusedPushed) 02239 { 02240 UINT OtherBox = ((infoPtr->FocusedCheckItemBox == CLB_ALLOW) ? CLB_DENY : CLB_ALLOW); 02241 DWORD OtherStateMask = ((OtherBox == CLB_ALLOW) ? 02242 (CIS_ALLOW | CIS_ALLOWDISABLED) : 02243 (CIS_DENY | CIS_DENYDISABLED)); 02244 DWORD OtherStateOld = infoPtr->FocusedCheckItem->State & OtherStateMask; 02245 02246 infoPtr->FocusedPushed = FALSE; 02247 02248 if (ChangeCheckBox(infoPtr, 02249 infoPtr->FocusedCheckItem, 02250 infoPtr->FocusedCheckItemBox)) 02251 { 02252 UpdateCheckItemBox(infoPtr, 02253 infoPtr->FocusedCheckItem, 02254 infoPtr->FocusedCheckItemBox); 02255 02256 if ((infoPtr->FocusedCheckItem->State & OtherStateMask) != OtherStateOld) 02257 { 02258 UpdateCheckItemBox(infoPtr, 02259 infoPtr->FocusedCheckItem, 02260 OtherBox); 02261 } 02262 } 02263 } 02264 break; 02265 } 02266 02267 case WM_GETDLGCODE: 02268 { 02269 INT virtKey; 02270 02271 Ret = 0; 02272 virtKey = (lParam != 0 ? (INT)((LPMSG)lParam)->wParam : 0); 02273 switch (virtKey) 02274 { 02275 case VK_RETURN: 02276 { 02277 if (infoPtr->QuickSearchEnabled && infoPtr->QuickSearchHitItem != NULL) 02278 { 02279 Ret |= DLGC_WANTCHARS | DLGC_WANTMESSAGE; 02280 } 02281 else 02282 { 02283 Ret |= DLGC_WANTMESSAGE; 02284 } 02285 break; 02286 } 02287 02288 case VK_TAB: 02289 { 02290 UINT CheckBox; 02291 BOOL EnabledBox; 02292 BOOL Shift = GetKeyState(VK_SHIFT) & 0x8000; 02293 02294 EnabledBox = FindEnabledCheckBox(infoPtr, 02295 Shift, 02296 &CheckBox) != NULL; 02297 Ret |= (EnabledBox ? DLGC_WANTTAB : DLGC_WANTCHARS); 02298 break; 02299 } 02300 02301 default: 02302 { 02303 if (infoPtr->QuickSearchEnabled) 02304 { 02305 Ret |= DLGC_WANTCHARS; 02306 } 02307 break; 02308 } 02309 } 02310 break; 02311 } 02312 02313 case WM_CHAR: 02314 { 02315 QuickSearchFindHit(infoPtr, 02316 (WCHAR)wParam); 02317 break; 02318 } 02319 02320 case WM_SYSCOLORCHANGE: 02321 { 02322 infoPtr->TextColor[0] = GetSysColor(COLOR_GRAYTEXT); 02323 infoPtr->TextColor[1] = GetSysColor(COLOR_WINDOWTEXT); 02324 break; 02325 } 02326 02327 #if SUPPORT_UXTHEME 02328 case WM_MOUSELEAVE: 02329 { 02330 if (infoPtr->HoveredCheckItem != NULL) 02331 { 02332 /* reset and repaint the hovered check item box */ 02333 ChangeCheckItemHotTrack(infoPtr, 02334 NULL, 02335 0); 02336 } 02337 break; 02338 } 02339 02340 case WM_THEMECHANGED: 02341 { 02342 if (infoPtr->ThemeHandle != NULL) 02343 { 02344 CloseThemeData(infoPtr->ThemeHandle); 02345 infoPtr->ThemeHandle = NULL; 02346 } 02347 if (IsAppThemed()) 02348 { 02349 infoPtr->ThemeHandle = OpenThemeData(infoPtr->hSelf, 02350 L"BUTTON"); 02351 } 02352 break; 02353 } 02354 #endif 02355 02356 case WM_SETTINGCHANGE: 02357 { 02358 DWORD OldCaretWidth = infoPtr->CaretWidth; 02359 02360 #if SUPPORT_UXTHEME 02361 /* update the hover time */ 02362 if (!SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 02363 0, 02364 &infoPtr->HoverTime, 02365 0)) 02366 { 02367 infoPtr->HoverTime = HOVER_DEFAULT; 02368 } 02369 #endif 02370 02371 /* update the caret */ 02372 if (!SystemParametersInfo(SPI_GETCARETWIDTH, 02373 0, 02374 &infoPtr->CaretWidth, 02375 0)) 02376 { 02377 infoPtr->CaretWidth = 2; 02378 } 02379 if (OldCaretWidth != infoPtr->CaretWidth && infoPtr->ShowingCaret) 02380 { 02381 DestroyCaret(); 02382 CreateCaret(hwnd, 02383 NULL, 02384 infoPtr->CaretWidth, 02385 infoPtr->ItemHeight - (2 * CI_TEXT_MARGIN_HEIGHT)); 02386 } 02387 break; 02388 } 02389 02390 case WM_SIZE: 02391 { 02392 UpdateControl(infoPtr); 02393 break; 02394 } 02395 02396 case WM_UPDATEUISTATE: 02397 { 02398 DWORD OldUIState = infoPtr->UIState; 02399 02400 switch (LOWORD(wParam)) 02401 { 02402 case UIS_SET: 02403 infoPtr->UIState |= HIWORD(wParam); 02404 break; 02405 02406 case UIS_CLEAR: 02407 infoPtr->UIState &= ~(HIWORD(wParam)); 02408 break; 02409 } 02410 02411 if (OldUIState != infoPtr->UIState) 02412 { 02413 if (infoPtr->FocusedCheckItem != NULL) 02414 { 02415 UpdateCheckItemBox(infoPtr, 02416 infoPtr->FocusedCheckItem, 02417 infoPtr->FocusedCheckItemBox); 02418 } 02419 } 02420 break; 02421 } 02422 02423 case WM_TIMER: 02424 { 02425 switch (wParam) 02426 { 02427 case TIMER_ID_SETHITFOCUS: 02428 { 02429 /* kill the timer */ 02430 KillTimer(hwnd, 02431 wParam); 02432 02433 if (infoPtr->QuickSearchEnabled && infoPtr->QuickSearchHitItem != NULL) 02434 { 02435 /* change the focus to the hit item, this item has to have 02436 at least one enabled checkbox! */ 02437 ChangeCheckItemFocus(infoPtr, 02438 infoPtr->QuickSearchHitItem, 02439 ((!(infoPtr->QuickSearchHitItem->State & CIS_ALLOWDISABLED)) ? CLB_ALLOW : CLB_DENY)); 02440 02441 /* start the timer to reset quicksearch */ 02442 if (infoPtr->QuickSearchResetDelay != 0) 02443 { 02444 SetTimer(hwnd, 02445 TIMER_ID_RESETQUICKSEARCH, 02446 infoPtr->QuickSearchResetDelay, 02447 NULL); 02448 } 02449 } 02450 break; 02451 } 02452 case TIMER_ID_RESETQUICKSEARCH: 02453 { 02454 /* kill the timer */ 02455 KillTimer(hwnd, 02456 wParam); 02457 02458 /* escape quick search */ 02459 EscapeQuickSearch(infoPtr); 02460 break; 02461 } 02462 } 02463 break; 02464 } 02465 02466 case WM_CREATE: 02467 { 02468 infoPtr = HeapAlloc(GetProcessHeap(), 02469 0, 02470 sizeof(CHECKLISTWND)); 02471 if (infoPtr != NULL) 02472 { 02473 RECT rcClient; 02474 02475 infoPtr->hSelf = hwnd; 02476 infoPtr->hNotify = ((LPCREATESTRUCTW)lParam)->hwndParent; 02477 02478 SetWindowLongPtr(hwnd, 02479 0, 02480 (DWORD_PTR)infoPtr); 02481 02482 infoPtr->CheckItemListHead = NULL; 02483 infoPtr->CheckItemCount = 0; 02484 02485 if (!SystemParametersInfo(SPI_GETCARETWIDTH, 02486 0, 02487 &infoPtr->CaretWidth, 02488 0)) 02489 { 02490 infoPtr->CaretWidth = 2; 02491 } 02492 infoPtr->ItemHeight = 10; 02493 infoPtr->ShowingCaret = FALSE; 02494 02495 infoPtr->HasFocus = FALSE; 02496 infoPtr->FocusedCheckItem = NULL; 02497 infoPtr->FocusedCheckItemBox = 0; 02498 infoPtr->FocusedPushed = FALSE; 02499 02500 infoPtr->TextColor[0] = GetSysColor(COLOR_GRAYTEXT); 02501 infoPtr->TextColor[1] = GetSysColor(COLOR_WINDOWTEXT); 02502 02503 GetClientRect(hwnd, 02504 &rcClient); 02505 02506 infoPtr->CheckBoxLeft[0] = rcClient.right - 30; 02507 infoPtr->CheckBoxLeft[1] = rcClient.right - 15; 02508 02509 infoPtr->QuickSearchEnabled = FALSE; 02510 infoPtr->QuickSearchText[0] = L'\0'; 02511 02512 infoPtr->QuickSearchSetFocusDelay = DEFAULT_QUICKSEARCH_SETFOCUS_DELAY; 02513 infoPtr->QuickSearchResetDelay = DEFAULT_QUICKSEARCH_RESET_DELAY; 02514 02515 #if SUPPORT_UXTHEME 02516 infoPtr->HoveredCheckItem = NULL; 02517 infoPtr->HoveredCheckItemBox = 0; 02518 if (!SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 02519 0, 02520 &infoPtr->HoverTime, 02521 0)) 02522 { 02523 infoPtr->HoverTime = HOVER_DEFAULT; 02524 } 02525 02526 if (IsAppThemed()) 02527 { 02528 infoPtr->ThemeHandle = OpenThemeData(infoPtr->hSelf, 02529 L"BUTTON"); 02530 } 02531 else 02532 { 02533 infoPtr->ThemeHandle = NULL; 02534 } 02535 #endif 02536 02537 infoPtr->UIState = SendMessage(hwnd, 02538 WM_QUERYUISTATE, 02539 0, 02540 0); 02541 } 02542 else 02543 { 02544 Ret = -1; 02545 } 02546 break; 02547 } 02548 02549 case WM_DESTROY: 02550 { 02551 if (infoPtr->ShowingCaret) 02552 { 02553 DestroyCaret(); 02554 } 02555 02556 ClearCheckItems(infoPtr); 02557 02558 #if SUPPORT_UXTHEME 02559 if (infoPtr->ThemeHandle != NULL) 02560 { 02561 CloseThemeData(infoPtr->ThemeHandle); 02562 } 02563 #endif 02564 02565 HeapFree(GetProcessHeap(), 02566 0, 02567 infoPtr); 02568 SetWindowLongPtr(hwnd, 02569 0, 02570 (DWORD_PTR)NULL); 02571 break; 02572 } 02573 02574 default: 02575 { 02576 HandleDefaultMessage: 02577 Ret = DefWindowProc(hwnd, 02578 uMsg, 02579 wParam, 02580 lParam); 02581 break; 02582 } 02583 } 02584 02585 return Ret; 02586 } 02587 02588 BOOL 02589 RegisterCheckListControl(IN HINSTANCE hInstance) 02590 { 02591 WNDCLASS wc; 02592 02593 wc.style = CS_DBLCLKS; 02594 wc.lpfnWndProc = CheckListWndProc; 02595 wc.cbClsExtra = 0; 02596 wc.cbWndExtra = sizeof(PCHECKLISTWND); 02597 wc.hInstance = hInstance; 02598 wc.hIcon = NULL; 02599 wc.hCursor = LoadCursor(NULL, 02600 (LPWSTR)IDC_ARROW); 02601 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 02602 wc.lpszMenuName = NULL; 02603 wc.lpszClassName = szCheckListWndClass; 02604 02605 return RegisterClass(&wc) != 0; 02606 } 02607 02608 VOID 02609 UnregisterCheckListControl(HINSTANCE hInstance) 02610 { 02611 UnregisterClass(szCheckListWndClass, 02612 hInstance); 02613 } Generated on Sun May 27 2012 04:22:36 for ReactOS by
1.7.6.1
|