ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

checklist.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.