source: trunk/src/comctl32/propsheet.c@ 2820

Last change on this file since 2820 was 2820, checked in by cbratschi, 26 years ago

* empty log message *

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