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

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

Corel WINE 20000807 changes

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