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

Last change on this file since 3993 was 3993, checked in by sandervl, 25 years ago

Updates for fake system dll headers

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