1 /* 2 * 'View' tab property sheet of Folder Options 3 * 4 * Copyright 2007 Johannes Anderwald <johannes.anderwald@reactos.org> 5 * Copyright 2016-2018 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "precomp.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL (fprop); 25 26 ///////////////////////////////////////////////////////////////////////////// 27 // View Tree 28 29 // predefined icon IDs (See ViewDlg_CreateTreeImageList function below) 30 #define I_CHECKED 0 31 #define I_UNCHECKED 1 32 #define I_CHECKED_DISABLED 2 33 #define I_UNCHECKED_DISABLED 3 34 #define I_RADIO_CHECKED 4 35 #define I_RADIO_UNCHECKED 5 36 #define I_RADIO_CHECKED_DISABLED 6 37 #define I_RADIO_UNCHECKED_DISABLED 7 38 #define PREDEFINED_ICON_COUNT 8 39 40 // uniquely-defined icon entry for View Advanced Settings 41 typedef struct VIEWTREE_ICON 42 { 43 WCHAR szPath[MAX_PATH]; 44 UINT nIconIndex; 45 } VIEWTREE_ICON, *PVIEWTREE_ICON; 46 47 // types of View Advanced Setting entry 48 typedef enum VIEWTREE_ENTRY_TYPE 49 { 50 AETYPE_GROUP, 51 AETYPE_CHECKBOX, 52 AETYPE_RADIO, 53 } VIEWTREE_ENTRY_TYPE, *PVIEWTREE_ENTRY_TYPE; 54 55 // an entry info of View Advanced Settings 56 typedef struct VIEWTREE_ENTRY 57 { 58 DWORD dwID; // entry ID 59 DWORD dwParentID; // parent entry ID 60 DWORD dwResourceID; // resource ID 61 WCHAR szKeyName[64]; // entry key name 62 DWORD dwType; // VIEWTREE_ENTRY_TYPE 63 WCHAR szText[MAX_PATH]; // text 64 INT nIconID; // icon ID (See VIEWTREE_ICON) 65 66 HKEY hkeyRoot; // registry root key 67 WCHAR szRegPath[MAX_PATH]; // registry path 68 WCHAR szValueName[64]; // registry value name 69 70 DWORD dwCheckedValue; // checked value 71 DWORD dwUncheckedValue; // unchecked value 72 DWORD dwDefaultValue; // defalut value 73 BOOL bHasUncheckedValue; // If FALSE, UncheckedValue is invalid 74 75 HTREEITEM hItem; // for TreeView 76 BOOL bGrayed; // disabled? 77 BOOL bChecked; // checked? 78 } VIEWTREE_ENTRY, *PVIEWTREE_ENTRY; 79 80 // definition of view advanced entries 81 static PVIEWTREE_ENTRY s_ViewTreeEntries = NULL; 82 static INT s_ViewTreeEntryCount = 0; 83 84 // definition of icon stock 85 static PVIEWTREE_ICON s_ViewTreeIcons = NULL; 86 static INT s_ViewTreeIconCount = 0; 87 static HIMAGELIST s_hTreeImageList = NULL; 88 89 static INT 90 ViewTree_FindIcon(LPCWSTR pszPath, UINT nIconIndex) 91 { 92 for (INT i = PREDEFINED_ICON_COUNT; i < s_ViewTreeIconCount; ++i) 93 { 94 PVIEWTREE_ICON pIcon = &s_ViewTreeIcons[i]; 95 if (pIcon->nIconIndex == nIconIndex && 96 lstrcmpiW(pIcon->szPath, pszPath) == 0) 97 { 98 return i; // icon ID 99 } 100 } 101 return -1; // not found 102 } 103 104 static INT 105 ViewTree_AddIcon(LPCWSTR pszPath, UINT nIconIndex) 106 { 107 PVIEWTREE_ICON pAllocated; 108 109 // return the ID if already existed 110 INT nIconID = ViewTree_FindIcon(pszPath, nIconIndex); 111 if (nIconID != -1) 112 return nIconID; // already exists 113 114 // extract a small icon 115 HICON hIconSmall = NULL; 116 ExtractIconExW(pszPath, nIconIndex, NULL, &hIconSmall, 1); 117 if (hIconSmall == NULL) 118 return -1; // failure 119 120 // resize s_ViewTreeIcons 121 size_t Size = (s_ViewTreeIconCount + 1) * sizeof(VIEWTREE_ICON); 122 pAllocated = (PVIEWTREE_ICON)realloc(s_ViewTreeIcons, Size); 123 if (pAllocated == NULL) 124 return -1; // failure 125 else 126 s_ViewTreeIcons = pAllocated; 127 128 // save icon information 129 PVIEWTREE_ICON pIcon = &s_ViewTreeIcons[s_ViewTreeIconCount]; 130 lstrcpynW(pIcon->szPath, pszPath, _countof(pIcon->szPath)); 131 pIcon->nIconIndex = nIconIndex; 132 133 // add the icon to the image list 134 ImageList_AddIcon(s_hTreeImageList, hIconSmall); 135 136 // increment the counter 137 nIconID = s_ViewTreeIconCount; 138 ++s_ViewTreeIconCount; 139 140 DestroyIcon(hIconSmall); 141 142 return nIconID; // newly-added icon ID 143 } 144 145 static PVIEWTREE_ENTRY 146 ViewTree_GetItem(DWORD dwID) 147 { 148 if (dwID == DWORD(-1)) 149 return NULL; 150 151 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 152 { 153 PVIEWTREE_ENTRY pEntry = &s_ViewTreeEntries[i]; 154 if (pEntry->dwID == dwID) 155 return pEntry; 156 } 157 return NULL; // failure 158 } 159 160 static INT 161 ViewTree_GetImage(PVIEWTREE_ENTRY pEntry) 162 { 163 switch (pEntry->dwType) 164 { 165 case AETYPE_GROUP: 166 return pEntry->nIconID; 167 168 case AETYPE_CHECKBOX: 169 if (pEntry->bGrayed) 170 { 171 if (pEntry->bChecked) 172 return I_CHECKED_DISABLED; 173 else 174 return I_UNCHECKED_DISABLED; 175 } 176 else 177 { 178 if (pEntry->bChecked) 179 return I_CHECKED; 180 else 181 return I_UNCHECKED; 182 } 183 184 case AETYPE_RADIO: 185 if (pEntry->bGrayed) 186 { 187 if (pEntry->bChecked) 188 return I_RADIO_CHECKED_DISABLED; 189 else 190 return I_RADIO_UNCHECKED_DISABLED; 191 } 192 else 193 { 194 if (pEntry->bChecked) 195 return I_RADIO_CHECKED; 196 else 197 return I_RADIO_UNCHECKED; 198 } 199 } 200 return -1; // failure 201 } 202 203 static VOID 204 ViewTree_InsertEntry(HWND hwndTreeView, PVIEWTREE_ENTRY pEntry) 205 { 206 PVIEWTREE_ENTRY pParent = ViewTree_GetItem(pEntry->dwParentID); 207 HTREEITEM hParent = TVI_ROOT; 208 if (pParent) 209 hParent = pParent->hItem; 210 211 TV_INSERTSTRUCT Insertion; 212 ZeroMemory(&Insertion, sizeof(Insertion)); 213 Insertion.hParent = hParent; 214 Insertion.hInsertAfter = TVI_LAST; 215 Insertion.item.mask = 216 TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; 217 Insertion.item.pszText = pEntry->szText; 218 219 INT iImage = ViewTree_GetImage(pEntry); 220 Insertion.item.iImage = Insertion.item.iSelectedImage = iImage; 221 Insertion.item.lParam = pEntry->dwID; 222 pEntry->hItem = TreeView_InsertItem(hwndTreeView, &Insertion); 223 } 224 225 static VOID 226 ViewTree_InsertAll(HWND hwndTreeView) 227 { 228 TreeView_DeleteAllItems(hwndTreeView); 229 230 // insert the entries 231 PVIEWTREE_ENTRY pEntry; 232 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 233 { 234 pEntry = &s_ViewTreeEntries[i]; 235 ViewTree_InsertEntry(hwndTreeView, pEntry); 236 } 237 238 // expand all 239 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 240 { 241 pEntry = &s_ViewTreeEntries[i]; 242 if (pEntry->dwType == AETYPE_GROUP) 243 { 244 TreeView_Expand(hwndTreeView, pEntry->hItem, TVE_EXPAND); 245 } 246 } 247 } 248 249 static BOOL 250 ViewTree_LoadTree(HKEY hKey, LPCWSTR pszKeyName, DWORD dwParentID) 251 { 252 DWORD dwIndex; 253 WCHAR szKeyName[64], szText[MAX_PATH], *pch; 254 DWORD Size, Value; 255 PVIEWTREE_ENTRY pAllocated; 256 257 // resize s_ViewTreeEntries 258 Size = (s_ViewTreeEntryCount + 1) * sizeof(VIEWTREE_ENTRY); 259 pAllocated = (PVIEWTREE_ENTRY)realloc(s_ViewTreeEntries, Size); 260 if (pAllocated == NULL) 261 return FALSE; // failure 262 else 263 s_ViewTreeEntries = pAllocated; 264 265 PVIEWTREE_ENTRY pEntry = &s_ViewTreeEntries[s_ViewTreeEntryCount]; 266 267 // dwID, dwParentID, szKeyName 268 pEntry->dwID = s_ViewTreeEntryCount; 269 pEntry->dwParentID = dwParentID; 270 lstrcpynW(pEntry->szKeyName, pszKeyName, _countof(pEntry->szKeyName)); 271 272 // Text, ResourceID 273 pEntry->szText[0] = 0; 274 pEntry->dwResourceID = 0; 275 szText[0] = 0; 276 Size = sizeof(szText); 277 RegQueryValueExW(hKey, L"Text", NULL, NULL, LPBYTE(szText), &Size); 278 if (szText[0] == L'@') 279 { 280 pch = wcsrchr(szText, L','); 281 if (pch) 282 { 283 *pch = 0; 284 dwIndex = abs(_wtoi(pch + 1)); 285 pEntry->dwResourceID = dwIndex; 286 } 287 HINSTANCE hInst = LoadLibraryW(&szText[1]); 288 LoadStringW(hInst, dwIndex, szText, _countof(szText)); 289 FreeLibrary(hInst); 290 } 291 else 292 { 293 pEntry->dwResourceID = DWORD(-1); 294 } 295 lstrcpynW(pEntry->szText, szText, _countof(pEntry->szText)); 296 297 // Type 298 szText[0] = 0; 299 RegQueryValueExW(hKey, L"Type", NULL, NULL, LPBYTE(szText), &Size); 300 if (lstrcmpiW(szText, L"checkbox") == 0) 301 pEntry->dwType = AETYPE_CHECKBOX; 302 else if (lstrcmpiW(szText, L"radio") == 0) 303 pEntry->dwType = AETYPE_RADIO; 304 else if (lstrcmpiW(szText, L"group") == 0) 305 pEntry->dwType = AETYPE_GROUP; 306 else 307 return FALSE; // failure 308 309 pEntry->nIconID = -1; 310 if (pEntry->dwType == AETYPE_GROUP) 311 { 312 // Bitmap (Icon) 313 UINT nIconIndex = 0; 314 Size = sizeof(szText); 315 szText[0] = 0; 316 RegQueryValueExW(hKey, L"Bitmap", NULL, NULL, LPBYTE(szText), &Size); 317 318 WCHAR szExpanded[MAX_PATH]; 319 ExpandEnvironmentStringsW(szText, szExpanded, _countof(szExpanded)); 320 pch = wcsrchr(szExpanded, L','); 321 if (pch) 322 { 323 *pch = 0; 324 nIconIndex = abs(_wtoi(pch + 1)); 325 } 326 pEntry->nIconID = ViewTree_AddIcon(szExpanded, nIconIndex); 327 } 328 329 if (pEntry->dwType == AETYPE_GROUP) 330 { 331 pEntry->hkeyRoot = NULL; 332 pEntry->szRegPath[0] = 0; 333 pEntry->szValueName[0] = 0; 334 pEntry->dwCheckedValue = 0; 335 pEntry->bHasUncheckedValue = FALSE; 336 pEntry->dwUncheckedValue = 0; 337 pEntry->dwDefaultValue = 0; 338 pEntry->hItem = NULL; 339 pEntry->bGrayed = FALSE; 340 pEntry->bChecked = FALSE; 341 } 342 else 343 { 344 // HKeyRoot 345 HKEY HKeyRoot = HKEY_CURRENT_USER; 346 Size = sizeof(HKeyRoot); 347 RegQueryValueExW(hKey, L"HKeyRoot", NULL, NULL, LPBYTE(&HKeyRoot), &Size); 348 pEntry->hkeyRoot = HKeyRoot; 349 350 // RegPath 351 pEntry->szRegPath[0] = 0; 352 Size = sizeof(szText); 353 RegQueryValueExW(hKey, L"RegPath", NULL, NULL, LPBYTE(szText), &Size); 354 lstrcpynW(pEntry->szRegPath, szText, _countof(pEntry->szRegPath)); 355 356 // ValueName 357 pEntry->szValueName[0] = 0; 358 Size = sizeof(szText); 359 RegQueryValueExW(hKey, L"ValueName", NULL, NULL, LPBYTE(szText), &Size); 360 lstrcpynW(pEntry->szValueName, szText, _countof(pEntry->szValueName)); 361 362 // CheckedValue 363 Size = sizeof(Value); 364 Value = 0x00000001; 365 RegQueryValueExW(hKey, L"CheckedValue", NULL, NULL, LPBYTE(&Value), &Size); 366 pEntry->dwCheckedValue = Value; 367 368 // UncheckedValue 369 Size = sizeof(Value); 370 Value = 0x00000000; 371 pEntry->bHasUncheckedValue = TRUE; 372 if (RegQueryValueExW(hKey, L"UncheckedValue", NULL, 373 NULL, LPBYTE(&Value), &Size) != ERROR_SUCCESS) 374 { 375 pEntry->bHasUncheckedValue = FALSE; 376 } 377 pEntry->dwUncheckedValue = Value; 378 379 // DefaultValue 380 Size = sizeof(Value); 381 Value = 0x00000001; 382 RegQueryValueExW(hKey, L"DefaultValue", NULL, NULL, LPBYTE(&Value), &Size); 383 pEntry->dwDefaultValue = Value; 384 385 // hItem 386 pEntry->hItem = NULL; 387 388 // bGrayed, bChecked 389 HKEY hkeyTarget; 390 Value = pEntry->dwDefaultValue; 391 pEntry->bGrayed = TRUE; 392 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0, 393 KEY_READ, &hkeyTarget) == ERROR_SUCCESS) 394 { 395 Size = sizeof(Value); 396 if (RegQueryValueExW(hkeyTarget, pEntry->szValueName, NULL, NULL, 397 LPBYTE(&Value), &Size) == ERROR_SUCCESS) 398 { 399 pEntry->bGrayed = FALSE; 400 } 401 RegCloseKey(hkeyTarget); 402 } 403 pEntry->bChecked = (Value == pEntry->dwCheckedValue); 404 } 405 406 // Grayed (ReactOS extension) 407 Size = sizeof(Value); 408 Value = FALSE; 409 RegQueryValueExW(hKey, L"Grayed", NULL, NULL, LPBYTE(&Value), &Size); 410 if (!pEntry->bGrayed) 411 pEntry->bGrayed = Value; 412 413 BOOL bIsGroup = (pEntry->dwType == AETYPE_GROUP); 414 dwParentID = pEntry->dwID; 415 ++s_ViewTreeEntryCount; 416 417 if (!bIsGroup) 418 return TRUE; // success 419 420 // load the children 421 dwIndex = 0; 422 while (RegEnumKeyW(hKey, dwIndex, szKeyName, 423 _countof(szKeyName)) == ERROR_SUCCESS) 424 { 425 HKEY hkeyChild; 426 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ, 427 &hkeyChild) != ERROR_SUCCESS) 428 { 429 ++dwIndex; 430 continue; // failure 431 } 432 433 ViewTree_LoadTree(hkeyChild, szKeyName, dwParentID); 434 RegCloseKey(hkeyChild); 435 436 ++dwIndex; 437 } 438 439 return TRUE; // success 440 } 441 442 static BOOL ViewTree_LoadAll(VOID) 443 { 444 static const WCHAR s_szAdvanced[] = 445 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"; 446 447 // free if already existed 448 if (s_ViewTreeEntries) 449 { 450 free(s_ViewTreeEntries); 451 s_ViewTreeEntries = NULL; 452 } 453 s_ViewTreeEntryCount = 0; 454 455 HKEY hKey; 456 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_szAdvanced, 0, 457 KEY_READ, &hKey) != ERROR_SUCCESS) 458 { 459 return FALSE; // failure 460 } 461 462 // load the children 463 WCHAR szKeyName[64]; 464 DWORD dwIndex = 0; 465 while (RegEnumKeyW(hKey, dwIndex, szKeyName, 466 _countof(szKeyName)) == ERROR_SUCCESS) 467 { 468 HKEY hkeyChild; 469 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ, 470 &hkeyChild) != ERROR_SUCCESS) 471 { 472 ++dwIndex; 473 continue; // failure 474 } 475 476 ViewTree_LoadTree(hkeyChild, szKeyName, DWORD(-1)); 477 RegCloseKey(hkeyChild); 478 479 ++dwIndex; 480 } 481 482 RegCloseKey(hKey); 483 484 return TRUE; // success 485 } 486 487 static int ViewTree_Compare(const void *x, const void *y) 488 { 489 PVIEWTREE_ENTRY pEntry1 = (PVIEWTREE_ENTRY)x; 490 PVIEWTREE_ENTRY pEntry2 = (PVIEWTREE_ENTRY)y; 491 492 DWORD dwParentID1 = pEntry1->dwParentID; 493 DWORD dwParentID2 = pEntry2->dwParentID; 494 495 if (dwParentID1 == dwParentID2) 496 return lstrcmpi(pEntry1->szText, pEntry2->szText); 497 498 DWORD i, m, n; 499 const UINT MAX_DEPTH = 32; 500 PVIEWTREE_ENTRY pArray1[MAX_DEPTH]; 501 PVIEWTREE_ENTRY pArray2[MAX_DEPTH]; 502 503 // Make ancestor lists 504 for (i = m = n = 0; i < MAX_DEPTH; ++i) 505 { 506 PVIEWTREE_ENTRY pParent1 = ViewTree_GetItem(dwParentID1); 507 PVIEWTREE_ENTRY pParent2 = ViewTree_GetItem(dwParentID2); 508 if (!pParent1 && !pParent2) 509 break; 510 511 if (pParent1) 512 { 513 pArray1[m++] = pParent1; 514 dwParentID1 = pParent1->dwParentID; 515 } 516 if (pParent2) 517 { 518 pArray2[n++] = pParent2; 519 dwParentID2 = pParent2->dwParentID; 520 } 521 } 522 523 UINT k = min(m, n); 524 for (i = 0; i < k; ++i) 525 { 526 INT nCompare = lstrcmpi(pArray1[m - i - 1]->szText, pArray2[n - i - 1]->szText); 527 if (nCompare < 0) 528 return -1; 529 if (nCompare > 0) 530 return 1; 531 } 532 533 if (m < n) 534 return -1; 535 if (m > n) 536 return 1; 537 return lstrcmpi(pEntry1->szText, pEntry2->szText); 538 } 539 540 static VOID 541 ViewTree_SortAll(VOID) 542 { 543 qsort(s_ViewTreeEntries, s_ViewTreeEntryCount, sizeof(VIEWTREE_ENTRY), ViewTree_Compare); 544 } 545 546 ///////////////////////////////////////////////////////////////////////////// 547 // ViewDlg 548 549 static HIMAGELIST 550 ViewDlg_CreateTreeImageList(VOID) 551 { 552 HIMAGELIST hImageList; 553 hImageList = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 9, 1); 554 if (hImageList == NULL) 555 return NULL; // failure 556 557 // free if existed 558 if (s_ViewTreeIcons) 559 { 560 free(s_ViewTreeIcons); 561 s_ViewTreeIcons = NULL; 562 } 563 s_ViewTreeIconCount = 0; 564 565 // allocate now 566 PVIEWTREE_ICON pAllocated; 567 size_t Size = PREDEFINED_ICON_COUNT * sizeof(VIEWTREE_ICON); 568 pAllocated = (PVIEWTREE_ICON)calloc(1, Size); 569 if (pAllocated == NULL) 570 return NULL; // failure 571 572 s_ViewTreeIconCount = PREDEFINED_ICON_COUNT; 573 s_ViewTreeIcons = pAllocated; 574 575 // add the predefined icons 576 577 HDC hDC = CreateCompatibleDC(NULL); 578 HBITMAP hbmMask = CreateCheckMask(hDC); 579 580 HBITMAP hbmChecked, hbmUnchecked; 581 582 hbmChecked = CreateCheckImage(hDC, TRUE); 583 ImageList_Add(hImageList, hbmChecked, hbmMask); 584 DeleteObject(hbmChecked); 585 586 hbmUnchecked = CreateCheckImage(hDC, FALSE); 587 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 588 DeleteObject(hbmUnchecked); 589 590 hbmChecked = CreateCheckImage(hDC, TRUE, FALSE); 591 ImageList_Add(hImageList, hbmChecked, hbmMask); 592 DeleteObject(hbmChecked); 593 594 hbmUnchecked = CreateCheckImage(hDC, FALSE, FALSE); 595 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 596 DeleteObject(hbmUnchecked); 597 598 DeleteObject(hbmMask); 599 hbmMask = CreateRadioMask(hDC); 600 601 hbmChecked = CreateRadioImage(hDC, TRUE); 602 ImageList_Add(hImageList, hbmChecked, hbmMask); 603 DeleteObject(hbmChecked); 604 605 hbmUnchecked = CreateRadioImage(hDC, FALSE); 606 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 607 DeleteObject(hbmUnchecked); 608 609 hbmChecked = CreateRadioImage(hDC, TRUE, FALSE); 610 ImageList_Add(hImageList, hbmChecked, hbmMask); 611 DeleteObject(hbmChecked); 612 613 hbmUnchecked = CreateRadioImage(hDC, FALSE, FALSE); 614 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 615 DeleteObject(hbmUnchecked); 616 617 DeleteObject(hbmMask); 618 619 return hImageList; 620 } 621 622 static BOOL 623 ViewDlg_OnInitDialog(HWND hwndDlg) 624 { 625 HWND hwndTreeView = GetDlgItem(hwndDlg, IDC_VIEW_TREEVIEW); 626 627 s_hTreeImageList = ViewDlg_CreateTreeImageList(); 628 TreeView_SetImageList(hwndTreeView, s_hTreeImageList, TVSIL_NORMAL); 629 630 ViewTree_LoadAll(); 631 ViewTree_SortAll(); 632 ViewTree_InsertAll(hwndTreeView); 633 634 return TRUE; // set focus 635 } 636 637 static BOOL 638 ViewDlg_ToggleCheckItem(HWND hwndDlg, HTREEITEM hItem) 639 { 640 HWND hwndTreeView = GetDlgItem(hwndDlg, IDC_VIEW_TREEVIEW); 641 642 // get the item 643 TV_ITEM Item; 644 INT i; 645 ZeroMemory(&Item, sizeof(Item)); 646 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM; 647 Item.hItem = hItem; 648 if (!TreeView_GetItem(hwndTreeView, &Item)) 649 return FALSE; // no such item 650 651 VIEWTREE_ENTRY *pEntry = ViewTree_GetItem(Item.lParam); 652 if (pEntry == NULL) 653 return FALSE; // no such item 654 if (pEntry->bGrayed) 655 return FALSE; // disabled 656 657 // toggle check mark 658 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; 659 switch (pEntry->dwType) 660 { 661 case AETYPE_CHECKBOX: 662 pEntry->bChecked = !pEntry->bChecked; 663 break; 664 665 case AETYPE_RADIO: 666 // reset all the entries of the same parent 667 for (i = 0; i < s_ViewTreeEntryCount; ++i) 668 { 669 VIEWTREE_ENTRY *pEntry2 = &s_ViewTreeEntries[i]; 670 if (pEntry->dwParentID == pEntry2->dwParentID) 671 { 672 pEntry2->bChecked = FALSE; 673 674 Item.hItem = pEntry2->hItem; 675 INT iImage = ViewTree_GetImage(pEntry2); 676 Item.iImage = Item.iSelectedImage = iImage; 677 TreeView_SetItem(hwndTreeView, &Item); 678 } 679 } 680 pEntry->bChecked = TRUE; 681 break; 682 683 default: 684 return FALSE; // failure 685 } 686 Item.iImage = Item.iSelectedImage = ViewTree_GetImage(pEntry); 687 Item.hItem = hItem; 688 TreeView_SetItem(hwndTreeView, &Item); 689 690 // redraw the item 691 RECT rcItem; 692 TreeView_GetItemRect(hwndTreeView, hItem, &rcItem, FALSE); 693 InvalidateRect(hwndTreeView, &rcItem, TRUE); 694 return TRUE; // success 695 } 696 697 static VOID 698 ViewDlg_OnTreeViewClick(HWND hwndDlg) 699 { 700 HWND hwndTreeView = GetDlgItem(hwndDlg, IDC_VIEW_TREEVIEW); 701 702 // do hit test to get the clicked item 703 TV_HITTESTINFO HitTest; 704 ZeroMemory(&HitTest, sizeof(HitTest)); 705 DWORD dwPos = GetMessagePos(); 706 HitTest.pt.x = LOWORD(dwPos); 707 HitTest.pt.y = HIWORD(dwPos); 708 ScreenToClient(hwndTreeView, &HitTest.pt); 709 HTREEITEM hItem = TreeView_HitTest(hwndTreeView, &HitTest); 710 711 // toggle the check mark if possible 712 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem)) 713 { 714 // property sheet was changed 715 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 716 } 717 } 718 719 static void 720 ViewDlg_OnTreeViewKeyDown(HWND hwndDlg, TV_KEYDOWN *KeyDown) 721 { 722 HWND hwndTreeView = GetDlgItem(hwndDlg, IDC_VIEW_TREEVIEW); 723 724 if (KeyDown->wVKey == VK_SPACE) 725 { 726 // [Space] key was pressed 727 HTREEITEM hItem = TreeView_GetSelection(hwndTreeView); 728 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem)) 729 { 730 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 731 } 732 } 733 } 734 735 static INT_PTR 736 ViewDlg_OnTreeCustomDraw(HWND hwndDlg, NMTVCUSTOMDRAW *Draw) 737 { 738 NMCUSTOMDRAW& nmcd = Draw->nmcd; 739 switch (nmcd.dwDrawStage) 740 { 741 case CDDS_PREPAINT: 742 return CDRF_NOTIFYITEMDRAW; // for CDDS_ITEMPREPAINT 743 744 case CDDS_ITEMPREPAINT: 745 if (!(nmcd.uItemState & CDIS_SELECTED)) // not selected 746 { 747 LPARAM lParam = nmcd.lItemlParam; 748 VIEWTREE_ENTRY *pEntry = ViewTree_GetItem(lParam); 749 if (pEntry && pEntry->bGrayed) // disabled 750 { 751 // draw as grayed 752 Draw->clrText = GetSysColor(COLOR_GRAYTEXT); 753 Draw->clrTextBk = GetSysColor(COLOR_WINDOW); 754 return CDRF_NEWFONT; 755 } 756 } 757 break; 758 759 default: 760 break; 761 } 762 return CDRF_DODEFAULT; 763 } 764 765 static VOID 766 ViewDlg_RestoreDefaults(HWND hwndDlg) 767 { 768 HWND hwndTreeView = GetDlgItem(hwndDlg, IDC_VIEW_TREEVIEW); 769 770 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 771 { 772 // ignore if the type is group 773 VIEWTREE_ENTRY *pEntry = &s_ViewTreeEntries[i]; 774 if (pEntry->dwType == AETYPE_GROUP) 775 continue; 776 777 // set default value on registry 778 HKEY hKey; 779 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 780 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) 781 { 782 continue; 783 } 784 RegSetValueExW(hKey, pEntry->szValueName, 0, REG_DWORD, 785 LPBYTE(&pEntry->dwDefaultValue), sizeof(DWORD)); 786 RegCloseKey(hKey); 787 788 // update check status 789 pEntry->bChecked = (pEntry->dwCheckedValue == pEntry->dwDefaultValue); 790 791 // update the image 792 TV_ITEM Item; 793 ZeroMemory(&Item, sizeof(Item)); 794 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; 795 Item.hItem = pEntry->hItem; 796 Item.iImage = Item.iSelectedImage = ViewTree_GetImage(pEntry); 797 TreeView_SetItem(hwndTreeView, &Item); 798 } 799 800 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 801 } 802 803 static VOID 804 ScanAdvancedSettings(SHELLSTATE *pSS, DWORD *pdwMask) 805 { 806 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 807 { 808 const VIEWTREE_ENTRY *pEntry = &s_ViewTreeEntries[i]; 809 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed) 810 continue; 811 812 BOOL bChecked = pEntry->bChecked; 813 814 // FIXME: Add more items 815 if (lstrcmpiW(pEntry->szKeyName, L"SuperHidden") == 0) 816 { 817 pSS->fShowSuperHidden = !bChecked ? 1 : 0; 818 *pdwMask |= SSF_SHOWSUPERHIDDEN; 819 continue; 820 } 821 if (lstrcmpiW(pEntry->szKeyName, L"DesktopProcess") == 0) 822 { 823 pSS->fSepProcess = bChecked ? 1 : 0; 824 *pdwMask |= SSF_SEPPROCESS; 825 continue; 826 } 827 if (lstrcmpiW(pEntry->szKeyName, L"SHOWALL") == 0) 828 { 829 pSS->fShowAllObjects = !bChecked ? 1 : 0; 830 *pdwMask |= SSF_SHOWALLOBJECTS; 831 continue; 832 } 833 if (lstrcmpiW(pEntry->szKeyName, L"HideFileExt") == 0) 834 { 835 pSS->fShowExtensions = !bChecked ? 1 : 0; 836 *pdwMask |= SSF_SHOWEXTENSIONS; 837 continue; 838 } 839 if (lstrcmpiW(pEntry->szKeyName, L"ShowCompColor") == 0) 840 { 841 pSS->fShowCompColor = bChecked ? 1 : 0; 842 *pdwMask |= SSF_SHOWCOMPCOLOR; 843 continue; 844 } 845 if (lstrcmpiW(pEntry->szKeyName, L"ShowInfoTip") == 0) 846 { 847 pSS->fShowInfoTip = bChecked ? 1 : 0; 848 *pdwMask |= SSF_SHOWINFOTIP; 849 continue; 850 } 851 } 852 } 853 854 static BOOL CALLBACK 855 RefreshBrowsersCallback(HWND hWnd, LPARAM msg) 856 { 857 WCHAR ClassName[100]; 858 if (GetClassNameW(hWnd, ClassName, _countof(ClassName))) 859 { 860 if (!wcscmp(ClassName, L"Progman") || 861 !wcscmp(ClassName, L"CabinetWClass") || 862 !wcscmp(ClassName, L"ExploreWClass")) 863 { 864 PostMessage(hWnd, WM_COMMAND, FCIDM_DESKBROWSER_REFRESH, 0); 865 } 866 } 867 return TRUE; 868 } 869 870 static VOID 871 ViewDlg_Apply(HWND hwndDlg) 872 { 873 for (INT i = 0; i < s_ViewTreeEntryCount; ++i) 874 { 875 // ignore the entry if the type is group or the entry is grayed 876 VIEWTREE_ENTRY *pEntry = &s_ViewTreeEntries[i]; 877 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed) 878 continue; 879 880 // open the registry key 881 HKEY hkeyTarget; 882 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0, 883 KEY_WRITE, &hkeyTarget) != ERROR_SUCCESS) 884 { 885 continue; 886 } 887 888 // checked or unchecked? 889 DWORD dwValue, dwSize; 890 if (pEntry->bChecked) 891 { 892 dwValue = pEntry->dwCheckedValue; 893 } 894 else 895 { 896 if (pEntry->bHasUncheckedValue) 897 { 898 dwValue = pEntry->dwUncheckedValue; 899 } 900 else 901 { 902 // there is no unchecked value 903 RegCloseKey(hkeyTarget); 904 continue; // ignore 905 } 906 } 907 908 // set the value 909 dwSize = sizeof(dwValue); 910 RegSetValueExW(hkeyTarget, pEntry->szValueName, 0, REG_DWORD, 911 LPBYTE(&dwValue), dwSize); 912 913 // close now 914 RegCloseKey(hkeyTarget); 915 } 916 917 // scan advanced settings for user's settings 918 DWORD dwMask = 0; 919 SHELLSTATE ShellState; 920 ZeroMemory(&ShellState, sizeof(ShellState)); 921 ScanAdvancedSettings(&ShellState, &dwMask); 922 923 // update user's settings 924 SHGetSetSettings(&ShellState, dwMask, TRUE); 925 926 // notify all 927 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0); 928 929 EnumWindows(RefreshBrowsersCallback, NULL); 930 } 931 932 // IDD_FOLDER_OPTIONS_VIEW 933 INT_PTR CALLBACK 934 FolderOptionsViewDlg( 935 HWND hwndDlg, 936 UINT uMsg, 937 WPARAM wParam, 938 LPARAM lParam) 939 { 940 INT_PTR Result; 941 NMTVCUSTOMDRAW *Draw; 942 943 switch (uMsg) 944 { 945 case WM_INITDIALOG: 946 return ViewDlg_OnInitDialog(hwndDlg); 947 948 case WM_COMMAND: 949 switch (LOWORD(wParam)) 950 { 951 case IDC_VIEW_RESTORE_DEFAULTS: // Restore Defaults 952 ViewDlg_RestoreDefaults(hwndDlg); 953 break; 954 } 955 break; 956 957 case WM_NOTIFY: 958 switch (LPNMHDR(lParam)->code) 959 { 960 case NM_CLICK: // clicked on treeview 961 ViewDlg_OnTreeViewClick(hwndDlg); 962 break; 963 964 case NM_CUSTOMDRAW: // custom draw (for graying) 965 Draw = (NMTVCUSTOMDRAW *)lParam; 966 Result = ViewDlg_OnTreeCustomDraw(hwndDlg, Draw); 967 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, Result); 968 return Result; 969 970 case TVN_KEYDOWN: // key is down 971 ViewDlg_OnTreeViewKeyDown(hwndDlg, (TV_KEYDOWN *)lParam); 972 break; 973 974 case PSN_APPLY: // [Apply] is clicked 975 ViewDlg_Apply(hwndDlg); 976 break; 977 978 default: 979 break; 980 } 981 break; 982 } 983 984 return FALSE; 985 } 986