4 * Copyright 1998 Francis Beaudet
5 * Copyright 1999 Thuy Nguyen
9 * - Unicode property sheets
18 #include "debugtools.h"
22 /******************************************************************************
34 typedef struct tagPropPageInfo
36 HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
45 typedef struct tagPropSheetInfo
48 PROPSHEETHEADERA ppshheader;
49 LPSTR strPropertiesFor;
59 PropPageInfo* proppage;
64 HIMAGELIST hImageList;
73 /******************************************************************************
74 * Defines and global variables
77 const char * PropSheetInfoStr = "PropertySheetInfo";
79 #define MAX_CAPTION_LENGTH 255
80 #define MAX_TABTEXT_LENGTH 255
81 #define MAX_BUTTONTEXT_LENGTH 64
83 /******************************************************************************
86 static BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo);
87 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo);
88 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);
89 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);
90 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
91 PropSheetInfo * psInfo);
92 static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
93 PropSheetInfo * psInfo,
95 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
96 PropSheetInfo * psInfo);
97 static BOOL PROPSHEET_CreatePage(HWND hwndParent, int index,
98 const PropSheetInfo * psInfo,
99 LPCPROPSHEETPAGEA ppshpage);
100 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);
101 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
102 static BOOL PROPSHEET_Back(HWND hwndDlg);
103 static BOOL PROPSHEET_Next(HWND hwndDlg);
104 static BOOL PROPSHEET_Finish(HWND hwndDlg);
105 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam);
106 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam);
107 static void PROPSHEET_Help(HWND hwndDlg);
108 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
109 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
110 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
111 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText);
112 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
113 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
114 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
117 HPROPSHEETPAGE hpage);
118 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
119 WPARAM wParam, LPARAM lParam);
120 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
121 HPROPSHEETPAGE hpage);
123 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
125 HPROPSHEETPAGE hpage);
126 static void PROPSHEET_CleanUp();
127 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
128 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags);
129 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo);
130 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg);
133 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
135 DEFAULT_DEBUG_CHANNEL(propsheet);
137 /******************************************************************************
138 * PROPSHEET_CollectSheetInfo
140 * Collect relevant data.
142 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
143 PropSheetInfo * psInfo)
145 DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA));
146 DWORD dwFlags = lppsh->dwFlags;
148 psInfo->hasHelp = dwFlags & PSH_HASHELP;
149 psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
150 psInfo->useCallback = dwFlags & PSH_USECALLBACK;
151 psInfo->isModeless = dwFlags & PSH_MODELESS;
153 memcpy(&psInfo->ppshheader,lppsh,dwSize);
155 if (HIWORD(lppsh->pszCaption))
156 psInfo->ppshheader.pszCaption = HEAP_strdupA( GetProcessHeap(),
157 0, lppsh->pszCaption );
159 psInfo->nPages = lppsh->nPages;
161 if (dwFlags & PSH_USEPSTARTPAGE)
163 TRACE("PSH_USEPSTARTPAGE is on");
164 psInfo->active_page = 0;
167 psInfo->active_page = lppsh->u2.nStartPage;
169 if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
170 psInfo->active_page = 0;
172 psInfo->restartWindows = FALSE;
173 psInfo->rebootSystem = FALSE;
174 psInfo->hImageList = 0;
175 psInfo->activeValid = FALSE;
180 /******************************************************************************
181 * PROPSHEET_CollectPageInfo
183 * Collect property sheet data.
184 * With code taken from DIALOG_ParseTemplate32.
186 BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
187 PropSheetInfo * psInfo,
190 DLGTEMPLATE* pTemplate;
195 psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
196 psInfo->proppage[index].hwndPage = 0;
197 psInfo->proppage[index].isDirty = FALSE;
200 * Process property page flags.
202 dwFlags = lppsp->dwFlags;
203 psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback);
204 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
205 psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
207 /* as soon as we have a page with the help flag, set the sheet flag on */
208 if (psInfo->proppage[index].hasHelp)
209 psInfo->hasHelp = TRUE;
212 * Process page template.
214 if (dwFlags & PSP_DLGINDIRECT)
215 pTemplate = (DLGTEMPLATE*)lppsp->u.pResource;
218 HRSRC hResource = FindResourceA(lppsp->hInstance,
219 lppsp->u.pszTemplate,
221 HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
223 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
227 * Extract the size of the page and the caption.
232 p = (const WORD *)pTemplate;
234 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
236 /* DIALOGEX template */
240 p += 2; /* help ID */
241 p += 2; /* ext style */
246 /* DIALOG template */
249 p += 2; /* ext style */
255 width = (WORD)*p; p++;
256 height = (WORD)*p; p++;
258 /* remember the largest width and height */
259 if (width > psInfo->width)
260 psInfo->width = width;
262 if (height > psInfo->height)
263 psInfo->height = height;
275 p += lstrlenW( (LPCWSTR)p ) + 1;
289 p += lstrlenW( (LPCWSTR)p ) + 1;
293 /* Extract the caption */
294 psInfo->proppage[index].pszText = (LPCWSTR)p;
295 TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
296 p += lstrlenW((LPCWSTR)p) + 1;
298 if (dwFlags & PSP_USETITLE)
300 if ( !HIWORD( lppsp->pszTitle ) )
304 if ( !LoadStringA( lppsp->hInstance, (UINT) lppsp->pszTitle, szTitle, 256 ) )
307 psInfo->proppage[index].pszText = HEAP_strdupAtoW( GetProcessHeap(),
311 psInfo->proppage[index].pszText = HEAP_strdupAtoW(GetProcessHeap(),
317 * Build the image list for icons
319 if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
322 int icon_cx = GetSystemMetrics(SM_CXSMICON);
323 int icon_cy = GetSystemMetrics(SM_CYSMICON);
325 if (dwFlags & PSP_USEICONID)
326 hIcon = LoadImageA(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
327 icon_cx, icon_cy, LR_DEFAULTCOLOR);
329 hIcon = lppsp->u2.hIcon;
333 if (psInfo->hImageList == 0 )
334 psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
336 ImageList_AddIcon(psInfo->hImageList, hIcon);
345 /******************************************************************************
346 * PROPSHEET_CreateDialog
348 * Creates the actual property sheet.
350 BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
357 WORD resID = IDD_PROPSHEET;
359 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
362 if(!(hRes = FindResourceA(COMCTL32_hModule,
363 MAKEINTRESOURCEA(resID),
367 if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
371 * Make a copy of the dialog template.
373 resSize = SizeofResource(COMCTL32_hModule, hRes);
375 temp = COMCTL32_Alloc(resSize);
380 memcpy(temp, template, resSize);
382 if (psInfo->useCallback)
383 (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
385 if (!(psInfo->ppshheader.dwFlags & PSH_MODELESS))
386 ret = DialogBoxIndirectParamA(psInfo->ppshheader.hInstance,
387 (LPDLGTEMPLATEA) temp,
388 psInfo->ppshheader.hwndParent,
389 (DLGPROC) PROPSHEET_DialogProc,
392 ret = CreateDialogIndirectParamA(psInfo->ppshheader.hInstance,
393 (LPDLGTEMPLATEA) temp,
394 psInfo->ppshheader.hwndParent,
395 (DLGPROC) PROPSHEET_DialogProc,
403 /******************************************************************************
404 * PROPSHEET_SizeMismatch
406 * Verify that the tab control and the "largest" property sheet page dlg. template
409 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)
411 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
412 RECT rcOrigTab, rcPage;
417 GetClientRect(hwndTabCtrl, &rcOrigTab);
418 TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
419 rcOrigTab.right, rcOrigTab.bottom);
424 rcPage.left = psInfo->x;
425 rcPage.top = psInfo->y;
426 rcPage.right = psInfo->width;
427 rcPage.bottom = psInfo->height;
429 MapDialogRect(hwndDlg, &rcPage);
430 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
431 rcPage.right, rcPage.bottom);
433 if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
435 if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
441 /******************************************************************************
442 * PROPSHEET_IsTooSmallWizard
444 * Verify that the default property sheet is big enough.
446 static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
448 RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
449 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
450 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg, psInfo);
452 GetClientRect(hwndDlg, &rcSheetClient);
453 GetWindowRect(hwndDlg, &rcSheetRect);
454 GetWindowRect(hwndLine, &rcLine);
456 /* Remove the space below the sunken line */
457 rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
459 /* Remove the buffer zone all around the edge */
460 rcSheetClient.bottom -= (padding.y * 2);
461 rcSheetClient.right -= (padding.x * 2);
466 rcPage.left = psInfo->x;
467 rcPage.top = psInfo->y;
468 rcPage.right = psInfo->width;
469 rcPage.bottom = psInfo->height;
471 MapDialogRect(hwndDlg, &rcPage);
472 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
473 rcPage.right, rcPage.bottom);
475 if (rcPage.right > rcSheetClient.right)
478 if (rcPage.bottom > rcSheetClient.bottom)
484 /******************************************************************************
485 * PROPSHEET_AdjustSize
487 * Resizes the property sheet and the tab control to fit the largest page.
489 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
491 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
492 HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
494 int tabOffsetX, tabOffsetY, buttonHeight;
495 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
498 /* Get the height of buttons */
499 GetClientRect(hwndButton, &rc);
500 buttonHeight = rc.bottom;
507 rc.right = psInfo->width;
508 rc.bottom = psInfo->height;
510 MapDialogRect(hwndDlg, &rc);
512 /* retrieve the dialog units */
513 units.left = units.right = 4;
514 units.top = units.bottom = 8;
515 MapDialogRect(hwndDlg, &units);
518 * Resize the tab control.
520 GetClientRect(hwndTabCtrl,&tabRect);
522 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);
524 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
526 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
527 psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top);
530 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
532 rc.right = rc.left + tabRect.right - tabRect.left;
533 psInfo->width = MulDiv((rc.right - rc.left),4,units.left);
536 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
538 tabOffsetX = -(rc.left);
539 tabOffsetY = -(rc.top);
543 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
544 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
546 GetClientRect(hwndTabCtrl, &rc);
548 TRACE("tab client rc %d %d %d %d\n",
549 rc.left, rc.top, rc.right, rc.bottom);
551 rc.right += ((padding.x * 2) + tabOffsetX);
552 rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
555 * Resize the property sheet.
557 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
558 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
562 /******************************************************************************
563 * PROPSHEET_AdjustSizeWizard
565 * Resizes the property sheet to fit the largest page.
567 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
569 HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
570 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
571 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
573 int buttonHeight, lineHeight;
574 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg, psInfo);
577 /* Get the height of buttons */
578 GetClientRect(hwndButton, &rc);
579 buttonHeight = rc.bottom;
581 GetClientRect(hwndLine, &rc);
582 lineHeight = rc.bottom;
584 /* retrieve the dialog units */
585 units.left = units.right = 4;
586 units.top = units.bottom = 8;
587 MapDialogRect(hwndDlg, &units);
594 rc.right = psInfo->width;
595 rc.bottom = psInfo->height;
597 MapDialogRect(hwndDlg, &rc);
599 GetClientRect(hwndTabCtrl,&tabRect);
601 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
603 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
604 psInfo->height = MulDiv((rc.bottom - rc.top), 8, units.top);
607 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
609 rc.right = rc.left + tabRect.right - tabRect.left;
610 psInfo->width = MulDiv((rc.right - rc.left), 4, units.left);
613 TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
616 rc.right += (padding.x * 2);
617 rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
620 * Resize the property sheet.
622 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
623 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
627 /******************************************************************************
628 * PROPSHEET_AdjustButtons
630 * Adjusts the buttons' positions.
632 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
634 HWND hwndButton = GetDlgItem(hwndParent, IDOK);
638 int buttonWidth, buttonHeight;
639 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
641 if (psInfo->hasApply)
648 * Obtain the size of the buttons.
650 GetClientRect(hwndButton, &rcSheet);
651 buttonWidth = rcSheet.right;
652 buttonHeight = rcSheet.bottom;
655 * Get the size of the property sheet.
657 GetClientRect(hwndParent, &rcSheet);
660 * All buttons will be at this y coordinate.
662 y = rcSheet.bottom - (padding.y + buttonHeight);
665 * Position OK button.
667 hwndButton = GetDlgItem(hwndParent, IDOK);
669 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
671 SetWindowPos(hwndButton, 0, x, y, 0, 0,
672 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
675 * Position Cancel button.
677 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
679 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
681 SetWindowPos(hwndButton, 0, x, y, 0, 0,
682 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
685 * Position Apply button.
687 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
689 if (psInfo->hasApply)
692 x = rcSheet.right - ((padding.x + buttonWidth) * 2);
694 x = rcSheet.right - (padding.x + buttonWidth);
696 SetWindowPos(hwndButton, 0, x, y, 0, 0,
697 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
699 EnableWindow(hwndButton, FALSE);
702 ShowWindow(hwndButton, SW_HIDE);
705 * Position Help button.
707 hwndButton = GetDlgItem(hwndParent, IDHELP);
711 x = rcSheet.right - (padding.x + buttonWidth);
713 SetWindowPos(hwndButton, 0, x, y, 0, 0,
714 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
717 ShowWindow(hwndButton, SW_HIDE);
722 /******************************************************************************
723 * PROPSHEET_AdjustButtonsWizard
725 * Adjusts the buttons' positions.
727 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
728 PropSheetInfo* psInfo)
730 HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
731 HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
735 int buttonWidth, buttonHeight, lineHeight, lineWidth;
736 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
742 * Obtain the size of the buttons.
744 GetClientRect(hwndButton, &rcSheet);
745 buttonWidth = rcSheet.right;
746 buttonHeight = rcSheet.bottom;
748 GetClientRect(hwndLine, &rcSheet);
749 lineHeight = rcSheet.bottom;
752 * Get the size of the property sheet.
754 GetClientRect(hwndParent, &rcSheet);
757 * All buttons will be at this y coordinate.
759 y = rcSheet.bottom - (padding.y + buttonHeight);
762 * Position the Next and the Finish buttons.
764 hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
766 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
768 SetWindowPos(hwndButton, 0, x, y, 0, 0,
769 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
771 hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
773 SetWindowPos(hwndButton, 0, x, y, 0, 0,
774 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
776 ShowWindow(hwndButton, SW_HIDE);
779 * Position the Back button.
781 hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
785 SetWindowPos(hwndButton, 0, x, y, 0, 0,
786 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
789 * Position the Cancel button.
791 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
793 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
795 SetWindowPos(hwndButton, 0, x, y, 0, 0,
796 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
799 * Position Help button.
801 hwndButton = GetDlgItem(hwndParent, IDHELP);
805 x = rcSheet.right - (padding.x + buttonWidth);
807 SetWindowPos(hwndButton, 0, x, y, 0, 0,
808 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
811 ShowWindow(hwndButton, SW_HIDE);
814 * Position and resize the sunken line.
817 y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
819 GetClientRect(hwndParent, &rcSheet);
820 lineWidth = rcSheet.right - (padding.x * 2);
822 SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
823 SWP_NOZORDER | SWP_NOACTIVATE);
828 /******************************************************************************
829 * PROPSHEET_GetPaddingInfo
831 * Returns the layout information.
833 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
835 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
838 PADDING_INFO padding;
840 GetWindowRect(hwndTab, &rcTab);
845 ScreenToClient(hwndDlg, &tl);
853 /******************************************************************************
854 * PROPSHEET_GetPaddingInfoWizard
856 * Returns the layout information.
857 * Vertical spacing is the distance between the line and the buttons.
858 * Do NOT use the Help button to gather padding information when it isn't mapped
859 * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates
860 * for it in this case !
861 * FIXME: I'm not sure about any other coordinate problems with these evil
862 * buttons. Fix it in case additional problems appear or maybe calculate
863 * a padding in a completely different way, as this is somewhat messy.
865 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo*
868 PADDING_INFO padding;
872 POINT ptButton, ptLine;
880 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
882 idButton = IDC_NEXT_BUTTON;
886 /* hopefully this is ok */
891 hwndControl = GetDlgItem(hwndDlg, idButton);
892 GetWindowRect(hwndControl, &rc);
894 ptButton.x = rc.left;
897 ScreenToClient(hwndDlg, &ptButton);
900 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
901 GetWindowRect(hwndControl, &rc);
904 ptLine.y = rc.bottom;
906 ScreenToClient(hwndDlg, &ptLine);
908 padding.y = ptButton.y - ptLine.y;
911 ERR("padding negative ! Please report this !\n");
913 /* this is most probably not correct, but the best we have now */
914 padding.x = padding.y;
918 /******************************************************************************
919 * PROPSHEET_CreateTabControl
921 * Insert the tabs in the tab control.
923 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
924 PropSheetInfo * psInfo)
926 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
930 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
932 item.mask = TCIF_TEXT;
933 item.pszText = tabtext;
934 item.cchTextMax = MAX_TABTEXT_LENGTH;
936 nTabs = psInfo->nPages;
939 * Set the image list for icons.
941 if (psInfo->hImageList)
943 SendMessageA(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
946 for (i = 0; i < nTabs; i++)
948 if ( psInfo->proppage[i].hasIcon )
950 item.mask |= TCIF_IMAGE;
951 item.iImage = iImage++;
955 item.mask &= ~TCIF_IMAGE;
958 WideCharToMultiByte(CP_ACP, 0,
959 (LPCWSTR)psInfo->proppage[i].pszText,
960 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
962 SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
968 /******************************************************************************
969 * PROPSHEET_CreatePage
973 static BOOL PROPSHEET_CreatePage(HWND hwndParent,
975 const PropSheetInfo * psInfo,
976 LPCPROPSHEETPAGEA ppshpage)
978 DLGTEMPLATE* pTemplate;
981 PropPageInfo* ppInfo = psInfo->proppage;
982 PADDING_INFO padding;
983 UINT pageWidth,pageHeight;
987 TRACE("index %d\n", index);
989 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
990 pTemplate = (DLGTEMPLATE*)ppshpage->u.pResource;
996 hResource = FindResourceA(ppshpage->hInstance,
997 ppshpage->u.pszTemplate,
1002 resSize = SizeofResource(ppshpage->hInstance, hResource);
1004 hTemplate = LoadResource(ppshpage->hInstance, hResource);
1008 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
1010 * Make a copy of the dialog template to make it writable
1012 temp = COMCTL32_Alloc(resSize);
1016 memcpy(temp, pTemplate, resSize);
1020 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
1022 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;
1023 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
1024 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
1025 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
1026 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
1027 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
1028 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
1032 pTemplate->style |= WS_CHILD | DS_CONTROL;
1033 pTemplate->style &= ~DS_MODALFRAME;
1034 pTemplate->style &= ~WS_CAPTION;
1035 pTemplate->style &= ~WS_SYSMENU;
1036 pTemplate->style &= ~WS_POPUP;
1037 pTemplate->style &= ~WS_DISABLED;
1038 pTemplate->style &= ~WS_VISIBLE;
1041 if (psInfo->proppage[index].useCallback)
1042 (*(ppshpage->pfnCallback))(hwndParent,
1044 (LPPROPSHEETPAGEA)ppshpage);
1046 hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
1049 ppshpage->pfnDlgProc,
1051 /* Free a no more needed copy */
1053 COMCTL32_Free(temp);
1055 ppInfo[index].hwndPage = hwndPage;
1057 rc.left = psInfo->x;
1059 rc.right = psInfo->width;
1060 rc.bottom = psInfo->height;
1062 MapDialogRect(hwndParent, &rc);
1064 pageWidth = rc.right - rc.left;
1065 pageHeight = rc.bottom - rc.top;
1067 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
1068 padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
1072 * Ask the Tab control to fit this page in.
1075 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1076 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
1077 padding = PROPSHEET_GetPaddingInfo(hwndParent);
1080 SetWindowPos(hwndPage, HWND_TOP,
1081 rc.left + padding.x,
1083 pageWidth, pageHeight, 0);
1088 /******************************************************************************
1089 * PROPSHEET_ShowPage
1091 * Displays or creates the specified page.
1093 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1095 if (index == psInfo->active_page)
1097 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1098 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1102 if (psInfo->proppage[index].hwndPage == 0)
1104 LPCPROPSHEETPAGEA ppshpage;
1106 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1107 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1110 if (psInfo->active_page != -1)
1111 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1113 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1115 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
1119 /* Synchronize current selection with tab control */
1120 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1121 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1124 psInfo->active_page = index;
1125 psInfo->activeValid = TRUE;
1130 /******************************************************************************
1133 static BOOL PROPSHEET_Back(HWND hwndDlg)
1138 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1142 if (psInfo->active_page < 0)
1145 psn.hdr.code = PSN_WIZBACK;
1146 psn.hdr.hwndFrom = hwndDlg;
1150 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1152 result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1156 if (psInfo->active_page > 0)
1158 res = PROPSHEET_CanSetCurSel(hwndDlg);
1161 res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, -1, 0);
1168 /******************************************************************************
1171 static BOOL PROPSHEET_Next(HWND hwndDlg)
1175 LRESULT msgResult = 0;
1176 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1179 if (psInfo->active_page < 0)
1182 psn.hdr.code = PSN_WIZNEXT;
1183 psn.hdr.hwndFrom = hwndDlg;
1187 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1189 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1190 if (msgResult == -1)
1193 if(PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1195 PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 1, 0);
1201 /******************************************************************************
1204 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1208 LRESULT msgResult = 0;
1209 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1212 if (psInfo->active_page < 0)
1215 psn.hdr.code = PSN_WIZFINISH;
1216 psn.hdr.hwndFrom = hwndDlg;
1220 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1222 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1224 TRACE("msg result %ld\n", msgResult);
1229 if (psInfo->isModeless)
1230 psInfo->activeValid = FALSE;
1232 EndDialog(hwndDlg, TRUE);
1237 /******************************************************************************
1240 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1246 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1249 if (psInfo->active_page < 0)
1252 psn.hdr.hwndFrom = hwndDlg;
1258 * Send PSN_KILLACTIVE to the current page.
1260 psn.hdr.code = PSN_KILLACTIVE;
1262 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1264 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1268 * Send PSN_APPLY to all pages.
1270 psn.hdr.code = PSN_APPLY;
1271 psn.lParam = lParam;
1273 for (i = 0; i < psInfo->nPages; i++)
1275 hwndPage = psInfo->proppage[i].hwndPage;
1278 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1279 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1286 psInfo->activeValid = FALSE;
1288 else if(psInfo->active_page >= 0)
1290 psn.hdr.code = PSN_SETACTIVE;
1292 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1293 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1299 /******************************************************************************
1302 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1304 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1310 if (psInfo->active_page < 0)
1313 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1314 psn.hdr.code = PSN_QUERYCANCEL;
1315 psn.hdr.hwndFrom = hwndDlg;
1319 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1322 psn.hdr.code = PSN_RESET;
1323 psn.lParam = lParam;
1325 for (i = 0; i < psInfo->nPages; i++)
1327 hwndPage = psInfo->proppage[i].hwndPage;
1330 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1333 if (psInfo->isModeless)
1335 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1336 psInfo->activeValid = FALSE;
1339 EndDialog(hwndDlg, FALSE);
1342 /******************************************************************************
1345 static void PROPSHEET_Help(HWND hwndDlg)
1347 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1352 if (psInfo->active_page < 0)
1355 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1356 psn.hdr.code = PSN_HELP;
1357 psn.hdr.hwndFrom = hwndDlg;
1361 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1364 /******************************************************************************
1367 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1370 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1373 if (!psInfo) return;
1375 * Set the dirty flag of this page.
1377 for (i = 0; i < psInfo->nPages; i++)
1379 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1380 psInfo->proppage[i].isDirty = TRUE;
1384 * Enable the Apply button.
1386 if (psInfo->hasApply)
1388 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1390 EnableWindow(hwndApplyBtn, TRUE);
1394 /******************************************************************************
1395 * PROPSHEET_UnChanged
1397 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1400 BOOL noPageDirty = TRUE;
1401 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1402 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1405 if ( !psInfo ) return;
1406 for (i = 0; i < psInfo->nPages; i++)
1408 /* set the specified page as clean */
1409 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1410 psInfo->proppage[i].isDirty = FALSE;
1412 /* look to see if there's any dirty pages */
1413 if (psInfo->proppage[i].isDirty)
1414 noPageDirty = FALSE;
1418 * Disable Apply button.
1421 EnableWindow(hwndApplyBtn, FALSE);
1424 /******************************************************************************
1425 * PROPSHEET_PressButton
1427 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1431 case PSBTN_APPLYNOW:
1432 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
1435 PROPSHEET_Back(hwndDlg);
1438 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
1441 PROPSHEET_Finish(hwndDlg);
1444 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
1447 PROPSHEET_Next(hwndDlg);
1450 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
1453 FIXME("Invalid button index %d\n", buttonID);
1458 /*************************************************************************
1459 * BOOL PROPSHEET_CanSetCurSel [Internal]
1461 * Test whether the current page can be changed by sending a PSN_KILLACTIVE
1464 * hwndDlg [I] handle to a Dialog hWnd
1467 * TRUE if Current Selection can change
1471 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1473 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1481 if (psInfo->active_page < 0)
1485 * Notify the current page.
1487 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1488 psn.hdr.code = PSN_KILLACTIVE;
1489 psn.hdr.hwndFrom = hwndDlg;
1493 return !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1496 /******************************************************************************
1497 * PROPSHEET_SetCurSel
1499 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1502 HPROPSHEETPAGE hpage
1505 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1506 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1508 /* hpage takes precedence over index */
1510 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1512 if (index < 0 || index >= psInfo->nPages)
1514 TRACE("Could not find page to select!\n");
1522 psn.hdr.code = PSN_SETACTIVE;
1523 psn.hdr.hwndFrom = hwndDlg;
1527 if (!psInfo->proppage[index].hwndPage) {
1528 LPCPROPSHEETPAGEA ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1529 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1532 result = SendMessageA(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1539 FIXME("Tried to skip before first property sheet page!\n");
1542 if (index >= psInfo->nPages) {
1543 FIXME("Tried to skip after last property sheet page!\n");
1544 index = psInfo->nPages-1;
1550 * Display the new page.
1552 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1554 if (psInfo->proppage[index].hasHelp)
1555 EnableWindow(hwndHelp, TRUE);
1557 EnableWindow(hwndHelp, FALSE);
1562 /******************************************************************************
1563 * PROPSHEET_SetTitleA
1565 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1567 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1570 if (HIWORD(lpszText) == 0) {
1571 if (!LoadStringA(psInfo->ppshheader.hInstance,
1572 LOWORD(lpszText), szTitle, sizeof(szTitle)-1))
1576 if (dwStyle & PSH_PROPTITLE)
1579 int lentitle = strlen(lpszText);
1580 int lenprop = strlen(psInfo->strPropertiesFor);
1582 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
1583 strcpy(dest, psInfo->strPropertiesFor);
1584 strcat(dest, lpszText);
1586 SetWindowTextA(hwndDlg, dest);
1587 COMCTL32_Free(dest);
1590 SetWindowTextA(hwndDlg, lpszText);
1593 /******************************************************************************
1594 * PROPSHEET_SetFinishTextA
1596 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1598 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1600 /* Set text, show and enable the Finish button */
1601 SetWindowTextA(hwndButton, lpszText);
1602 ShowWindow(hwndButton, SW_SHOW);
1603 EnableWindow(hwndButton, TRUE);
1605 /* Make it default pushbutton */
1606 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1608 /* Hide Back button */
1609 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1610 ShowWindow(hwndButton, SW_HIDE);
1612 /* Hide Next button */
1613 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1614 ShowWindow(hwndButton, SW_HIDE);
1617 /******************************************************************************
1618 * PROPSHEET_QuerySiblings
1620 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1621 WPARAM wParam, LPARAM lParam)
1625 LRESULT msgResult = 0;
1626 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1629 while ((i < psInfo->nPages) && (msgResult == 0))
1631 hwndPage = psInfo->proppage[i].hwndPage;
1632 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1640 /******************************************************************************
1643 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1644 HPROPSHEETPAGE hpage)
1646 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1648 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1650 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1651 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1654 * Allocate and fill in a new PropPageInfo entry.
1656 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1657 sizeof(PropPageInfo) *
1658 (psInfo->nPages + 1));
1659 if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))
1662 psInfo->proppage[psInfo->nPages].hpage = hpage;
1664 if (ppsp->dwFlags & PSP_PREMATURE)
1666 /* Create the page but don't show it */
1667 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
1671 * Add a new tab to the tab control.
1673 item.mask = TCIF_TEXT;
1674 item.pszText = tabtext;
1675 item.cchTextMax = MAX_TABTEXT_LENGTH;
1677 WideCharToMultiByte(CP_ACP, 0,
1678 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1679 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1681 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1686 /* If it is the only page - show it */
1687 if(psInfo->nPages == 1)
1688 PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0);
1692 /******************************************************************************
1693 * PROPSHEET_RemovePage
1695 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1697 HPROPSHEETPAGE hpage)
1699 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1701 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1702 PropPageInfo* oldPages;
1707 oldPages = psInfo->proppage;
1709 * hpage takes precedence over index.
1713 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1716 /* Make sure that index is within range */
1717 if (index < 0 || index >= psInfo->nPages)
1719 TRACE("Could not find page to remove!\n");
1723 TRACE("total pages %d removing page %d active page %d\n",
1724 psInfo->nPages, index, psInfo->active_page);
1726 * Check if we're removing the active page.
1728 if (index == psInfo->active_page)
1730 if (psInfo->nPages > 1)
1734 /* activate previous page */
1735 PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0);
1739 /* activate the next page */
1740 PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0);
1741 psInfo->active_page = index;
1746 psInfo->active_page = -1;
1747 if (!psInfo->isModeless)
1749 EndDialog(hwndDlg, FALSE);
1754 else if (index < psInfo->active_page)
1755 psInfo->active_page--;
1757 /* Destroy page dialog window */
1758 DestroyWindow(psInfo->proppage[index].hwndPage);
1760 /* Free page resources */
1761 if(psInfo->proppage[index].hpage)
1763 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[index].hpage;
1765 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
1766 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
1768 DestroyPropertySheetPage(psInfo->proppage[index].hpage);
1771 /* Remove the tab */
1772 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1775 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1778 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1780 if (index < psInfo->nPages)
1781 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1782 (psInfo->nPages - index) * sizeof(PropPageInfo));
1784 COMCTL32_Free(oldPages);
1789 /******************************************************************************
1790 * PROPSHEET_SetWizButtons
1792 * This code will work if (and assumes that) the Next button is on top of the
1793 * Finish button. ie. Finish comes after Next in the Z order.
1794 * This means make sure the dialog template reflects this.
1797 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1799 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1800 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1801 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1803 TRACE("%ld\n", dwFlags);
1805 EnableWindow(hwndBack, FALSE);
1806 EnableWindow(hwndNext, FALSE);
1807 EnableWindow(hwndFinish, FALSE);
1809 if (dwFlags & PSWIZB_BACK)
1810 EnableWindow(hwndBack, TRUE);
1812 if (dwFlags & PSWIZB_NEXT)
1814 /* Hide the Finish button */
1815 ShowWindow(hwndFinish, SW_HIDE);
1817 /* Show and enable the Next button */
1818 ShowWindow(hwndNext, SW_SHOW);
1819 EnableWindow(hwndNext, TRUE);
1821 /* Set the Next button as the default pushbutton */
1822 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1825 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1827 /* Hide the Next button */
1828 ShowWindow(hwndNext, SW_HIDE);
1830 /* Show the Finish button */
1831 ShowWindow(hwndFinish, SW_SHOW);
1833 if (dwFlags & PSWIZB_FINISH)
1834 EnableWindow(hwndFinish, TRUE);
1836 /* Set the Finish button as the default pushbutton */
1837 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1841 /******************************************************************************
1842 * PROPSHEET_GetPageIndex
1844 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1845 * the array of PropPageInfo.
1847 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1852 while ((index < psInfo->nPages) && (found == FALSE))
1854 if (psInfo->proppage[index].hpage == hpage)
1866 /******************************************************************************
1869 static void PROPSHEET_CleanUp(HWND hwndDlg)
1872 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1876 if (HIWORD(psInfo->ppshheader.pszCaption))
1877 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader.pszCaption);
1879 for (i = 0; i < psInfo->nPages; i++)
1881 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
1883 if(psInfo->proppage[i].hwndPage)
1884 DestroyWindow(psInfo->proppage[i].hwndPage);
1888 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
1889 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);
1891 DestroyPropertySheetPage(psInfo->proppage[i].hpage);
1895 COMCTL32_Free(psInfo->proppage);
1896 COMCTL32_Free(psInfo->strPropertiesFor);
1897 ImageList_Destroy(psInfo->hImageList);
1899 GlobalFree((HGLOBAL)psInfo);
1902 /******************************************************************************
1903 * PropertySheet (COMCTL32.87)
1904 * PropertySheetA (COMCTL32.88)
1906 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1909 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1910 sizeof(PropSheetInfo));
1914 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1916 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1918 pByte = (BYTE*) psInfo->ppshheader.u3.ppsp;
1920 for (n = i = 0; i < lppsh->nPages; i++, n++)
1922 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1923 psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
1926 psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
1927 pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;
1930 if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEA)psInfo->proppage[n].hpage,
1933 if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
1934 DestroyPropertySheetPage(psInfo->proppage[n].hpage);
1940 bRet = PROPSHEET_CreateDialog(psInfo);
1945 /******************************************************************************
1946 * PropertySheetW (COMCTL32.89)
1948 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1950 FIXME("(%p): stub\n", propertySheetHeader);
1955 /******************************************************************************
1956 * CreatePropertySheetPage (COMCTL32.18)
1957 * CreatePropertySheetPageA (COMCTL32.19)
1959 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1960 LPCPROPSHEETPAGEA lpPropSheetPage)
1962 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1964 memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEA)));
1966 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) )
1967 ppsp->u.pszTemplate = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u.pszTemplate );
1969 if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )
1970 ppsp->u2.pszIcon = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u2.pszIcon );
1973 if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
1974 ppsp->pszTitle = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszTitle );
1975 else if ( !(ppsp->dwFlags & PSP_USETITLE) )
1976 ppsp->pszTitle = NULL;
1978 return (HPROPSHEETPAGE)ppsp;
1981 /******************************************************************************
1982 * CreatePropertySheetPageW (COMCTL32.20)
1984 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1986 FIXME("(%p): stub\n", lpPropSheetPage);
1991 /******************************************************************************
1992 * DestroyPropertySheetPage (COMCTL32.24)
1994 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
1996 PROPSHEETPAGEA *psp = (PROPSHEETPAGEA *)hPropPage;
2001 if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u.pszTemplate ) )
2002 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u.pszTemplate);
2004 if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )
2005 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u2.pszIcon);
2007 if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
2008 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);
2010 COMCTL32_Free(hPropPage);
2015 /******************************************************************************
2016 * PROPSHEET_IsDialogMessage
2018 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
2020 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, PropSheetInfoStr);
2022 if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
2025 if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
2028 INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
2030 if (!(dlgCode & DLGC_WANTMESSAGE))
2032 switch (lpMsg->wParam)
2035 if (GetKeyState(VK_SHIFT) & 0x8000)
2041 case VK_NEXT: new_page = 1; break;
2042 case VK_PRIOR: new_page = -1; break;
2048 if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
2050 new_page += psInfo->active_page;
2053 new_page = psInfo->nPages - 1;
2054 else if (new_page >= psInfo->nPages)
2057 PROPSHEET_SetCurSel(hwnd, new_page, 1, 0);
2064 return IsDialogMessageA(hwnd, lpMsg);
2067 /******************************************************************************
2068 * PROPSHEET_DialogProc
2071 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2077 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
2078 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
2079 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2080 LPCPROPSHEETPAGEA ppshpage;
2083 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
2086 * psInfo->hwnd is not being used by WINE code - it exists
2087 * for compatibility with "real" Windoze. The same about
2088 * SetWindowLong - WINE is only using the PropSheetInfoStr
2091 psInfo->hwnd = hwnd;
2092 SetWindowLongA(hwnd,DWL_USER,(LONG)psInfo);
2095 * Small icon in the title bar.
2097 if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||
2098 (psInfo->ppshheader.dwFlags & PSH_USEHICON))
2101 int icon_cx = GetSystemMetrics(SM_CXSMICON);
2102 int icon_cy = GetSystemMetrics(SM_CYSMICON);
2104 if (psInfo->ppshheader.dwFlags & PSH_USEICONID)
2105 hIcon = LoadImageA(psInfo->ppshheader.hInstance,
2106 psInfo->ppshheader.u.pszIcon,
2111 hIcon = psInfo->ppshheader.u.hIcon;
2113 SendMessageA(hwnd, WM_SETICON, 0, hIcon);
2116 if (psInfo->ppshheader.dwFlags & PSH_USEHICON)
2117 SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader.u.hIcon);
2119 psInfo->strPropertiesFor = strCaption;
2121 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
2123 PROPSHEET_CreateTabControl(hwnd, psInfo);
2125 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
2127 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
2129 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
2130 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
2135 if (PROPSHEET_SizeMismatch(hwnd, psInfo))
2137 PROPSHEET_AdjustSize(hwnd, psInfo);
2138 PROPSHEET_AdjustButtons(hwnd, psInfo);
2142 if (psInfo->useCallback)
2143 (*(psInfo->ppshheader.pfnCallback))(hwnd,
2144 PSCB_INITIALIZED, (LPARAM)0);
2146 idx = psInfo->active_page;
2147 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[idx].hpage;
2148 psInfo->active_page = -1;
2150 PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage);
2152 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
2153 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
2155 if (!HIWORD(psInfo->ppshheader.pszCaption) &&
2156 psInfo->ppshheader.hInstance)
2160 if (LoadStringA(psInfo->ppshheader.hInstance,
2161 (UINT)psInfo->ppshheader.pszCaption, szText, 255))
2162 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags, szText);
2166 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags,
2167 psInfo->ppshheader.pszCaption);
2174 PROPSHEET_CleanUp(hwnd);
2178 PROPSHEET_Cancel(hwnd, 1);
2183 WORD wID = LOWORD(wParam);
2188 case IDC_APPLY_BUTTON:
2190 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
2192 if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
2197 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2201 if (psInfo->restartWindows)
2202 result = ID_PSRESTARTWINDOWS;
2204 /* reboot system takes precedence over restart windows */
2205 if (psInfo->rebootSystem)
2206 result = ID_PSREBOOTSYSTEM;
2208 if (psInfo->isModeless)
2209 psInfo->activeValid = FALSE;
2211 EndDialog(hwnd, result);
2214 EnableWindow(hwndApplyBtn, FALSE);
2219 case IDC_BACK_BUTTON:
2220 PROPSHEET_Back(hwnd);
2223 case IDC_NEXT_BUTTON:
2224 PROPSHEET_Next(hwnd);
2227 case IDC_FINISH_BUTTON:
2228 PROPSHEET_Finish(hwnd);
2232 PROPSHEET_Cancel(hwnd, 0);
2236 PROPSHEET_Help(hwnd);
2245 NMHDR* pnmh = (LPNMHDR) lParam;
2247 if (pnmh->code == TCN_SELCHANGE)
2249 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
2250 PROPSHEET_SetCurSel(hwnd, index, 1, 0);
2253 if(pnmh->code == TCN_SELCHANGING)
2255 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
2256 SetWindowLongA(hwnd, DWL_MSGRESULT, !bRet);
2263 case PSM_GETCURRENTPAGEHWND:
2265 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2269 if (psInfo->activeValid && psInfo->active_page != -1)
2270 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
2272 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
2278 PROPSHEET_Changed(hwnd, (HWND)wParam);
2282 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
2285 case PSM_GETTABCONTROL:
2287 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2289 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
2298 msgResult = PROPSHEET_CanSetCurSel(hwnd);
2299 if(msgResult != FALSE)
2301 msgResult = PROPSHEET_SetCurSel(hwnd,
2304 (HPROPSHEETPAGE)lParam);
2307 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2312 case PSM_CANCELTOCLOSE:
2314 char buf[MAX_BUTTONTEXT_LENGTH];
2315 HWND hwndOK = GetDlgItem(hwnd, IDOK);
2316 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2318 EnableWindow(hwndCancel, FALSE);
2319 if (LoadStringA(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
2320 SetWindowTextA(hwndOK, buf);
2325 case PSM_RESTARTWINDOWS:
2327 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2330 psInfo->restartWindows = TRUE;
2334 case PSM_REBOOTSYSTEM:
2336 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2339 psInfo->rebootSystem = TRUE;
2344 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2349 BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
2351 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2356 case PSM_QUERYSIBLINGS:
2358 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2360 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2368 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2369 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2370 * on success or FALSE otherwise, as specified on MSDN Online.
2371 * Also see the MFC code for
2372 * CPropertySheet::AddPage(CPropertyPage* pPage).
2375 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2377 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2382 case PSM_REMOVEPAGE:
2383 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2386 case PSM_ISDIALOGMESSAGE:
2388 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
2389 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2393 case PSM_PRESSBUTTON:
2394 PROPSHEET_PressButton(hwnd, (int)wParam);
2397 case PSM_SETFINISHTEXTA:
2398 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2401 case PSM_SETWIZBUTTONS:
2402 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2406 FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2409 case PSM_SETCURSELID:
2410 FIXME("Unimplemented msg PSM_SETCURSELID\n");
2413 case PSM_SETFINISHTEXTW:
2414 FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");