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

Last change on this file since 2126 was 2126, checked in by achimha, 26 years ago

WINE 991212 updates - treeview missing

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