initial (not yet complete) implementation of the checklist control for the permissions editor Modified: trunk/reactos/lib/aclui/aclui.c Modified: trunk/reactos/lib/aclui/aclui.xml Modified: trunk/reactos/lib/aclui/aclui_De.rc Modified: trunk/reactos/lib/aclui/aclui_En.rc Modified: trunk/reactos/lib/aclui/aclui_Sv.rc Modified: trunk/reactos/lib/aclui/acluilib.h Added: trunk/reactos/lib/aclui/checklist.c Modified: trunk/reactos/lib/aclui/misc.c Modified: trunk/reactos/lib/aclui/resource.h _____
Modified: trunk/reactos/lib/aclui/aclui.c --- trunk/reactos/lib/aclui/aclui.c 2005-07-01 23:26:01 UTC (rev 16373) +++ trunk/reactos/lib/aclui/aclui.c 2005-07-01 23:33:34 UTC (rev 16374) @@ -30,32 +30,6 @@
HINSTANCE hDllInstance;
-static LPARAM -ListViewGetSelectedItemData(IN HWND hwnd) -{ - int Index; - - Index = ListView_GetNextItem(hwnd, - -1, - LVNI_SELECTED); - if (Index != -1) - { - LVITEM li; - - li.mask = LVIF_PARAM; - li.iItem = Index; - li.iSubItem = 0; - - if (ListView_GetItem(hwnd, - &li)) - { - return li.lParam; - } - } - - return 0; -} - static VOID DestroySecurityPage(IN PSECURITY_PAGE sp) { @@ -363,6 +337,38 @@ } }
+static INT +AddAceListEntry(IN PSECURITY_PAGE sp, + IN PACE_LISTITEM AceListItem, + IN INT Index, + IN BOOL Selected) +{ + LVITEM li; + + li.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE | LVIF_TEXT; + li.iItem = Index; + li.iSubItem = 0; + li.state = (Selected ? LVIS_SELECTED : 0); + li.stateMask = LVIS_SELECTED; + li.pszText = (AceListItem->DisplayString != NULL ? AceListItem->DisplayString : AceListItem->AccountName); + switch (AceListItem->SidNameUse) + { + case SidTypeUser: + li.iImage = 0; + break; + case SidTypeGroup: + li.iImage = 1; + break; + default: + li.iImage = -1; + break; + } + li.lParam = (LPARAM)AceListItem; + + return ListView_InsertItem(sp->hWndAceList, + &li); +} + static VOID FillUsersGroupsList(IN PSECURITY_PAGE sp) { @@ -382,30 +388,10 @@ CurItem != NULL; CurItem = CurItem->Next) { - LVITEM li; - - li.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE | LVIF_TEXT; - li.iItem = -1; - li.iSubItem = 0; - li.state = (CurItem == (PACE_LISTITEM)SelLParam ? LVIS_SELECTED : 0); - li.stateMask = LVIS_SELECTED; - li.pszText = (CurItem->DisplayString != NULL ? CurItem->DisplayString : CurItem->AccountName); - switch (CurItem->SidNameUse) - { - case SidTypeUser: - li.iImage = 0; - break; - case SidTypeGroup: - li.iImage = 1; - break; - default: - li.iImage = -1; - break; - } - li.lParam = (LPARAM)CurItem; - - ListView_InsertItem(sp->hWndAceList, - &li); + AddAceListEntry(sp, + CurItem, + -1, + (SelLParam == (LPARAM)CurItem)); }
EnableRedrawWindow(sp->hWndAceList); @@ -417,7 +403,16 @@ rcLvClient.right); }
+static VOID +UpdateControlStates(IN PSECURITY_PAGE sp) +{ + BOOL UserOrGroupSelected; + + UserOrGroupSelected = (ListViewGetSelectedItemData(sp->hWndAceList) != 0);
+ EnableWindow(sp->hBtnRemove, UserOrGroupSelected); +} + static UINT CALLBACK SecurityPageCallback(IN HWND hwnd, IN UINT uMsg, @@ -434,6 +429,7 @@ case PSPCB_RELEASE: { DestroySecurityPage(sp); + UnregisterCheckListControl(); return FALSE; } } @@ -441,7 +437,30 @@ return FALSE; }
+static VOID +SetAceCheckListColumns(IN HWND hAceCheckList, + IN UINT Button, + IN HWND hLabel) +{ + POINT pt; + RECT rcLabel;
+ GetWindowRect(hLabel, + &rcLabel); + pt.y = 0; + pt.x = (rcLabel.right - rcLabel.left) / 2; + MapWindowPoints(hLabel, + hAceCheckList, + &pt, + 1); + + SendMessage(hAceCheckList, + CLM_SETCHECKBOXCOLUMN, + Button, + pt.x); +} + + static INT_PTR CALLBACK SecurityPageProc(IN HWND hwndDlg, IN UINT uMsg, @@ -452,6 +471,28 @@
switch(uMsg) { + case WM_NOTIFY: + { + NMHDR *pnmh = (NMHDR*)lParam; + if (pnmh->idFrom == IDC_ACELIST) + { + sp = (PSECURITY_PAGE)GetWindowLongPtr(hwndDlg, + DWL_USER); + if (sp != NULL) + { + switch(pnmh->code) + { + case LVN_ITEMCHANGED: + { + UpdateControlStates(sp); + break; + } + } + } + } + break; + } + case WM_INITDIALOG: { sp = (PSECURITY_PAGE)((LPPROPSHEETPAGE)lParam)->lParam; @@ -462,6 +503,8 @@
sp->hWnd = hwndDlg; sp->hWndAceList = GetDlgItem(hwndDlg, IDC_ACELIST); + sp->hBtnRemove = GetDlgItem(hwndDlg, IDC_ACELIST_REMOVE); + sp->hAceCheckList = GetDlgItem(hwndDlg, IDC_ACE_CHECKLIST);
/* save the pointer to the structure */ SetWindowLongPtr(hwndDlg, @@ -491,7 +534,18 @@ ListView_InsertColumn(sp->hWndAceList, 0, &lvc);
FillUsersGroupsList(sp); + + ListViewSelectItem(sp->hWndAceList, + 0);
+ /* calculate the columns of the allow/deny checkboxes */ + SetAceCheckListColumns(sp->hAceCheckList, + CLB_ALLOW, + GetDlgItem(hwndDlg, IDC_LABEL_ALLOW)); + SetAceCheckListColumns(sp->hAceCheckList, + CLB_DENY, + GetDlgItem(hwndDlg, IDC_LABEL_DENY)); + /* FIXME - hide controls in case the flags aren't present */ } break; @@ -530,10 +584,16 @@ { SetLastError(hRet);
- DPRINT("CreateSecurityPage() failed!\n"); + DPRINT("CreateSecurityPage() failed! Failed to query the object information!\n"); return NULL; }
+ if (!RegisterCheckListControl(hDllInstance)) + { + DPRINT("Registering the CHECKLIST_ACLUI class failed!\n"); + return NULL; + } + sPage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SECURITY_PAGE)); @@ -555,7 +615,7 @@ psp.lParam = (LPARAM)sPage; psp.pfnCallback = SecurityPageCallback;
- if((ObjectInfo.dwFlags & SI_PAGE_TITLE) != 0 && + if((ObjectInfo.dwFlags & SI_PAGE_TITLE) && ObjectInfo.pszPageTitle != NULL && ObjectInfo.pszPageTitle[0] != L'\0') { /* Set the page title if the flag is present and the string isn't empty */ @@ -618,7 +678,7 @@ psh.dwFlags = PSH_DEFAULT; psh.hwndParent = hwndOwner; psh.hInstance = hDllInstance; - if((ObjectInfo.dwFlags & SI_PAGE_TITLE) != 0 && + if((ObjectInfo.dwFlags & SI_PAGE_TITLE) && ObjectInfo.pszPageTitle != NULL && ObjectInfo.pszPageTitle[0] != L'\0') { /* Set the page title if the flag is present and the string isn't empty */ _____
Modified: trunk/reactos/lib/aclui/aclui.xml --- trunk/reactos/lib/aclui/aclui.xml 2005-07-01 23:26:01 UTC (rev 16373) +++ trunk/reactos/lib/aclui/aclui.xml 2005-07-01 23:33:34 UTC (rev 16374) @@ -10,8 +10,10 @@
<library>ntdll</library> <library>kernel32</library> <library>user32</library> + <library>gdi32</library> <library>comctl32</library> <file>aclui.c</file> + <file>checklist.c</file> <file>misc.c</file> <file>aclui.rc</file> <pch>acluilib.h</pch> _____
Modified: trunk/reactos/lib/aclui/aclui_De.rc --- trunk/reactos/lib/aclui/aclui_De.rc 2005-07-01 23:26:01 UTC (rev 16373) +++ trunk/reactos/lib/aclui/aclui_De.rc 2005-07-01 23:33:34 UTC (rev 16374) @@ -1,7 +1,7 @@
LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT
IDD_SECPAGE DIALOGEX 0, 0, 227, 215 -STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +STYLE DS_NOFAILCREATE | DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_CAPTION CAPTION "Sicherheit" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN @@ -9,8 +9,9 @@ CONTROL "", IDC_ACELIST, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 7, 17, 213, 66, WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE PUSHBUTTON "&Hinzuf³gen...", IDC_ACELIST_ADD, 116, 87, 50, 14 PUSHBUTTON "&Entfernen", IDC_ACELIST_REMOVE, 170, 87, 50, 14 - LTEXT "Erlauben", -1, 135, 107, 32, 8, SS_CENTER - LTEXT "Verbieten", -1, 176, 107, 32, 8, SS_CENTER + LTEXT "Erlauben", IDC_LABEL_ALLOW, 135, 107, 32, 8, SS_CENTER + LTEXT "Verbieten", IDC_LABEL_DENY, 176, 107, 32, 8, SS_CENTER + CONTROL "", IDC_ACE_CHECKLIST, "CHECKLIST_ACLUI", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 117, 213, 72, WS_EX_CLIENTEDGE END
STRINGTABLE DISCARDABLE _____
Modified: trunk/reactos/lib/aclui/aclui_En.rc --- trunk/reactos/lib/aclui/aclui_En.rc 2005-07-01 23:26:01 UTC (rev 16373) +++ trunk/reactos/lib/aclui/aclui_En.rc 2005-07-01 23:33:34 UTC (rev 16374) @@ -1,7 +1,7 @@
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
IDD_SECPAGE DIALOGEX 0, 0, 227, 215 -STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +STYLE DS_NOFAILCREATE | DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_CAPTION CAPTION "Security" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN @@ -9,8 +9,9 @@ CONTROL "", IDC_ACELIST, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 7, 17, 213, 66, WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE PUSHBUTTON "A&dd...", IDC_ACELIST_ADD, 116, 87, 50, 14 PUSHBUTTON "&Remove", IDC_ACELIST_REMOVE, 170, 87, 50, 14 - LTEXT "Allow", -1, 135, 107, 32, 8, SS_CENTER - LTEXT "Deny", -1, 176, 107, 32, 8, SS_CENTER + LTEXT "Allow", IDC_LABEL_ALLOW, 135, 107, 32, 8, SS_CENTER + LTEXT "Deny", IDC_LABEL_DENY, 176, 107, 32, 8, SS_CENTER + CONTROL "", IDC_ACE_CHECKLIST, "CHECKLIST_ACLUI", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 117, 213, 72, WS_EX_CLIENTEDGE END
STRINGTABLE DISCARDABLE _____
Modified: trunk/reactos/lib/aclui/aclui_Sv.rc --- trunk/reactos/lib/aclui/aclui_Sv.rc 2005-07-01 23:26:01 UTC (rev 16373) +++ trunk/reactos/lib/aclui/aclui_Sv.rc 2005-07-01 23:33:34 UTC (rev 16374) @@ -19,7 +19,7 @@
LANGUAGE LANG_SWEDISH, SUBLANG_DEFAULT
IDD_SECPAGE DIALOGEX 0, 0, 227, 215 -STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +STYLE DS_NOFAILCREATE | DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_CAPTION CAPTION "Sõkerhet" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN @@ -27,8 +27,9 @@ CONTROL "", IDC_ACELIST, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 7, 17, 213, 66, WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE PUSHBUTTON "&Lõgg till...", IDC_ACELIST_ADD, 116, 87, 50, 14 PUSHBUTTON "&Ta bort", IDC_ACELIST_REMOVE, 170, 87, 50, 14 - LTEXT "TillÕt", -1, 135, 107, 32, 8, SS_CENTER - LTEXT "Neka", -1, 176, 107, 32, 8, SS_CENTER + LTEXT "TillÕt", IDC_LABEL_ALLOW, 135, 107, 32, 8, SS_CENTER + LTEXT "Neka", IDC_LABEL_DENY, 176, 107, 32, 8, SS_CENTER + CONTROL "", IDC_ACE_CHECKLIST, "CHECKLIST_ACLUI", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 117, 213, 72, WS_EX_CLIENTEDGE END
STRINGTABLE DISCARDABLE _____
Modified: trunk/reactos/lib/aclui/acluilib.h --- trunk/reactos/lib/aclui/acluilib.h 2005-07-01 23:26:01 UTC (rev 16373) +++ trunk/reactos/lib/aclui/acluilib.h 2005-07-01 23:33:34 UTC (rev 16374) @@ -33,6 +33,8 @@
typedef struct _SECURITY_PAGE { HWND hWnd; + HWND hBtnRemove; + HWND hAceCheckList;
/* Main ACE List */ HWND hWndAceList; @@ -44,6 +46,8 @@ SI_OBJECT_INFO ObjectInfo; } SECURITY_PAGE, *PSECURITY_PAGE;
+/* MISC ***********************************************************************/ + BOOL OpenLSAPolicyHandle(IN WCHAR *SystemName, IN ACCESS_MASK DesiredAccess, @@ -55,4 +59,36 @@ OUT LPWSTR *lpTarget, ...);
+LPARAM +ListViewGetSelectedItemData(IN HWND hwnd); + +BOOL +ListViewSelectItem(IN HWND hwnd, + IN INT Index); + +/* CHECKLIST CONTROL **********************************************************/ + +#define CIS_DISABLED (0x2) +#define CIS_ENABLED (0x0) +#define CIS_ALLOW (0x1) +#define CIS_DENY (0x0) + +#define CLB_ALLOW (0x1) +#define CLB_DENY (0x0) + +#define CIS_MASK (CIS_DISABLED | CIS_ALLOW | CIS_DENY) + +#define CLM_ADDITEM (WM_USER + 1) +#define CLM_DELITEM (WM_USER + 2) +#define CLM_GETITEMCOUNT (WM_USER + 3) +#define CLM_CLEAR (WM_USER + 4) +#define CLM_SETCHECKBOXCOLUMN (WM_USER + 5) +#define CLM_GETCHECKBOXCOLUMN (WM_USER + 6) + +BOOL +RegisterCheckListControl(HINSTANCE hInstance); + +VOID +UnregisterCheckListControl(VOID); + /* EOF */ _____
Added: trunk/reactos/lib/aclui/checklist.c --- trunk/reactos/lib/aclui/checklist.c 2005-07-01 23:26:01 UTC (rev 16373) +++ trunk/reactos/lib/aclui/checklist.c 2005-07-01 23:33:34 UTC (rev 16374) @@ -0,0 +1,785 @@
+/* + * ReactOS Access Control List Editor + * Copyright (C) 2004 ReactOS Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* $Id$ + * + * PROJECT: ReactOS Access Control List Editor + * FILE: lib/aclui/checklist.c + * PURPOSE: Access Control List Editor + * PROGRAMMER: Thomas Weidenmueller w3seek@reactos.com + * + * UPDATE HISTORY: + * 08/10/2004 Created + */ +#include "acluilib.h" + +typedef struct _CHECKITEM +{ + struct _CHECKITEM *Next; + DWORD State; + WCHAR Name[1]; +} CHECKITEM, *PCHECKITEM; + +typedef struct _CHECKLISTWND +{ + HWND hSelf; + HWND hNotify; + DWORD Style; + HFONT hFont; + + PCHECKITEM CheckItemListHead; + UINT CheckItemCount; + + INT ItemHeight; + BOOL HasFocus; + + COLORREF TextColor[2]; + UINT CheckBoxLeft[2]; +} CHECKLISTWND, *PCHECKLISTWND; + +static PCHECKITEM +FindCheckItemByIndex(IN PCHECKLISTWND infoPtr, + IN UINT Index) +{ + PCHECKITEM Item, Found = NULL; + + for (Item = infoPtr->CheckItemListHead; + Item != NULL; + Item = Item->Next) + { + if (Index == 0) + { + Found = Item; + break; + } + + Index--; + } + + return Found; +} + +static VOID +ClearCheckItems(IN PCHECKLISTWND infoPtr) +{ + PCHECKITEM CurItem, NextItem; + + CurItem = infoPtr->CheckItemListHead; + while (CurItem != NULL) + { + NextItem = CurItem->Next; + HeapFree(GetProcessHeap(), + 0, + CurItem); + CurItem = NextItem; + } + + infoPtr->CheckItemListHead = NULL; + infoPtr->CheckItemCount = 0; +} + +static BOOL +DeleteCheckItem(IN PCHECKLISTWND infoPtr, + IN PCHECKITEM Item) +{ + PCHECKITEM CurItem; + PCHECKITEM *PrevPtr = &infoPtr->CheckItemListHead; + + for (CurItem = infoPtr->CheckItemListHead; + CurItem != NULL; + CurItem = CurItem->Next) + { + if (CurItem == Item) + { + *PrevPtr = CurItem->Next; + HeapFree(GetProcessHeap(), + 0, + CurItem); + infoPtr->CheckItemCount--; + return TRUE; + } + + PrevPtr = &CurItem->Next; + } + + return FALSE; +} + +static PCHECKITEM +AddCheckItem(IN PCHECKLISTWND infoPtr, + IN LPWSTR Name, + IN DWORD State) +{ + PCHECKITEM CurItem; + PCHECKITEM *PrevPtr = &infoPtr->CheckItemListHead; + PCHECKITEM Item = HeapAlloc(GetProcessHeap(), + 0, + sizeof(CHECKITEM) + (wcslen(Name) * sizeof(WCHAR))); + if (Item != NULL) + { + for (CurItem = infoPtr->CheckItemListHead; + CurItem != NULL; + CurItem = CurItem->Next) + { + PrevPtr = &CurItem->Next; + } + + Item->Next = NULL; + Item->State = State & CIS_MASK; + wcscpy(Item->Name, + Name); + + *PrevPtr = Item; + infoPtr->CheckItemCount++; + } + + return Item; +} + +static VOID +UpdateControl(IN PCHECKLISTWND infoPtr, + IN BOOL AllowChangeStyle) +{ + RECT rcClient; + SCROLLINFO ScrollInfo; + + GetClientRect(infoPtr->hSelf, + &rcClient); + + ScrollInfo.cbSize = sizeof(ScrollInfo); + ScrollInfo.fMask = SIF_PAGE | SIF_RANGE; + ScrollInfo.nMin = 0; + ScrollInfo.nMax = infoPtr->CheckItemCount; + ScrollInfo.nPage = ((rcClient.bottom - rcClient.top) + infoPtr->ItemHeight - 1) / infoPtr->ItemHeight; + ScrollInfo.nPos = 0; + ScrollInfo.nTrackPos = 0; + + if (AllowChangeStyle) + { + /* determine whether the vertical scrollbar has to be visible or not */ + if (ScrollInfo.nMax > ScrollInfo.nPage && + !(infoPtr->Style & WS_VSCROLL)) + { + SetWindowLong(infoPtr->hSelf, + GWL_STYLE, + infoPtr->Style | WS_VSCROLL); + } + else if (ScrollInfo.nMax < ScrollInfo.nPage && + infoPtr->Style & WS_VSCROLL) + { + SetWindowLong(infoPtr->hSelf, + GWL_STYLE, + infoPtr->Style & ~WS_VSCROLL); + } + } + + SetScrollInfo(infoPtr->hSelf, + SB_VERT, + &ScrollInfo, + TRUE); + + RedrawWindow(infoPtr->hSelf, + NULL, + NULL, + RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN); +} + +static UINT +GetIdealItemHeight(IN PCHECKLISTWND infoPtr) +{ + HDC hdc = GetDC(infoPtr->hSelf); + if(hdc != NULL) + { + UINT height; + TEXTMETRIC tm; + HGDIOBJ hOldFont = SelectObject(hdc, + infoPtr->hFont); + + if(GetTextMetrics(hdc, + &tm)) + { + height = tm.tmHeight; + } + else + { + height = 0; + } + + SelectObject(hdc, + hOldFont); + + ReleaseDC(infoPtr->hSelf, + hdc); + + return height; + } + return 0; +} + +static HFONT +RetChangeControlFont(IN PCHECKLISTWND infoPtr, + IN HFONT hFont, + IN BOOL Redraw) +{ + HFONT hOldFont = infoPtr->hFont; + infoPtr->hFont = hFont; + + if (hOldFont != hFont) + { + infoPtr->ItemHeight = 4 + GetIdealItemHeight(infoPtr); + } + + UpdateControl(infoPtr, + TRUE); + + return hOldFont; +} + +static VOID +PaintControl(IN PCHECKLISTWND infoPtr, + IN HDC hDC, + IN PRECT rcUpdate) +{ + INT ScrollPos; + PCHECKITEM FirstItem, Item; + RECT rcClient; + UINT VisibleFirstIndex = rcUpdate->top / infoPtr->ItemHeight; + UINT LastTouchedIndex = rcUpdate->bottom / infoPtr->ItemHeight; + + FillRect(hDC, + rcUpdate, + (HBRUSH)(COLOR_WINDOW + 1)); + + GetClientRect(infoPtr->hSelf, &rcClient); + + if (infoPtr->Style & WS_VSCROLL) + { + ScrollPos = GetScrollPos(infoPtr->hSelf, + SB_VERT); + } + else + { + ScrollPos = 0; + } + + FirstItem = FindCheckItemByIndex(infoPtr, + ScrollPos + VisibleFirstIndex); + if (FirstItem != NULL) + { + RECT TextRect, ItemRect; + HFONT hOldFont; + DWORD CurrentIndex; + COLORREF OldTextColor; + BOOL Enabled, PrevEnabled; + POINT ptOld; + + Enabled = IsWindowEnabled(infoPtr->hSelf); + PrevEnabled = Enabled; + + ItemRect.left = 0; + ItemRect.right = rcClient.right; + ItemRect.top = VisibleFirstIndex * infoPtr->ItemHeight; + + TextRect.left = ItemRect.left + 6; + TextRect.right = ItemRect.right - 6; + TextRect.top = ItemRect.top + 2; + + MoveToEx(hDC, + infoPtr->CheckBoxLeft[CLB_ALLOW], + ItemRect.top, + &ptOld); + + OldTextColor = SetTextColor(hDC, + infoPtr->TextColor[Enabled]); + + hOldFont = SelectObject(hDC, + infoPtr->hFont); + + for (Item = FirstItem, CurrentIndex = VisibleFirstIndex; + Item != NULL && CurrentIndex <= LastTouchedIndex; + Item = Item->Next, CurrentIndex++) + { + TextRect.bottom = TextRect.top + infoPtr->ItemHeight; + + if (Enabled && PrevEnabled != ((Item->State & CIS_DISABLED) == 0)) + { + PrevEnabled = ((Item->State & CIS_DISABLED) == 0); + + SetTextColor(hDC, + infoPtr->TextColor[PrevEnabled]); + } + + DrawText(hDC, + Item->Name, + -1, + &TextRect, + DT_LEFT | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER); + + MoveToEx(hDC, + infoPtr->CheckBoxLeft[CLB_ALLOW], + TextRect.top - 6, + NULL); + LineTo(hDC, + infoPtr->CheckBoxLeft[CLB_ALLOW], + TextRect.bottom - 6); + MoveToEx(hDC, + infoPtr->CheckBoxLeft[CLB_DENY], + TextRect.top - 6, + NULL); + LineTo(hDC, + infoPtr->CheckBoxLeft[CLB_DENY], + TextRect.bottom - 6); + + TextRect.top += infoPtr->ItemHeight; + } + + SelectObject(hDC, + hOldFont); + + SetTextColor(hDC, + OldTextColor); + + MoveToEx(hDC, + ptOld.x, + ptOld.y, + NULL); + } +} + +LRESULT CALLBACK +CheckListWndProc(IN HWND hwnd, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam) +{ + PCHECKLISTWND infoPtr; + LRESULT Ret; + + infoPtr = (PCHECKLISTWND)GetWindowLongPtr(hwnd, + 0); + + if (infoPtr == NULL && uMsg != WM_CREATE) + { + return DefWindowProc(hwnd, + uMsg, + wParam, + lParam); + } + + Ret = 0; + + switch (uMsg) + { + case WM_PAINT: + { + HDC hdc; + RECT rcUpdate; + PAINTSTRUCT ps; + + if (GetUpdateRect(hwnd, + &rcUpdate, + FALSE)) + { + hdc = (wParam != 0 ? (HDC)wParam : BeginPaint(hwnd, &ps)); + + PaintControl(infoPtr, + hdc, + &rcUpdate); + + if (wParam == 0) + { + EndPaint(hwnd, + &ps); + } + } + break; + } + + case WM_VSCROLL: + { + SCROLLINFO ScrollInfo; + + ScrollInfo.cbSize = sizeof(ScrollInfo); + ScrollInfo.fMask = SIF_PAGE | SIF_RANGE | SIF_POS | SIF_TRACKPOS; + + if (GetScrollInfo(hwnd, + SB_VERT, + &ScrollInfo)) + { + INT OldPos = ScrollInfo.nPos; + + switch (LOWORD(wParam)) + { + case SB_BOTTOM: + ScrollInfo.nPos = ScrollInfo.nMax; + break; + + case SB_LINEDOWN: + if (ScrollInfo.nPos < ScrollInfo.nMax) + { + ScrollInfo.nPos++; + } + break; + + case SB_LINEUP: + if (ScrollInfo.nPos > 0) + { + ScrollInfo.nPos--; + } + break; + + case SB_PAGEDOWN: + if (ScrollInfo.nPos + ScrollInfo.nPage <= ScrollInfo.nMax) + { + ScrollInfo.nPos += ScrollInfo.nPage; + } + else + { + ScrollInfo.nPos = ScrollInfo.nMax; + } + break; + + case SB_PAGEUP: + if (ScrollInfo.nPos >= ScrollInfo.nPage) + { + ScrollInfo.nPos -= ScrollInfo.nPage; + } + else + { + ScrollInfo.nPos = 0; + } + break; + + case SB_THUMBPOSITION: + { + ScrollInfo.nPos = HIWORD(wParam); + break; + } + + case SB_THUMBTRACK: + { + ScrollInfo.nPos = ScrollInfo.nTrackPos; + break; + } + + case SB_TOP: + ScrollInfo.nPos = 0; + break; + } + + if (OldPos != ScrollInfo.nPos) + { + ScrollInfo.fMask = SIF_POS; + + ScrollInfo.nPos = SetScrollInfo(hwnd, + SB_VERT, + &ScrollInfo, + TRUE); + + if (OldPos != ScrollInfo.nPos) + { + ScrollWindowEx(hwnd, + 0, + (OldPos - ScrollInfo.nPos) * infoPtr->ItemHeight, + NULL, + NULL, + NULL, + NULL, + SW_INVALIDATE); + + RedrawWindow(hwnd, + NULL, + NULL, + RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN); + } + } + } + break; + } + + case CLM_ADDITEM: + { + Ret = (AddCheckItem(infoPtr, + (LPWSTR)lParam, + (DWORD)wParam) != NULL); + if (Ret) + { + UpdateControl(infoPtr, + TRUE); + } + break; + } + + case CLM_DELITEM: + { + PCHECKITEM Item = FindCheckItemByIndex(infoPtr, + wParam); + if (Item != NULL) + { + Ret = DeleteCheckItem(infoPtr, + Item); + if (Ret) + { + UpdateControl(infoPtr, + TRUE); + } + } + else + { + Ret = FALSE; + } + break; + } + + case CLM_GETITEMCOUNT: + { + Ret = infoPtr->CheckItemCount; + break; + } + + case CLM_CLEAR: + { + ClearCheckItems(infoPtr); + UpdateControl(infoPtr, + TRUE); + break; + } + + case CLM_SETCHECKBOXCOLUMN: + { + infoPtr->CheckBoxLeft[wParam != CLB_DENY] = (UINT)lParam; + Ret = 1; + break; + } + + case CLM_GETCHECKBOXCOLUMN: + { + Ret = (LRESULT)infoPtr->CheckBoxLeft[wParam != CLB_DENY]; + break; + } + + case WM_SETFONT: + { + Ret = (LRESULT)RetChangeControlFont(infoPtr, + (HFONT)wParam, + (BOOL)lParam); + break; + } + + case WM_GETFONT: + { + Ret = (LRESULT)infoPtr->hFont; [truncated at 1000 lines; 270 more skipped]