source: trunk/src/comctl32/propsheet.cpp@ 5120

Last change on this file since 5120 was 4026, checked in by cbratschi, 25 years ago

wizard workaround

File size: 66.3 KB
Line 
1/* $Id: propsheet.cpp,v 1.8 2000-08-17 17:08:15 cbratschi Exp $ */
2/*
3 * Property Sheets
4 *
5 * Copyright 1998 Francis Beaudet
6 * Copyright 1999 Thuy Nguyen
7 * Copyright 1999 Achim Hasenmueller
8 * Copyright 1999-2000 Christoph Bratschi
9 *
10 * TODO:
11 * - Tab order
12 * - Unicode property sheets
13 * - Wizard bugs
14 */
15
16/*
17 - Corel WINE 20000807 level
18 - (WINE 991212 level)
19*/
20
21#include <string.h>
22#include "winbase.h"
23#include "commctrl.h"
24#include "prsht.h"
25#include "dialog.h"
26#include "winnls.h"
27#include "comctl32.h"
28#include "heap.h"
29
30/******************************************************************************
31 * Data structures
32 */
33typedef struct
34{
35 WORD dlgVer;
36 WORD signature;
37 DWORD helpID;
38 DWORD exStyle;
39 DWORD style;
40} MyDLGTEMPLATEEX;
41
42typedef struct tagPropPageInfo
43{
44 HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
45 HWND hwndPage;
46 BOOL isDirty;
47 LPCWSTR pszText;
48 BOOL hasHelp;
49 BOOL useCallback;
50 BOOL hasIcon;
51} PropPageInfo;
52
53typedef struct tagPropSheetInfo
54{
55 LPSTR strPropertiesFor;
56 int nPages;
57 int active_page;
58 LPPROPSHEETHEADERA ppshheader;
59 BOOL isModeless;
60 BOOL hasHelp;
61 BOOL hasApply;
62 BOOL useCallback;
63 BOOL restartWindows;
64 BOOL rebootSystem;
65 BOOL activeValid;
66 PropPageInfo* proppage;
67 int x;
68 int y;
69 int width;
70 int height;
71 HIMAGELIST hImageList;
72} PropSheetInfo;
73
74typedef struct
75{
76 int x;
77 int y;
78} PADDING_INFO;
79
80/******************************************************************************
81 * Defines and global variables
82 */
83
84const char * PropSheetInfoStr = "PropertySheetInfo";
85
86#define MAX_CAPTION_LENGTH 255
87#define MAX_TABTEXT_LENGTH 255
88#define MAX_BUTTONTEXT_LENGTH 64
89
90/******************************************************************************
91 * Prototypes
92 */
93static BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo);
94static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo);
95static BOOL PROPSHEET_IsTooSmall(HWND hwndDlg, PropSheetInfo* psInfo);
96static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);
97static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);
98static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
99 PropSheetInfo * psInfo);
100static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
101 PropSheetInfo * psInfo,
102 int index);
103static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
104 PropSheetInfo * psInfo);
105static int PROPSHEET_CreatePage(HWND hwndParent, int index,
106 const PropSheetInfo * psInfo,
107 LPPROPSHEETPAGEA ppshpage);
108static int PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);
109static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
110static void PROPSHEET_Back(HWND hwndDlg);
111static void PROPSHEET_Next(HWND hwndDlg);
112static void PROPSHEET_Finish(HWND hwndDlg);
113static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam);
114static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam);
115static void PROPSHEET_Help(HWND hwndDlg);
116static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
117static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
118static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
119static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText);
120static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
121static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
122static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
123 int index,
124 HPROPSHEETPAGE hpage);
125static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
126 WPARAM wParam, LPARAM lParam);
127static BOOL PROPSHEET_AddPage(HWND hwndDlg,
128 HPROPSHEETPAGE hpage);
129
130static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
131 int index,
132 HPROPSHEETPAGE hpage);
133static void PROPSHEET_CleanUp();
134static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
135static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags);
136static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg,PropSheetInfo* psInfo);
137static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg);
138static INT PROPSHEET_DoDialogBox( HWND hwnd, HWND owner);
139
140BOOL WINAPI
141PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
142
143
144/******************************************************************************
145 * PROPSHEET_CollectSheetInfo
146 *
147 * Collect relevant data.
148 */
149static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
150 PropSheetInfo * psInfo)
151{
152 DWORD dwFlags = lppsh->dwFlags;
153
154 psInfo->hasHelp = dwFlags & PSH_HASHELP;
155 psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
156 psInfo->useCallback = dwFlags & PSH_USECALLBACK;
157 psInfo->isModeless = dwFlags & PSH_MODELESS;
158 psInfo->ppshheader = (PROPSHEETHEADERA*)lppsh;
159 psInfo->ppshheader = (PROPSHEETHEADERA*)COMCTL32_Alloc(sizeof(PROPSHEETHEADERA));
160 *psInfo->ppshheader = *lppsh;
161
162 if (HIWORD(lppsh->pszCaption))
163 psInfo->ppshheader->pszCaption = HEAP_strdupA( GetProcessHeap(),
164 0, lppsh->pszCaption );
165
166 psInfo->nPages = lppsh->nPages;
167
168 if (dwFlags & PSH_USEPSTARTPAGE)
169 {
170 //TRACE(propsheet, "PSH_USEPSTARTPAGE is on");
171 psInfo->active_page = 0;
172 }
173 else
174 psInfo->active_page = lppsh->nStartPage;
175
176 if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
177 psInfo->active_page = 0;
178
179 psInfo->restartWindows = FALSE;
180 psInfo->rebootSystem = FALSE;
181 psInfo->hImageList = 0;
182 psInfo->activeValid = FALSE;
183
184 return TRUE;
185}
186
187/******************************************************************************
188 * PROPSHEET_FindPageByResId
189 *
190 * Find page index corresponding to page resource id.
191 */
192INT PROPSHEET_FindPageByResId(PropSheetInfo * psInfo, LRESULT resId)
193{
194 INT i;
195
196 for (i = 0; i < psInfo->nPages; i++)
197 {
198 LPCPROPSHEETPAGEA lppsp = (LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage;
199
200 /* Fixme: if resource ID is a string shall we use strcmp ??? */
201 if (lppsp->pszTemplate == (LPVOID)resId)
202 break;
203 }
204
205 return i;
206}
207
208/******************************************************************************
209 * PROPSHEET_CollectPageInfo
210 *
211 * Collect property sheet data.
212 * With code taken from DIALOG_ParseTemplate32.
213 */
214BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
215 PropSheetInfo * psInfo,
216 int index)
217{
218 DLGTEMPLATE* pTemplate;
219 const WORD* p;
220 DWORD dwFlags;
221 int width, height;
222
223 psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
224 psInfo->proppage[index].hwndPage = 0;
225 psInfo->proppage[index].isDirty = FALSE;
226
227 /*
228 * Process property page flags.
229 */
230 dwFlags = lppsp->dwFlags;
231 psInfo->proppage[index].useCallback = dwFlags & PSP_USECALLBACK;
232 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
233 psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
234
235 /* as soon as we have a page with the help flag, set the sheet flag on */
236 if (psInfo->proppage[index].hasHelp)
237 psInfo->hasHelp = TRUE;
238
239 /*
240 * Process page template.
241 */
242 if (dwFlags & PSP_DLGINDIRECT)
243 pTemplate = (DLGTEMPLATE*)lppsp->pResource;
244 else
245 {
246 HRSRC hResource = FindResourceA(lppsp->hInstance,
247 lppsp->pszTemplate,
248 RT_DIALOGA);
249 HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
250 hResource);
251 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
252 }
253
254 /*
255 * Extract the size of the page and the caption.
256 */
257 p = (const WORD *)pTemplate;
258
259 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
260 {
261 /* DIALOGEX template */
262
263 p++; /* dlgVer */
264 p++; /* signature */
265 p += 2; /* help ID */
266 p += 2; /* ext style */
267 p += 2; /* style */
268 }
269 else
270 {
271 /* DIALOG template */
272
273 p += 2; /* style */
274 p += 2; /* ext style */
275 }
276
277 p++; /* nb items */
278 p++; /* x */
279 p++; /* y */
280 width = (WORD)*p; p++;
281 height = (WORD)*p; p++;
282
283 /* remember the largest width and height */
284 if (width > psInfo->width)
285 psInfo->width = width;
286
287 if (height > psInfo->height)
288 psInfo->height = height;
289
290 /* menu */
291 switch ((WORD)*p)
292 {
293 case 0x0000:
294 p++;
295 break;
296 case 0xffff:
297 p += 2;
298 break;
299 default:
300 p += lstrlenW( (LPCWSTR)p ) + 1;
301 break;
302 }
303
304 /* class */
305 switch ((WORD)*p)
306 {
307 case 0x0000:
308 p++;
309 break;
310 case 0xffff:
311 p += 2;
312 break;
313 default:
314 p += lstrlenW( (LPCWSTR)p ) + 1;
315 break;
316 }
317
318 /* Extract the caption */
319 psInfo->proppage[index].pszText = (LPCWSTR)p;
320 //TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
321 p += lstrlenW((LPCWSTR)p) + 1;
322
323 if (dwFlags & PSP_USETITLE)
324 {
325 if ( !HIWORD( lppsp->pszTitle ) )
326 {
327 char szTitle[256];
328
329 if ( !LoadStringA( lppsp->hInstance, (UINT) lppsp->pszTitle, szTitle, 256 ) )
330 return FALSE;
331
332 psInfo->proppage[index].pszText = HEAP_strdupAtoW( GetProcessHeap(),
333 0, szTitle );
334 }
335 else
336 psInfo->proppage[index].pszText = HEAP_strdupAtoW(GetProcessHeap(),
337 0,
338 lppsp->pszTitle);
339 }
340
341 /*
342 * Build the image list for icons
343 */
344 if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
345 {
346 HICON hIcon;
347 int icon_cx = GetSystemMetrics(SM_CXSMICON);
348 int icon_cy = GetSystemMetrics(SM_CYSMICON);
349
350 if (dwFlags & PSP_USEICONID)
351 hIcon = LoadImageA(lppsp->hInstance, lppsp->pszIcon, IMAGE_ICON,
352 icon_cx, icon_cy, LR_DEFAULTCOLOR);
353 else
354 hIcon = lppsp->hIcon;
355
356 if ( hIcon )
357 {
358 if (psInfo->hImageList == 0 )
359 psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
360
361 ImageList_AddIcon(psInfo->hImageList, hIcon);
362 }
363
364 }
365
366 return TRUE;
367}
368
369/******************************************************************************
370 * PROPSHEET_DoDialogBox
371 *
372 * Copied from windows/dialog.c:DIALOG_DoDialogBox
373 */
374static INT PROPSHEET_DoDialogBox( HWND hwnd, HWND owner)
375{
376 DIALOGINFO * dlgInfo;
377 MSG msg;
378 INT retval;
379
380 dprintf(("PROPSHEET: PROPSHEET_DoDialogBox not implemented!!!"));
381
382#if 0 //CB: implement! sync with user32\win32dlg.cpp DoDialogBox method (not easy)
383 // this functions isn't used so far
384 /* Owner must be a top-level window */
385 owner = WIN_GetTopParent( owner );
386 if (!IsWindow(hwnd))) return -1;
387 dlgInfo = (DIALOGINFO*)wndPtr->wExtra;
388
389 if (!dlgInfo->flags & DF_END) /* was EndDialog called in WM_INITDIALOG ? */
390 {
391 EnableWindow( owner, FALSE );
392 ShowWindow( hwnd, SW_SHOW );
393 while (GetMessageA(&msg, 0, 0, 0))
394 {
395 if (!PROPSHEET_IsDialogMessage( hwnd, &msg))
396 {
397 TranslateMessage( &msg );
398 DispatchMessageA( &msg );
399 }
400 if (dlgInfo->flags & DF_END) break;
401 }
402 EnableWindow( owner, TRUE );
403 }
404 retval = dlgInfo->dlgExtra->idResult;
405#endif
406 DestroyWindow( hwnd );
407 return retval;
408}
409
410/******************************************************************************
411 * PROPSHEET_CreateDialog
412 *
413 * Creates the actual property sheet.
414 */
415
416BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
417{
418 LRESULT ret;
419 LPCVOID templ;
420 LPVOID temp = 0;
421 HRSRC hRes;
422 DWORD resSize;
423 WORD resID = IDD_PROPSHEET;
424
425 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
426 resID = IDD_WIZARD;
427
428 if(!(hRes = FindResourceA(COMCTL32_hModule,
429 MAKEINTRESOURCEA(resID),
430 RT_DIALOGA)))
431 return FALSE;
432
433 if(!(templ = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
434 return FALSE;
435
436 /*
437 * Make a copy of the dialog template.
438 */
439 resSize = SizeofResource(COMCTL32_hModule, hRes);
440
441 temp = COMCTL32_Alloc(resSize);
442
443 if (!temp)
444 return FALSE;
445
446 memcpy(temp, templ, resSize);
447
448 if (psInfo->useCallback)
449 (*(psInfo->ppshheader->pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
450
451 if (psInfo->ppshheader->dwFlags & PSH_MODELESS)
452 ret = CreateDialogIndirectParamA(psInfo->ppshheader->hInstance,
453 (LPDLGTEMPLATEA) temp,
454 psInfo->ppshheader->hwndParent,
455 (DLGPROC) PROPSHEET_DialogProc,
456 (LPARAM)psInfo);
457 else
458 ret = DialogBoxIndirectParamA(psInfo->ppshheader->hInstance,
459 (LPDLGTEMPLATEA) temp,
460 psInfo->ppshheader->hwndParent,
461 (DLGPROC) PROPSHEET_DialogProc,
462 (LPARAM)psInfo);
463
464 COMCTL32_Free(temp);
465
466 return ret;
467}
468
469/******************************************************************************
470 * PROPSHEET_IsTooSmall
471 *
472 * Verify that the resource property sheet is big enough.
473 */
474static BOOL PROPSHEET_IsTooSmall(HWND hwndDlg, PropSheetInfo* psInfo)
475{
476 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
477 RECT rcOrigTab, rcPage;
478
479 /*
480 * Original tab size.
481 */
482 GetClientRect(hwndTabCtrl, &rcOrigTab);
483// TRACE(propsheet, "orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
484// rcOrigTab.right, rcOrigTab.bottom);
485
486 /*
487 * Biggest page size.
488 */
489 rcPage.left = psInfo->x;
490 rcPage.top = psInfo->y;
491 rcPage.right = psInfo->width;
492 rcPage.bottom = psInfo->height;
493
494 MapDialogRect(hwndDlg, &rcPage);
495// TRACE(propsheet, "biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
496// rcPage.right, rcPage.bottom);
497
498 if (rcPage.right > rcOrigTab.right)
499 return TRUE;
500
501 if (rcPage.bottom > rcOrigTab.bottom)
502 return TRUE;
503
504 return FALSE;
505}
506
507/******************************************************************************
508 * PROPSHEET_SizeMismatch
509 *
510 * Verify that the tab control and the "largest" property sheet page dlg. template
511 * match in size.
512 */
513static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)
514{
515 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
516 RECT rcOrigTab, rcPage;
517
518 /*
519 * Original tab size.
520 */
521 GetClientRect(hwndTabCtrl, &rcOrigTab);
522 //TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
523 // rcOrigTab.right, rcOrigTab.bottom);
524
525 /*
526 * Biggest page size.
527 */
528 rcPage.left = psInfo->x;
529 rcPage.top = psInfo->y;
530 rcPage.right = psInfo->width;
531 rcPage.bottom = psInfo->height;
532
533 MapDialogRect(hwndDlg, &rcPage);
534 //TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
535 // rcPage.right, rcPage.bottom);
536
537 if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
538 return TRUE;
539 if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
540 return TRUE;
541
542 return FALSE;
543}
544
545/******************************************************************************
546 * PROPSHEET_IsTooSmallWizard
547 *
548 * Verify that the default property sheet is big enough.
549 */
550static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
551{
552 RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
553 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
554 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg,psInfo);
555
556 GetClientRect(hwndDlg, &rcSheetClient);
557 GetWindowRect(hwndDlg, &rcSheetRect);
558 GetWindowRect(hwndLine, &rcLine);
559
560 /* Remove the space below the sunken line */
561 rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
562
563 /* Remove the buffer zone all around the edge */
564 rcSheetClient.bottom -= (padding.y * 2);
565 rcSheetClient.right -= (padding.x * 2);
566
567 /*
568 * Biggest page size.
569 */
570 rcPage.left = psInfo->x;
571 rcPage.top = psInfo->y;
572 rcPage.right = psInfo->width;
573 rcPage.bottom = psInfo->height;
574
575 MapDialogRect(hwndDlg, &rcPage);
576// TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
577// rcPage.right, rcPage.bottom);
578
579 if (rcPage.right > rcSheetClient.right)
580 return TRUE;
581
582 if (rcPage.bottom > rcSheetClient.bottom)
583 return TRUE;
584
585 return FALSE;
586}
587
588/******************************************************************************
589 * PROPSHEET_AdjustSize
590 *
591 * Resizes the property sheet and the tab control to fit the largest page.
592 */
593static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
594{
595 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
596 HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
597 RECT rc;
598 int tabOffsetX, tabOffsetY, buttonHeight;
599 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
600
601 /* Get the height of buttons */
602 GetClientRect(hwndButton, &rc);
603 buttonHeight = rc.bottom;
604
605 /*
606 * Biggest page size.
607 */
608 rc.left = psInfo->x;
609 rc.top = psInfo->y;
610 rc.right = psInfo->width;
611 rc.bottom = psInfo->height;
612
613 MapDialogRect(hwndDlg, &rc);
614
615 /*
616 * Resize the tab control.
617 */
618 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
619
620 tabOffsetX = -(rc.left);
621 tabOffsetY = -(rc.top);
622
623 rc.right -= rc.left;
624 rc.bottom -= rc.top;
625 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
626 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
627
628 GetClientRect(hwndTabCtrl, &rc);
629
630// TRACE(propsheet, "tab client rc %d %d %d %d\n",
631// rc.left, rc.top, rc.right, rc.bottom);
632
633 rc.right += ((padding.x * 2) + tabOffsetX);
634 rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
635
636 /*
637 * Resize the property sheet.
638 */
639 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
640 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
641
642 return TRUE;
643}
644
645/******************************************************************************
646 * PROPSHEET_AdjustSizeWizard
647 *
648 * Resizes the property sheet to fit the largest page.
649 */
650static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
651{
652 HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
653 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
654 RECT rc;
655 int buttonHeight, lineHeight;
656 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg,psInfo);
657
658 /* Get the height of buttons */
659 GetClientRect(hwndButton, &rc);
660 buttonHeight = rc.bottom;
661
662 GetClientRect(hwndLine, &rc);
663 lineHeight = rc.bottom;
664
665 /*
666 * Biggest page size.
667 */
668 rc.left = psInfo->x;
669 rc.top = psInfo->y;
670 rc.right = psInfo->width;
671 rc.bottom = psInfo->height;
672
673 MapDialogRect(hwndDlg, &rc);
674
675// TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
676
677 /* Make room */
678 rc.right += (padding.x * 2);
679 rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
680
681 /*
682 * Resize the property sheet.
683 */
684 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
685 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
686
687 return TRUE;
688}
689
690/******************************************************************************
691 * PROPSHEET_AdjustButtons
692 *
693 * Adjusts the buttons' positions.
694 */
695static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
696{
697 HWND hwndButton = GetDlgItem(hwndParent, IDOK);
698 RECT rcSheet;
699 int x, y;
700 int num_buttons = 2;
701 int buttonWidth, buttonHeight;
702 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
703
704 if (psInfo->hasApply)
705 num_buttons++;
706
707 if (psInfo->hasHelp)
708 num_buttons++;
709
710 /*
711 * Obtain the size of the buttons.
712 */
713 GetClientRect(hwndButton, &rcSheet);
714 buttonWidth = rcSheet.right;
715 buttonHeight = rcSheet.bottom;
716
717 /*
718 * Get the size of the property sheet.
719 */
720 GetClientRect(hwndParent, &rcSheet);
721
722 /*
723 * All buttons will be at this y coordinate.
724 */
725 y = rcSheet.bottom - (padding.y + buttonHeight);
726
727 /*
728 * Position OK button.
729 */
730 hwndButton = GetDlgItem(hwndParent, IDOK);
731
732 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
733
734 SetWindowPos(hwndButton, 0, x, y, 0, 0,
735 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
736
737 /*
738 * Position Cancel button.
739 */
740 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
741
742 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
743
744 SetWindowPos(hwndButton, 0, x, y, 0, 0,
745 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
746
747 /*
748 * Position Apply button.
749 */
750 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
751
752 if (psInfo->hasApply)
753 {
754 if (psInfo->hasHelp)
755 x = rcSheet.right - ((padding.x + buttonWidth) * 2);
756 else
757 x = rcSheet.right - (padding.x + buttonWidth);
758
759 SetWindowPos(hwndButton, 0, x, y, 0, 0,
760 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
761
762 EnableWindow(hwndButton, FALSE);
763 }
764 else
765 ShowWindow(hwndButton, SW_HIDE);
766
767 /*
768 * Position Help button.
769 */
770 hwndButton = GetDlgItem(hwndParent, IDHELP);
771
772 if (psInfo->hasHelp)
773 {
774 x = rcSheet.right - (padding.x + buttonWidth);
775
776 SetWindowPos(hwndButton, 0, x, y, 0, 0,
777 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
778 }
779 else
780 ShowWindow(hwndButton, SW_HIDE);
781
782 return TRUE;
783}
784
785/******************************************************************************
786 * PROPSHEET_AdjustButtonsWizard
787 *
788 * Adjusts the buttons' positions.
789 */
790static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
791 PropSheetInfo* psInfo)
792{
793 HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
794 HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
795 RECT rcSheet;
796 int x, y;
797 int num_buttons = 3;
798 int buttonWidth, buttonHeight, lineHeight, lineWidth;
799 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent,psInfo);
800
801 if (psInfo->hasHelp)
802 num_buttons++;
803
804 /*
805 * Obtain the size of the buttons.
806 */
807 GetClientRect(hwndButton, &rcSheet);
808 buttonWidth = rcSheet.right;
809 buttonHeight = rcSheet.bottom;
810
811 GetClientRect(hwndLine, &rcSheet);
812 lineHeight = rcSheet.bottom;
813
814 /*
815 * Get the size of the property sheet.
816 */
817 GetClientRect(hwndParent, &rcSheet);
818
819 /*
820 * All buttons will be at this y coordinate.
821 */
822 y = rcSheet.bottom - (padding.y + buttonHeight);
823
824 /*
825 * Position the Next and the Finish buttons.
826 */
827 hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
828
829 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
830
831 SetWindowPos(hwndButton, 0, x, y, 0, 0,
832 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
833
834 hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
835
836 SetWindowPos(hwndButton, 0, x, y, 0, 0,
837 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
838
839 ShowWindow(hwndButton, SW_HIDE);
840
841 /*
842 * Position the Back button.
843 */
844 hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
845
846 x -= buttonWidth;
847
848 SetWindowPos(hwndButton, 0, x, y, 0, 0,
849 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
850
851 /*
852 * Position the Cancel button.
853 */
854 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
855
856 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
857
858 SetWindowPos(hwndButton, 0, x, y, 0, 0,
859 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
860
861 /*
862 * Position Help button.
863 */
864 hwndButton = GetDlgItem(hwndParent, IDHELP);
865
866 if (psInfo->hasHelp)
867 {
868 x = rcSheet.right - (padding.x + buttonWidth);
869
870 SetWindowPos(hwndButton, 0, x, y, 0, 0,
871 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
872 }
873 else
874 ShowWindow(hwndButton, SW_HIDE);
875
876 /*
877 * Position and resize the sunken line.
878 */
879 x = padding.x;
880 y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
881
882 GetClientRect(hwndParent, &rcSheet);
883 lineWidth = rcSheet.right - (padding.x * 2);
884
885 SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
886 SWP_NOZORDER | SWP_NOACTIVATE);
887
888 return TRUE;
889}
890
891/******************************************************************************
892 * PROPSHEET_GetPaddingInfo
893 *
894 * Returns the layout information.
895 */
896static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
897{
898 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
899 RECT rcTab;
900 POINT tl;
901 PADDING_INFO padding;
902
903 GetWindowRect(hwndTab, &rcTab);
904
905 tl.x = rcTab.left;
906 tl.y = rcTab.top;
907
908 ScreenToClient(hwndDlg, &tl);
909
910 padding.x = tl.x;
911 padding.y = tl.y;
912
913 return padding;
914}
915
916/******************************************************************************
917 * PROPSHEET_GetPaddingInfoWizard
918 *
919 * Returns the layout information.
920 * Horizontal spacing is the distance between the Cancel and Help buttons.
921 * Vertical spacing is the distance between the line and the buttons.
922 */
923static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg,PropSheetInfo* psInfo)
924{
925 PADDING_INFO padding;
926 RECT rc;
927 HWND hwndControl;
928 POINT ptHelp, ptCancel, ptLine;
929
930 /* Help button */
931 hwndControl = GetDlgItem(hwndDlg, IDHELP);
932 GetWindowRect(hwndControl, &rc);
933
934 ptHelp.x = rc.left;
935 ptHelp.y = rc.top;
936
937 ScreenToClient(hwndDlg, &ptHelp);
938
939 /* Cancel button */
940 hwndControl = GetDlgItem(hwndDlg, IDCANCEL);
941 GetWindowRect(hwndControl, &rc);
942
943 ptCancel.x = rc.right;
944 ptCancel.y = rc.top;
945
946 ScreenToClient(hwndDlg, &ptCancel);
947
948 /* Line */
949 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
950 GetWindowRect(hwndControl, &rc);
951
952 ptLine.x = 0;
953 ptLine.y = rc.bottom;
954
955 ScreenToClient(hwndDlg, &ptLine);
956
957 padding.x = ptHelp.x - ptCancel.x;
958 padding.y = ptHelp.y - ptLine.y;
959
960//CB: BUG: psInfo->hasHelp not checked -> negative values
961// add better wizard handling, fix button placement bugs FIXME
962//
963// workaround for now:
964if (padding.x < 0) padding.x = 0;
965if (padding.y < 0) padding.y = 0;
966
967 return padding;
968}
969
970/******************************************************************************
971 * PROPSHEET_CreateTabControl
972 *
973 * Insert the tabs in the tab control.
974 */
975static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
976 PropSheetInfo * psInfo)
977{
978 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
979 TCITEMA item;
980 int i, nTabs;
981 int iImage = 0;
982 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
983
984 item.mask = TCIF_TEXT;
985 item.pszText = tabtext;
986 item.cchTextMax = MAX_TABTEXT_LENGTH;
987
988 nTabs = psInfo->ppshheader->nPages;
989
990 /*
991 * Set the image list for icons.
992 */
993 if (psInfo->hImageList)
994 {
995 SendMessageA(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
996 }
997
998 for (i = 0; i < nTabs; i++)
999 {
1000 if ( psInfo->proppage[i].hasIcon )
1001 {
1002 item.mask |= TCIF_IMAGE;
1003 item.iImage = iImage++;
1004 }
1005 else
1006 {
1007 item.mask &= ~TCIF_IMAGE;
1008 }
1009
1010 WideCharToMultiByte(CP_ACP, 0,
1011 (LPCWSTR)psInfo->proppage[i].pszText,
1012 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1013
1014 SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
1015 }
1016
1017 return TRUE;
1018}
1019
1020/******************************************************************************
1021 * PROPSHEET_CreatePage
1022 *
1023 * Creates a page.
1024 */
1025static int PROPSHEET_CreatePage(HWND hwndParent,
1026 int index,
1027 const PropSheetInfo * psInfo,
1028 LPPROPSHEETPAGEA ppshpage)
1029{
1030 DLGTEMPLATE* pTemplate;
1031 HWND hwndPage;
1032
1033 PropPageInfo* ppInfo = psInfo->proppage;
1034
1035 //TRACE("index %d\n", index);
1036
1037 //AH: Check if ppshpage is valid
1038 if (ppshpage == NULL)
1039 {
1040 dprintf(("COMCTL32:PROPSHEET_CreatePage: ERROR!!! ppshpage == NULL!!!\n"));
1041 return FALSE;
1042 }
1043
1044 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
1045 pTemplate = (DLGTEMPLATE*)ppshpage->pResource;
1046 else
1047 {
1048 HRSRC hResource = FindResourceA(ppshpage->hInstance,
1049 ppshpage->pszTemplate,
1050 RT_DIALOGA);
1051 HGLOBAL hTemplate = LoadResource(ppshpage->hInstance, hResource);
1052 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
1053 }
1054
1055 //AH: Check if pTemplate is valid
1056 if (pTemplate == NULL)
1057 {
1058 dprintf(("COMCTL32:PROPSHEET_CreatePage: ERROR!!! Dialog Template == NULL!!!\n"));
1059 return FALSE;
1060 }
1061
1062 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
1063 {
1064 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;
1065 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
1066 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
1067 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
1068 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
1069 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
1070 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
1071 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_THICKFRAME;
1072 }
1073 else
1074 {
1075 pTemplate->style |= WS_CHILDWINDOW | DS_CONTROL;
1076 pTemplate->style &= ~DS_MODALFRAME;
1077 pTemplate->style &= ~WS_CAPTION;
1078 pTemplate->style &= ~WS_SYSMENU;
1079 pTemplate->style &= ~WS_POPUP;
1080 pTemplate->style &= ~WS_DISABLED;
1081 pTemplate->style &= ~WS_VISIBLE;
1082 pTemplate->style &= ~WS_THICKFRAME;
1083 }
1084
1085 if (psInfo->proppage[index].useCallback)
1086 (*(ppshpage->pfnCallback))(hwndParent,
1087 PSPCB_CREATE,
1088 (LPPROPSHEETPAGEA)ppshpage);
1089
1090 hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
1091 pTemplate,
1092 hwndParent,
1093 ppshpage->pfnDlgProc,
1094 (LPARAM)ppshpage);
1095
1096 ppInfo[index].hwndPage = hwndPage;
1097
1098 return TRUE;
1099}
1100
1101/******************************************************************************
1102 * PROPSHEET_ShowPage
1103 *
1104 * Displays or creates the specified page.
1105 *
1106 * Returns: 1 - specified page is activated.
1107 * 0 - function fails
1108 * -1 - some other page is activated
1109 */
1110static int PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1111{
1112 RECT rc;
1113 PADDING_INFO padding;
1114 UINT pageWidth,pageHeight;
1115
1116 if (index == psInfo->active_page)
1117 {
1118 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1119 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1120
1121 return 1;
1122 }
1123
1124 if (psInfo->active_page != -1)
1125 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1126
1127 if (psInfo->proppage[index].hwndPage == 0)
1128 {
1129 LPCPROPSHEETPAGEA ppshpage;
1130 PSHNOTIFY psn;
1131 LRESULT ret;
1132
1133 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1134 PROPSHEET_CreatePage(hwndDlg, index, psInfo, (PROPSHEETPAGEA*)ppshpage);
1135
1136 if (psInfo->proppage[index].hwndPage == 0)
1137 return 0;
1138
1139 psn.hdr.hwndFrom = hwndDlg;
1140 psn.hdr.code = PSN_SETACTIVE;
1141 psn.hdr.idFrom = 0;
1142 psn.lParam = 0;
1143
1144 /* Send the notification before showing the page. */
1145 ret = SendMessageA(psInfo->proppage[index].hwndPage,
1146 WM_NOTIFY, 0, (LPARAM) &psn);
1147
1148 if (ret)
1149 {
1150 /* User doesn't accept new selection - find desired page and reselect */
1151 if (ret == -1)
1152 {
1153 if (index > psInfo->active_page)
1154 index++;
1155 else
1156 index--;
1157 }
1158 else
1159 index = PROPSHEET_FindPageByResId(psInfo, ret);
1160
1161 return PROPSHEET_SetCurSel(hwndDlg, index, 0) ? -1 : 0;
1162 }
1163 }
1164
1165 if (psInfo->active_page != -1)
1166 {
1167 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1168 }
1169
1170 /* HACK: Sometimes a property page doesn't get displayed at the right place inside the
1171 * property sheet. This will force the window to be placed at the proper location
1172 * before it is displayed.
1173 */
1174 rc.left = psInfo->x;
1175 rc.top = psInfo->y;
1176 rc.right = psInfo->width;
1177 rc.bottom = psInfo->height;
1178
1179 MapDialogRect(hwndDlg, &rc);
1180
1181 pageWidth = rc.right - rc.left;
1182 pageHeight = rc.bottom - rc.top;
1183
1184 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
1185 padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg,psInfo);
1186 else
1187 {
1188 /*
1189 * Ask the Tab control to fit this page in.
1190 */
1191
1192 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1193 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
1194 padding = PROPSHEET_GetPaddingInfo(hwndDlg);
1195 }
1196
1197 SetWindowPos(psInfo->proppage[index].hwndPage,HWND_TOP,rc.left+padding.x,rc.top+padding.y,pageWidth,pageHeight,SWP_SHOWWINDOW);
1198
1199 if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
1200 {
1201 HWND hwndTabCtrl;
1202
1203 /* Synchronize current selection with tab control */
1204 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1205 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1206 }
1207
1208 psInfo->active_page = index;
1209 psInfo->activeValid = TRUE;
1210
1211 return 1;
1212}
1213
1214/******************************************************************************
1215 * PROPSHEET_Back
1216 */
1217static void PROPSHEET_Back(HWND hwndDlg)
1218{
1219 PSHNOTIFY psn;
1220 HWND hwndPage;
1221 LRESULT msgResult = 0;
1222 INT idx;
1223 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1224 PropSheetInfoStr);
1225
1226 if (psInfo->active_page < 0)
1227 return;
1228
1229 psn.hdr.code = PSN_WIZBACK;
1230 psn.hdr.hwndFrom = hwndDlg;
1231 psn.hdr.idFrom = 0;
1232 psn.lParam = 0;
1233
1234 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1235
1236 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1237
1238 if (msgResult == -1)
1239 return;
1240 else if (msgResult == 0)
1241 idx = psInfo->active_page - 1;
1242 else
1243 idx = PROPSHEET_FindPageByResId(psInfo, msgResult);
1244
1245 if (idx >= 0 && idx < psInfo->nPages)
1246 {
1247 if (PROPSHEET_CanSetCurSel(hwndDlg))
1248 PROPSHEET_SetCurSel(hwndDlg, idx, 0);
1249 }
1250}
1251
1252/******************************************************************************
1253 * PROPSHEET_Next
1254 */
1255static void PROPSHEET_Next(HWND hwndDlg)
1256{
1257 PSHNOTIFY psn;
1258 HWND hwndPage;
1259 LRESULT msgResult = 0;
1260 INT idx;
1261 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1262 PropSheetInfoStr);
1263
1264 if (psInfo->active_page < 0)
1265 return;
1266
1267 psn.hdr.code = PSN_WIZNEXT;
1268 psn.hdr.hwndFrom = hwndDlg;
1269 psn.hdr.idFrom = 0;
1270 psn.lParam = 0;
1271
1272 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1273
1274 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1275
1276 //TRACE("msg result %ld\n", msgResult);
1277
1278 if (msgResult == -1)
1279 return;
1280 else if (msgResult == 0)
1281 idx = psInfo->active_page + 1;
1282 else
1283 idx = PROPSHEET_FindPageByResId(psInfo, msgResult);
1284
1285 if (idx < psInfo->nPages )
1286 {
1287 if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1288 PROPSHEET_SetCurSel(hwndDlg, idx, 0);
1289 }
1290}
1291
1292/******************************************************************************
1293 * PROPSHEET_Finish
1294 */
1295static void PROPSHEET_Finish(HWND hwndDlg)
1296{
1297 PSHNOTIFY psn;
1298 HWND hwndPage;
1299 LRESULT msgResult = 0;
1300 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1301 PropSheetInfoStr);
1302
1303 if (psInfo->active_page < 0)
1304 return;
1305
1306 psn.hdr.code = PSN_WIZFINISH;
1307 psn.hdr.hwndFrom = hwndDlg;
1308 psn.hdr.idFrom = 0;
1309 psn.lParam = 0;
1310
1311 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1312
1313 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1314
1315 //TRACE("msg result %ld\n", msgResult);
1316
1317 if (msgResult != 0)
1318 return;
1319
1320 if (psInfo->isModeless)
1321 psInfo->activeValid = FALSE;
1322 else
1323 EndDialog(hwndDlg, TRUE);
1324}
1325
1326/******************************************************************************
1327 * PROPSHEET_Apply
1328 */
1329static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1330{
1331 int i;
1332 HWND hwndPage;
1333 PSHNOTIFY psn;
1334 LRESULT msgResult;
1335 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1336 PropSheetInfoStr);
1337
1338 if (psInfo->active_page < 0)
1339 return FALSE;
1340
1341 psn.hdr.hwndFrom = hwndDlg;
1342 psn.hdr.idFrom = 0;
1343 psn.lParam = 0;
1344
1345
1346 /*
1347 * Send PSN_KILLACTIVE to the current page.
1348 */
1349 psn.hdr.code = PSN_KILLACTIVE;
1350
1351 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1352
1353 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1354 return FALSE;
1355
1356 /*
1357 * Send PSN_APPLY to all pages.
1358 */
1359 psn.hdr.code = PSN_APPLY;
1360 psn.lParam = lParam;
1361
1362 for (i = 0; i < psInfo->nPages; i++)
1363 {
1364 hwndPage = psInfo->proppage[i].hwndPage;
1365 if (hwndPage)
1366 {
1367 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1368 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1369 return FALSE;
1370 else if (msgResult == PSNRET_INVALID)
1371 {
1372 PROPSHEET_SetCurSel(hwndDlg, i, 0);
1373 return FALSE;
1374 }
1375 }
1376 }
1377
1378 EnableWindow(GetDlgItem(hwndDlg, IDC_APPLY_BUTTON), FALSE);
1379
1380 if(lParam)
1381 {
1382 int result = TRUE;
1383
1384 psInfo->activeValid = FALSE;
1385
1386 if (psInfo->restartWindows)
1387 result = ID_PSRESTARTWINDOWS;
1388
1389 /* reboot system takes precedence over restart windows */
1390 if (psInfo->rebootSystem)
1391 result = ID_PSREBOOTSYSTEM;
1392
1393 if (!psInfo->isModeless)
1394 EndDialog(hwndDlg, result);
1395 }
1396 else if(psInfo->active_page >= 0)
1397 {
1398 psn.hdr.code = PSN_SETACTIVE;
1399 psn.lParam = 0;
1400 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1401 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1402 /* Fixme: probably we have to handle return value */
1403 }
1404
1405 return TRUE;
1406}
1407
1408/******************************************************************************
1409 * PROPSHEET_Cancel
1410 */
1411static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1412{
1413 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1414 PropSheetInfoStr);
1415 HWND hwndPage;
1416 PSHNOTIFY psn;
1417 int i;
1418
1419 if (psInfo->active_page < 0)
1420 return;
1421
1422 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1423 psn.hdr.code = PSN_QUERYCANCEL;
1424 psn.hdr.hwndFrom = hwndDlg;
1425 psn.hdr.idFrom = 0;
1426 psn.lParam = 0;
1427
1428 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1429 return;
1430
1431 psn.hdr.code = PSN_RESET;
1432 psn.lParam = lParam;
1433
1434 for (i = 0; i < psInfo->nPages; i++)
1435 {
1436 hwndPage = psInfo->proppage[i].hwndPage;
1437
1438 if (hwndPage)
1439 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1440 /* No return value */
1441 }
1442
1443 if (psInfo->isModeless)
1444 {
1445 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1446 psInfo->activeValid = FALSE;
1447 }
1448 else
1449 EndDialog(hwndDlg, FALSE);
1450}
1451
1452/******************************************************************************
1453 * PROPSHEET_Help
1454 */
1455static void PROPSHEET_Help(HWND hwndDlg)
1456{
1457 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1458 PropSheetInfoStr);
1459 HWND hwndPage;
1460 PSHNOTIFY psn;
1461
1462 if (psInfo->active_page < 0)
1463 return;
1464
1465 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1466 psn.hdr.code = PSN_HELP;
1467 psn.hdr.hwndFrom = hwndDlg;
1468 psn.hdr.idFrom = 0;
1469 psn.lParam = 0;
1470
1471 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1472}
1473
1474/******************************************************************************
1475 * PROPSHEET_Changed
1476 */
1477static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1478{
1479 int i;
1480 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1481 PropSheetInfoStr);
1482 if (!psInfo) return;
1483 /*
1484 * Set the dirty flag of this page.
1485 */
1486 for (i = 0; i < psInfo->nPages; i++)
1487 {
1488 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1489 psInfo->proppage[i].isDirty = TRUE;
1490 }
1491
1492 /*
1493 * Enable the Apply button.
1494 */
1495 if (psInfo->hasApply)
1496 {
1497 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1498
1499 EnableWindow(hwndApplyBtn, TRUE);
1500 }
1501}
1502
1503/******************************************************************************
1504 * PROPSHEET_UnChanged
1505 */
1506static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1507{
1508 int i;
1509 BOOL noPageDirty = TRUE;
1510 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1511 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1512 PropSheetInfoStr);
1513 if ( !psInfo ) return;
1514 for (i = 0; i < psInfo->nPages; i++)
1515 {
1516 /* set the specified page as clean */
1517 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1518 psInfo->proppage[i].isDirty = FALSE;
1519
1520 /* look to see if there's any dirty pages */
1521 if (psInfo->proppage[i].isDirty)
1522 noPageDirty = FALSE;
1523 }
1524
1525 /*
1526 * Disable Apply button.
1527 */
1528 if (noPageDirty)
1529 EnableWindow(hwndApplyBtn, FALSE);
1530}
1531
1532/******************************************************************************
1533 * PROPSHEET_PressButton
1534 */
1535static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1536{
1537 switch (buttonID)
1538 {
1539 case PSBTN_APPLYNOW:
1540 PROPSHEET_Apply(hwndDlg, 0);
1541 break;
1542
1543 case PSBTN_BACK:
1544 PROPSHEET_Back(hwndDlg);
1545 break;
1546
1547 case PSBTN_CANCEL:
1548 PROPSHEET_Cancel(hwndDlg, 0);
1549 break;
1550
1551 case PSBTN_FINISH:
1552 PROPSHEET_Finish(hwndDlg);
1553 break;
1554
1555 case PSBTN_HELP:
1556 PROPSHEET_Help(hwndDlg);
1557 break;
1558
1559 case PSBTN_NEXT:
1560 PROPSHEET_Next(hwndDlg);
1561 break;
1562
1563 case PSBTN_OK:
1564 PROPSHEET_Apply(hwndDlg, 1);
1565 break;
1566
1567 //default:
1568 // FIXME("Invalid button index %d\n", buttonID);
1569 }
1570}
1571
1572/*************************************************************************
1573 * BOOL PROPSHEET_CanSetCurSel [Internal]
1574 *
1575 * Test weither the current page can be changed by sending a PSN_KILLACTIVE
1576 *
1577 * PARAMS
1578 * hwndDlg [I] handle to a Dialog hWnd
1579 *
1580 * RETURNS
1581 * TRUE if Current Selection can change
1582 *
1583 * NOTES
1584 */
1585static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1586{
1587 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1588 PropSheetInfoStr);
1589 HWND hwndPage;
1590 PSHNOTIFY psn;
1591
1592 if (!psInfo)
1593 return FALSE;
1594
1595 if (psInfo->active_page < 0)
1596 return TRUE;
1597
1598 /*
1599 * Notify the current page.
1600 */
1601 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1602 psn.hdr.code = PSN_KILLACTIVE;
1603 psn.hdr.hwndFrom = hwndDlg;
1604 psn.hdr.idFrom = 0;
1605 psn.lParam = 0;
1606
1607 return !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1608}
1609
1610/******************************************************************************
1611 * PROPSHEET_SetCurSel
1612 */
1613static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1614 int index,
1615 HPROPSHEETPAGE hpage)
1616{
1617 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1618 PropSheetInfoStr);
1619 HWND hwndPage;
1620 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1621 int i;
1622
1623 /* hpage takes precedence over index */
1624 if (hpage != NULL)
1625 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1626
1627 again:
1628
1629 if (index < 0 || index >= psInfo->nPages)
1630 {
1631 //TRACE("Could not find page to select!\n");
1632 return FALSE;
1633 }
1634
1635 hwndPage = psInfo->proppage[index].hwndPage;
1636
1637 /*
1638 * Notify the new page if it's already created.
1639 * If not it will get created and notified in PROPSHEET_ShowPage.
1640 */
1641 if (hwndPage)
1642 {
1643 LRESULT result;
1644 PSHNOTIFY psn;
1645
1646 psn.hdr.code = PSN_SETACTIVE;
1647 psn.hdr.hwndFrom = hwndDlg;
1648 psn.hdr.idFrom = 0;
1649 psn.lParam = 0;
1650
1651 result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1652
1653 /* Fixme: If user doesn't accept new selection shall we send
1654 * notifications to the page specified by user, or select it
1655 * silently?
1656 */
1657 if (result == -1)
1658 {
1659 if (index != psInfo->active_page)
1660 {
1661 if (index > psInfo->active_page)
1662 index++;
1663 else if (index < psInfo->active_page)
1664 index--;
1665
1666 goto again;
1667 }
1668 }
1669 else if (result != 0)
1670 {
1671 index = PROPSHEET_FindPageByResId(psInfo, result);
1672 goto again;
1673 }
1674 }
1675
1676 /*
1677 * Display the new page.
1678 */
1679 i = PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1680
1681 /* 0 - function is failed,
1682 * -1 - some other page is activated (via recursive call to SetCurSel) -
1683 * exit now to avoid overwriting state of help button.
1684 */
1685 if (i <= 0)
1686 return (BOOL)i;
1687
1688 if (psInfo->proppage[index].hasHelp)
1689 EnableWindow(hwndHelp, TRUE);
1690 else
1691 EnableWindow(hwndHelp, FALSE);
1692
1693 return TRUE;
1694}
1695
1696/******************************************************************************
1697 * PROPSHEET_SetTitleA
1698 */
1699static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1700{
1701 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1702 char szTitle[256];
1703
1704 if (HIWORD(lpszText) == 0) {
1705 if (!LoadStringA(psInfo->ppshheader->hInstance,
1706 LOWORD(lpszText), szTitle, sizeof(szTitle)-1))
1707 return;
1708 lpszText = szTitle;
1709 }
1710 if (dwStyle & PSH_PROPTITLE)
1711 {
1712 char* dest;
1713 int lentitle = strlen(lpszText);
1714 int lenprop = strlen(psInfo->strPropertiesFor);
1715
1716 dest = (CHAR*)COMCTL32_Alloc(lentitle + lenprop + 1);
1717 strcpy(dest, psInfo->strPropertiesFor);
1718 strcat(dest, lpszText);
1719
1720 SetWindowTextA(hwndDlg, dest);
1721 COMCTL32_Free(dest);
1722 }
1723 else
1724 SetWindowTextA(hwndDlg, lpszText);
1725}
1726
1727/******************************************************************************
1728 * PROPSHEET_SetFinishTextA
1729 */
1730static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1731{
1732 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1733
1734 /* Set text, show and enable the Finish button */
1735 SetWindowTextA(hwndButton, lpszText);
1736 ShowWindow(hwndButton, SW_SHOW);
1737 EnableWindow(hwndButton, TRUE);
1738
1739 /* Make it default pushbutton */
1740 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1741
1742 /* Hide Back button */
1743 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1744 ShowWindow(hwndButton, SW_HIDE);
1745
1746 /* Hide Next button */
1747 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1748 ShowWindow(hwndButton, SW_HIDE);
1749}
1750
1751/******************************************************************************
1752 * PROPSHEET_QuerySiblings
1753 */
1754static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1755 WPARAM wParam, LPARAM lParam)
1756{
1757 int i = 0;
1758 HWND hwndPage;
1759 LRESULT msgResult = 0;
1760 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1761 PropSheetInfoStr);
1762
1763 while ((i < psInfo->nPages) && (msgResult == 0))
1764 {
1765 hwndPage = psInfo->proppage[i].hwndPage;
1766 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1767 i++;
1768 }
1769
1770 return msgResult;
1771}
1772
1773
1774/******************************************************************************
1775 * PROPSHEET_AddPage
1776 */
1777static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1778 HPROPSHEETPAGE hpage)
1779{
1780 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1781 PropSheetInfoStr);
1782 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1783 TCITEMA item;
1784 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1785 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1786
1787 /*
1788 * Allocate and fill in a new PropPageInfo entry.
1789 */
1790 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1791 sizeof(PropPageInfo) *
1792 (psInfo->nPages + 1));
1793
1794 PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages);
1795 psInfo->proppage[psInfo->nPages].hpage = hpage;
1796
1797 if (ppsp->dwFlags & PSP_PREMATURE)
1798 {
1799 /* Create the page but don't show it */
1800 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, (PROPSHEETPAGEA*)ppsp);
1801 }
1802
1803 /*
1804 * Add a new tab to the tab control.
1805 */
1806 item.mask = TCIF_TEXT;
1807 item.pszText = tabtext;
1808 item.cchTextMax = MAX_TABTEXT_LENGTH;
1809
1810 WideCharToMultiByte(CP_ACP, 0,
1811 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1812 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1813
1814 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1815 (LPARAM)&item);
1816
1817 psInfo->nPages++;
1818
1819 /* If it is the only page - show it */
1820 if(psInfo->nPages == 1)
1821 PROPSHEET_ShowPage(hwndDlg, 0, psInfo);
1822
1823 return TRUE;
1824}
1825
1826/******************************************************************************
1827 * PROPSHEET_RemovePage
1828 */
1829static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1830 int index,
1831 HPROPSHEETPAGE hpage)
1832{
1833 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1834 PropSheetInfoStr);
1835 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1836 PropPageInfo* oldPages;
1837
1838 if (!psInfo) {
1839 return FALSE;
1840 }
1841 oldPages = psInfo->proppage;
1842 /*
1843 * hpage takes precedence over index.
1844 */
1845 if (hpage != 0)
1846 {
1847 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1848 }
1849
1850 /* Make shure that index is within range */
1851 if (index < 0 || index >= psInfo->nPages)
1852 {
1853 //TRACE("Could not find page to remove!\n");
1854 return FALSE;
1855 }
1856
1857 //TRACE("total pages %d removing page %d active page %d\n",
1858 // psInfo->nPages, index, psInfo->active_page);
1859 /*
1860 * Check if we're removing the active page.
1861 */
1862 if (index == psInfo->active_page)
1863 {
1864 if (psInfo->nPages > 1)
1865 {
1866 if (index > 0)
1867 {
1868 /* activate previous page */
1869 PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1870 }
1871 else
1872 {
1873 /* activate the next page */
1874 PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1875 psInfo->active_page = index;
1876 }
1877 }
1878 else
1879 {
1880 psInfo->active_page = -1;
1881 if (!psInfo->isModeless)
1882 {
1883 EndDialog(hwndDlg, FALSE);
1884 return TRUE;
1885 }
1886 }
1887 }
1888 else if (index < psInfo->active_page)
1889 psInfo->active_page--;
1890
1891 /* Destroy page dialog window */
1892 DestroyWindow(psInfo->proppage[index].hwndPage);
1893
1894 /* Free page resources */
1895 if(psInfo->proppage[index].hpage)
1896 {
1897 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[index].hpage;
1898
1899 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
1900 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
1901
1902 DestroyPropertySheetPage(psInfo->proppage[index].hpage);
1903 }
1904
1905 /* Remove the tab */
1906 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1907
1908 psInfo->nPages--;
1909 psInfo->proppage = (PropPageInfo*)COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1910
1911 if (index > 0)
1912 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1913
1914 if (index < psInfo->nPages)
1915 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1916 (psInfo->nPages - index) * sizeof(PropPageInfo));
1917
1918 COMCTL32_Free(oldPages);
1919
1920 return FALSE;
1921}
1922
1923/******************************************************************************
1924 * PROPSHEET_SetWizButtons
1925 *
1926 * This code will work if (and assumes that) the Next button is on top of the
1927 * Finish button. ie. Finish comes after Next in the Z order.
1928 * This means make sure the dialog template reflects this.
1929 *
1930 */
1931static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1932{
1933 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1934 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1935 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1936
1937 //TRACE("%ld\n", dwFlags);
1938
1939 EnableWindow(hwndBack, FALSE);
1940 EnableWindow(hwndNext, FALSE);
1941 EnableWindow(hwndFinish, FALSE);
1942
1943 if (dwFlags & PSWIZB_BACK)
1944 EnableWindow(hwndBack, TRUE);
1945
1946 if (dwFlags & PSWIZB_NEXT)
1947 {
1948 /* Hide the Finish button */
1949 ShowWindow(hwndFinish, SW_HIDE);
1950
1951 /* Show and enable the Next button */
1952 ShowWindow(hwndNext, SW_SHOW);
1953 EnableWindow(hwndNext, TRUE);
1954
1955 /* Set the Next button as the default pushbutton */
1956 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1957 }
1958
1959 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1960 {
1961 /* Hide the Next button */
1962 ShowWindow(hwndNext, SW_HIDE);
1963
1964 /* Show the Finish button */
1965 ShowWindow(hwndFinish, SW_SHOW);
1966
1967 if (dwFlags & PSWIZB_FINISH)
1968 EnableWindow(hwndFinish, TRUE);
1969
1970 /* Set the Finish button as the default pushbutton */
1971 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1972 }
1973}
1974
1975/******************************************************************************
1976 * PROPSHEET_GetPageIndex
1977 *
1978 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1979 * the array of PropPageInfo.
1980 */
1981static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1982{
1983 BOOL found = FALSE;
1984 int index = 0;
1985
1986 while ((index < psInfo->nPages) && (found == FALSE))
1987 {
1988 if (psInfo->proppage[index].hpage == hpage)
1989 found = TRUE;
1990 else
1991 index++;
1992 }
1993
1994 if (found == FALSE)
1995 index = -1;
1996
1997 return index;
1998}
1999
2000/******************************************************************************
2001 * PROPSHEET_CleanUp
2002 */
2003static void PROPSHEET_CleanUp(HWND hwndDlg)
2004{
2005 int i;
2006 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
2007 PropSheetInfoStr);
2008
2009 //TRACE("\n");
2010 if (HIWORD(psInfo->ppshheader->pszCaption))
2011 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader->pszCaption);
2012
2013 COMCTL32_Free((LPVOID)psInfo->ppshheader);
2014
2015 for (i = 0; i < psInfo->nPages; i++)
2016 {
2017 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
2018
2019 if(psInfo->proppage[i].hwndPage)
2020 DestroyWindow(psInfo->proppage[i].hwndPage);
2021
2022 if(psp)
2023 {
2024 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
2025 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);
2026
2027 DestroyPropertySheetPage(psInfo->proppage[i].hpage);
2028 }
2029 }
2030
2031 COMCTL32_Free(psInfo->proppage);
2032 COMCTL32_Free(psInfo->strPropertiesFor);
2033 ImageList_Destroy(psInfo->hImageList);
2034
2035 GlobalFree((HGLOBAL)psInfo);
2036}
2037
2038/******************************************************************************
2039 * PropertySheetA (COMCTL32.84)(COMCTL32.83)
2040 */
2041INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
2042{
2043 int bRet = 0;
2044 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
2045 sizeof(PropSheetInfo));
2046 int i;
2047 BYTE* pByte;
2048
2049 dprintf(("COMCTL32: PropertySheetA"));
2050
2051 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
2052
2053 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
2054 lppsh->nPages);
2055 pByte = (BYTE*) psInfo->ppshheader->ppsp;
2056
2057 for (i = 0; i < lppsh->nPages; i++)
2058 {
2059 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
2060 psInfo->proppage[i].hpage = psInfo->ppshheader->phpage[i];
2061 else
2062 {
2063 psInfo->proppage[i].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
2064 pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;
2065 }
2066
2067 PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage,
2068 psInfo, i);
2069 }
2070
2071 bRet = PROPSHEET_CreateDialog(psInfo);
2072
2073 return bRet;
2074}
2075
2076/******************************************************************************
2077 * PropertySheet32W (COMCTL32.85)
2078 */
2079INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
2080{
2081 dprintf(("COMCTL32: PropertySheetW - empty stub!"));
2082
2083 return -1;
2084}
2085
2086/******************************************************************************
2087 * CreatePropertySheetPageA (COMCTL32.19)(COMCTL32.18)
2088 */
2089HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
2090 LPCPROPSHEETPAGEA lpPropSheetPage)
2091{
2092 PROPSHEETPAGEA* ppsp = (PROPSHEETPAGEA*)COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
2093
2094 dprintf(("COMCTL32: CreatePropertySheetPageA"));
2095
2096 *ppsp = *lpPropSheetPage;
2097
2098 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->pszTemplate ) )
2099 ppsp->pszTemplate = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszTemplate );
2100
2101 if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->pszIcon ) )
2102 ppsp->pszIcon = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszIcon );
2103
2104
2105 if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
2106 ppsp->pszTitle = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszTitle );
2107 else if ( !(ppsp->dwFlags & PSP_USETITLE) )
2108 ppsp->pszTitle = NULL;
2109
2110 return (HPROPSHEETPAGE)ppsp;
2111}
2112
2113/******************************************************************************
2114 * CreatePropertySheetPageW (COMCTL32.20)
2115 */
2116HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
2117{
2118 dprintf(("COMCTL32: CreatePropertySheetPageW - empty stub!"));
2119
2120 return 0;
2121}
2122
2123/******************************************************************************
2124 * DestroyPropertySheetPage (COMCTL32.24)
2125 */
2126BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
2127{
2128 PROPSHEETPAGEA *psp = (PROPSHEETPAGEA *)hPropPage;
2129
2130 dprintf(("COMCTL32: DestroyPropertySheetPage"));
2131
2132 if (!psp)
2133 return FALSE;
2134
2135 if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->pszTemplate ) )
2136 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTemplate);
2137
2138 if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->pszIcon ) )
2139 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszIcon);
2140
2141 if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
2142 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);
2143
2144 COMCTL32_Free(hPropPage);
2145
2146 return TRUE;
2147}
2148
2149/******************************************************************************
2150 * PROPSHEET_IsDialogMessage
2151 */
2152static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
2153{
2154 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, PropSheetInfoStr);
2155
2156 if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
2157 return FALSE;
2158
2159 if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
2160 {
2161 int new_page = 0;
2162 INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
2163
2164 if (!(dlgCode & DLGC_WANTMESSAGE))
2165 {
2166 switch (lpMsg->wParam)
2167 {
2168 case VK_TAB:
2169 if (GetKeyState(VK_SHIFT) & 0x8000)
2170 new_page = -1;
2171 else
2172 new_page = 1;
2173 break;
2174
2175 case VK_NEXT: new_page = 1; break;
2176 case VK_PRIOR: new_page = -1; break;
2177 }
2178 }
2179
2180 if (new_page)
2181 {
2182 if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
2183 {
2184 new_page += psInfo->active_page;
2185
2186 if (new_page < 0)
2187 new_page = psInfo->nPages - 1;
2188 else if (new_page >= psInfo->nPages)
2189 new_page = 0;
2190
2191 PROPSHEET_SetCurSel(hwnd, new_page, 0);
2192 }
2193
2194 return TRUE;
2195 }
2196 }
2197
2198 return IsDialogMessageA(hwnd, lpMsg);
2199}
2200
2201/******************************************************************************
2202 * PROPSHEET_DialogProc
2203 */
2204BOOL WINAPI
2205PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2206{
2207 switch (uMsg)
2208 {
2209 case WM_INITDIALOG:
2210 {
2211 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
2212 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
2213 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2214 LPCPROPSHEETPAGEA ppshpage;
2215 int idx;
2216
2217 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
2218
2219 /*
2220 * Small icon in the title bar.
2221 */
2222 if ((psInfo->ppshheader->dwFlags & PSH_USEICONID) ||
2223 (psInfo->ppshheader->dwFlags & PSH_USEHICON))
2224 {
2225 HICON hIcon;
2226 int icon_cx = GetSystemMetrics(SM_CXSMICON);
2227 int icon_cy = GetSystemMetrics(SM_CYSMICON);
2228
2229 if (psInfo->ppshheader->dwFlags & PSH_USEICONID)
2230 hIcon = LoadImageA(psInfo->ppshheader->hInstance,
2231 psInfo->ppshheader->pszIcon,
2232 IMAGE_ICON,
2233 icon_cx, icon_cy,
2234 LR_DEFAULTCOLOR);
2235 else
2236 hIcon = psInfo->ppshheader->hIcon;
2237
2238 SendMessageA(hwnd, WM_SETICON, 0, hIcon);
2239 }
2240
2241 if (psInfo->ppshheader->dwFlags & PSH_USEHICON)
2242 SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader->hIcon);
2243
2244 psInfo->strPropertiesFor = strCaption;
2245
2246 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
2247
2248 PROPSHEET_CreateTabControl(hwnd, psInfo);
2249
2250 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
2251 {
2252 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
2253 {
2254 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
2255 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
2256 }
2257 }
2258 else
2259 {
2260 if (PROPSHEET_SizeMismatch(hwnd, psInfo))
2261 {
2262 PROPSHEET_AdjustSize(hwnd, psInfo);
2263 PROPSHEET_AdjustButtons(hwnd, psInfo);
2264 }
2265 }
2266
2267 if (psInfo->useCallback)
2268 (*(psInfo->ppshheader->pfnCallback))(hwnd,
2269 PSCB_INITIALIZED, (LPARAM)0);
2270
2271 idx = psInfo->active_page;
2272 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[idx].hpage;
2273 psInfo->active_page = -1;
2274
2275 PROPSHEET_SetCurSel(hwnd, idx, psInfo->proppage[idx].hpage);
2276
2277 if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
2278 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
2279
2280 if (!HIWORD(psInfo->ppshheader->pszCaption) &&
2281 psInfo->ppshheader->hInstance)
2282 {
2283 char szText[256];
2284
2285 if (LoadStringA(psInfo->ppshheader->hInstance,
2286 (UINT)psInfo->ppshheader->pszCaption, szText, 255))
2287 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader->dwFlags, szText);
2288 }
2289 else
2290 {
2291 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader->dwFlags,
2292 psInfo->ppshheader->pszCaption);
2293 }
2294
2295 return TRUE;
2296 }
2297
2298 case WM_DESTROY:
2299 PROPSHEET_CleanUp(hwnd);
2300 return TRUE;
2301
2302 case WM_CLOSE:
2303 PROPSHEET_Cancel(hwnd, 1);
2304 return TRUE;
2305
2306 case WM_COMMAND:
2307 {
2308 WORD wID = LOWORD(wParam);
2309 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,PropSheetInfoStr);
2310
2311 switch (wID)
2312 {
2313 case IDOK:
2314 case IDC_APPLY_BUTTON:
2315 PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0);
2316 break;
2317
2318 case IDC_BACK_BUTTON:
2319 PROPSHEET_Back(hwnd);
2320 break;
2321
2322 case IDC_NEXT_BUTTON:
2323 PROPSHEET_Next(hwnd);
2324 break;
2325
2326 case IDC_FINISH_BUTTON:
2327 PROPSHEET_Finish(hwnd);
2328 break;
2329
2330 case IDCANCEL:
2331 PROPSHEET_Cancel(hwnd, 0);
2332 break;
2333
2334 case IDHELP:
2335 PROPSHEET_Help(hwnd);
2336 break;
2337
2338 default:
2339 if(psInfo->active_page != -1)
2340 {
2341 return SendMessageA(psInfo->proppage[psInfo->active_page].hwndPage,
2342 uMsg, wParam, lParam);
2343 }
2344 }
2345
2346 return TRUE;
2347 }
2348
2349 case WM_NOTIFY:
2350 {
2351 NMHDR* pnmh = (LPNMHDR) lParam;
2352
2353 if (pnmh->code == TCN_SELCHANGE)
2354 {
2355 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
2356 PROPSHEET_SetCurSel(hwnd, index, 0);
2357 }
2358
2359 if(pnmh->code == TCN_SELCHANGING)
2360 {
2361 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
2362 SetWindowLongA(hwnd, DWL_MSGRESULT, !bRet);
2363 return TRUE;
2364 }
2365
2366
2367 return 0;
2368 }
2369
2370 case PSM_GETCURRENTPAGEHWND:
2371 {
2372 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2373 PropSheetInfoStr);
2374 HWND hwndPage = 0;
2375
2376 if (psInfo->activeValid && psInfo->active_page != -1)
2377 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
2378
2379 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
2380
2381 return TRUE;
2382 }
2383
2384 case PSM_CHANGED:
2385 PROPSHEET_Changed(hwnd, (HWND)wParam);
2386 return TRUE;
2387
2388 case PSM_UNCHANGED:
2389 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
2390 return TRUE;
2391
2392 case PSM_GETTABCONTROL:
2393 {
2394 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2395
2396 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
2397
2398 return TRUE;
2399 }
2400
2401 case PSM_SETCURSEL:
2402 {
2403 BOOL msgResult;
2404
2405 msgResult = PROPSHEET_CanSetCurSel(hwnd);
2406 if(msgResult != FALSE)
2407 {
2408 msgResult = PROPSHEET_SetCurSel(hwnd,
2409 (int)wParam,
2410 (HPROPSHEETPAGE)lParam);
2411 }
2412
2413 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2414
2415 return TRUE;
2416 }
2417
2418 case PSM_CANCELTOCLOSE:
2419 {
2420 char buf[MAX_BUTTONTEXT_LENGTH];
2421 HWND hwndOK = GetDlgItem(hwnd, IDOK);
2422 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2423
2424 EnableWindow(hwndCancel, FALSE);
2425 if (LoadStringA(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
2426 SetWindowTextA(hwndOK, buf);
2427
2428 return FALSE;
2429 }
2430
2431 case PSM_RESTARTWINDOWS:
2432 {
2433 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2434 PropSheetInfoStr);
2435
2436 psInfo->restartWindows = TRUE;
2437 return TRUE;
2438 }
2439
2440 case PSM_REBOOTSYSTEM:
2441 {
2442 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2443 PropSheetInfoStr);
2444
2445 psInfo->rebootSystem = TRUE;
2446 return TRUE;
2447 }
2448
2449 case PSM_SETTITLEA:
2450 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2451 return TRUE;
2452
2453 case PSM_APPLY:
2454 {
2455 BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
2456
2457 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2458
2459 return TRUE;
2460 }
2461
2462 case PSM_QUERYSIBLINGS:
2463 {
2464 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2465
2466 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2467
2468 return TRUE;
2469 }
2470
2471 case PSM_ADDPAGE:
2472 {
2473 /*
2474 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2475 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2476 * on success or FALSE otherwise, as specified on MSDN Online.
2477 * Also see the MFC code for
2478 * CPropertySheet::AddPage(CPropertyPage* pPage).
2479 */
2480
2481 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2482
2483 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2484
2485 return TRUE;
2486 }
2487
2488 case PSM_REMOVEPAGE:
2489 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2490 return TRUE;
2491
2492 case PSM_ISDIALOGMESSAGE:
2493 {
2494 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
2495 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2496 return TRUE;
2497 }
2498
2499 case PSM_PRESSBUTTON:
2500 PROPSHEET_PressButton(hwnd, (int)wParam);
2501 return TRUE;
2502
2503 case PSM_SETFINISHTEXTA:
2504 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2505 return TRUE;
2506
2507 case PSM_SETWIZBUTTONS:
2508 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2509 return TRUE;
2510
2511 case PSM_SETTITLEW:
2512 //FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2513 return 0;
2514 case PSM_SETCURSELID:
2515 //FIXME("Unimplemented msg PSM_SETCURSELID\n");
2516 return 0;
2517 case PSM_SETFINISHTEXTW:
2518 //FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");
2519 return 0;
2520
2521 default:
2522 return FALSE;
2523 }
2524}
2525
Note: See TracBrowser for help on using the repository browser.