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

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

merged with Corel WINE 20000513, added new DPA_* functions

File size: 63.7 KB
Line 
1/* $Id: propsheet.cpp,v 1.4 2000-05-22 17:25:10 cbratschi Exp $ */
2/*
3 * Property Sheets
4 *
5 * Copyright 1998 Francis Beaudet
6 * Copyright 1999 Thuy Nguyen
7 * Copyright 1999 Achim Hasenmueller
8 * Copyright 1999 Christoph Bratschi
9 *
10 * TODO:
11 * - Tab order
12 * - Unicode property sheets
13 */
14
15/*
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/******************************************************************************
1071 * PROPSHEET_ShowPage
1072 *
1073 * Displays or creates the specified page.
1074 */
1075static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1076{
1077 RECT rc;
1078 PADDING_INFO padding;
1079 UINT pageWidth,pageHeight;
1080
1081 if (index == psInfo->active_page)
1082 {
1083 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1084 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1085 return TRUE;
1086 }
1087
1088 if (psInfo->active_page != -1)
1089 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1090
1091 if (psInfo->proppage[index].hwndPage == 0)
1092 {
1093 LPCPROPSHEETPAGEA ppshpage;
1094 PSHNOTIFY psn;
1095
1096 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1097 PROPSHEET_CreatePage(hwndDlg, index, psInfo, (PROPSHEETPAGEA*)ppshpage);
1098
1099 psn.hdr.hwndFrom = hwndDlg;
1100 psn.hdr.code = PSN_SETACTIVE;
1101 psn.hdr.idFrom = 0;
1102 psn.lParam = 0;
1103
1104 /* Send the notification before showing the page. */
1105 SendMessageA(psInfo->proppage[index].hwndPage,
1106 WM_NOTIFY, 0, (LPARAM) &psn);
1107
1108 /*
1109 * TODO: check return value.
1110 */
1111 }
1112
1113 if (psInfo->active_page != -1)
1114 {
1115 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1116 }
1117
1118 /* HACK: Sometimes a property page doesn't get displayed at the right place inside the
1119 * property sheet. This will force the window to be placed at the proper location
1120 * before it is displayed.
1121 */
1122 rc.left = psInfo->x;
1123 rc.top = psInfo->y;
1124 rc.right = psInfo->width;
1125 rc.bottom = psInfo->height;
1126
1127 MapDialogRect(hwndDlg, &rc);
1128
1129 pageWidth = rc.right - rc.left;
1130 pageHeight = rc.bottom - rc.top;
1131
1132 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
1133 padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
1134 else
1135 {
1136 /*
1137 * Ask the Tab control to fit this page in.
1138 */
1139
1140 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1141 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
1142 padding = PROPSHEET_GetPaddingInfo(hwndDlg);
1143 }
1144
1145 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP,
1146 rc.left + padding.x,
1147 rc.top + padding.y,
1148 pageWidth, pageHeight, SWP_SHOWWINDOW);
1149
1150 if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
1151 {
1152 HWND hwndTabCtrl;
1153
1154 /* Synchronize current selection with tab control */
1155 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1156 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1157 }
1158
1159 psInfo->active_page = index;
1160 psInfo->activeValid = TRUE;
1161
1162 return TRUE;
1163}
1164
1165/******************************************************************************
1166 * PROPSHEET_Back
1167 */
1168static BOOL PROPSHEET_Back(HWND hwndDlg)
1169{
1170 BOOL res;
1171 PSHNOTIFY psn;
1172 HWND hwndPage;
1173 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1174 PropSheetInfoStr);
1175
1176 if (psInfo->active_page < 0)
1177 return FALSE;
1178
1179 psn.hdr.code = PSN_WIZBACK;
1180 psn.hdr.hwndFrom = hwndDlg;
1181 psn.hdr.idFrom = 0;
1182 psn.lParam = 0;
1183
1184 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1185
1186 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) == -1)
1187 return FALSE;
1188
1189 if (psInfo->active_page > 0)
1190 {
1191 res = PROPSHEET_CanSetCurSel(hwndDlg);
1192 if(res != FALSE)
1193 {
1194 res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, 0);
1195 }
1196 }
1197
1198 return TRUE;
1199}
1200
1201/******************************************************************************
1202 * PROPSHEET_Next
1203 */
1204static BOOL PROPSHEET_Next(HWND hwndDlg)
1205{
1206 PSHNOTIFY psn;
1207 HWND hwndPage;
1208 LRESULT msgResult = 0;
1209 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1210 PropSheetInfoStr);
1211
1212 if (psInfo->active_page < 0)
1213 return FALSE;
1214
1215 psn.hdr.code = PSN_WIZNEXT;
1216 psn.hdr.hwndFrom = hwndDlg;
1217 psn.hdr.idFrom = 0;
1218 psn.lParam = 0;
1219
1220 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1221
1222 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1223
1224 //TRACE("msg result %ld\n", msgResult);
1225
1226 if (msgResult == -1)
1227 return FALSE;
1228
1229 if(PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1230 {
1231 PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 0);
1232 }
1233
1234 return TRUE;
1235}
1236
1237/******************************************************************************
1238 * PROPSHEET_Finish
1239 */
1240static BOOL PROPSHEET_Finish(HWND hwndDlg)
1241{
1242 PSHNOTIFY psn;
1243 HWND hwndPage;
1244 LRESULT msgResult = 0;
1245 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1246 PropSheetInfoStr);
1247
1248 if (psInfo->active_page < 0)
1249 return FALSE;
1250
1251 psn.hdr.code = PSN_WIZFINISH;
1252 psn.hdr.hwndFrom = hwndDlg;
1253 psn.hdr.idFrom = 0;
1254 psn.lParam = 0;
1255
1256 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1257
1258 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1259
1260 //TRACE("msg result %ld\n", msgResult);
1261
1262 if (msgResult != 0)
1263 return FALSE;
1264
1265 if (psInfo->isModeless)
1266 psInfo->activeValid = FALSE;
1267 else
1268 EndDialog(hwndDlg, TRUE);
1269
1270 return TRUE;
1271}
1272
1273/******************************************************************************
1274 * PROPSHEET_Apply
1275 */
1276static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1277{
1278 int i;
1279 HWND hwndPage;
1280 PSHNOTIFY psn;
1281 LRESULT msgResult;
1282 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1283 PropSheetInfoStr);
1284
1285 if (psInfo->active_page < 0)
1286 return FALSE;
1287
1288 psn.hdr.hwndFrom = hwndDlg;
1289 psn.hdr.idFrom = 0;
1290 psn.lParam = 0;
1291
1292
1293 /*
1294 * Send PSN_KILLACTIVE to the current page.
1295 */
1296 psn.hdr.code = PSN_KILLACTIVE;
1297
1298 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1299
1300 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1301 return FALSE;
1302
1303 /*
1304 * Send PSN_APPLY to all pages.
1305 */
1306 psn.hdr.code = PSN_APPLY;
1307 psn.lParam = lParam;
1308
1309 for (i = 0; i < psInfo->nPages; i++)
1310 {
1311 hwndPage = psInfo->proppage[i].hwndPage;
1312 if (hwndPage)
1313 {
1314 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1315 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1316 return FALSE;
1317 }
1318 }
1319
1320 EnableWindow(GetDlgItem(hwndDlg, IDC_APPLY_BUTTON), FALSE);
1321
1322 if(lParam)
1323 {
1324 int result = TRUE;
1325
1326 psInfo->activeValid = FALSE;
1327
1328 if (psInfo->restartWindows)
1329 result = ID_PSRESTARTWINDOWS;
1330
1331 /* reboot system takes precedence over restart windows */
1332 if (psInfo->rebootSystem)
1333 result = ID_PSREBOOTSYSTEM;
1334
1335 if (!psInfo->isModeless)
1336 EndDialog(hwndDlg, result);
1337 }
1338 else if(psInfo->active_page >= 0)
1339 {
1340 psn.hdr.code = PSN_SETACTIVE;
1341 psn.lParam = 0;
1342 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1343 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1344 }
1345
1346 return TRUE;
1347}
1348
1349/******************************************************************************
1350 * PROPSHEET_Cancel
1351 */
1352static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1353{
1354 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1355 PropSheetInfoStr);
1356 HWND hwndPage;
1357 PSHNOTIFY psn;
1358 int i;
1359
1360 if (psInfo->active_page < 0)
1361 return;
1362
1363 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1364 psn.hdr.code = PSN_QUERYCANCEL;
1365 psn.hdr.hwndFrom = hwndDlg;
1366 psn.hdr.idFrom = 0;
1367 psn.lParam = 0;
1368
1369 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1370 return;
1371
1372 psn.hdr.code = PSN_RESET;
1373 psn.lParam = lParam;
1374
1375 for (i = 0; i < psInfo->nPages; i++)
1376 {
1377 hwndPage = psInfo->proppage[i].hwndPage;
1378
1379 if (hwndPage)
1380 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1381 }
1382
1383 if (psInfo->isModeless)
1384 {
1385 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1386 psInfo->activeValid = FALSE;
1387 }
1388 else
1389 EndDialog(hwndDlg, FALSE);
1390}
1391
1392/******************************************************************************
1393 * PROPSHEET_Help
1394 */
1395static void PROPSHEET_Help(HWND hwndDlg)
1396{
1397 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1398 PropSheetInfoStr);
1399 HWND hwndPage;
1400 PSHNOTIFY psn;
1401
1402 if (psInfo->active_page < 0)
1403 return;
1404
1405 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1406 psn.hdr.code = PSN_HELP;
1407 psn.hdr.hwndFrom = hwndDlg;
1408 psn.hdr.idFrom = 0;
1409 psn.lParam = 0;
1410
1411 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1412}
1413
1414/******************************************************************************
1415 * PROPSHEET_Changed
1416 */
1417static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1418{
1419 int i;
1420 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1421 PropSheetInfoStr);
1422 if (!psInfo) return;
1423 /*
1424 * Set the dirty flag of this page.
1425 */
1426 for (i = 0; i < psInfo->nPages; i++)
1427 {
1428 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1429 psInfo->proppage[i].isDirty = TRUE;
1430 }
1431
1432 /*
1433 * Enable the Apply button.
1434 */
1435 if (psInfo->hasApply)
1436 {
1437 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1438
1439 EnableWindow(hwndApplyBtn, TRUE);
1440 }
1441}
1442
1443/******************************************************************************
1444 * PROPSHEET_UnChanged
1445 */
1446static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1447{
1448 int i;
1449 BOOL noPageDirty = TRUE;
1450 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1451 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1452 PropSheetInfoStr);
1453 if ( !psInfo ) return;
1454 for (i = 0; i < psInfo->nPages; i++)
1455 {
1456 /* set the specified page as clean */
1457 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1458 psInfo->proppage[i].isDirty = FALSE;
1459
1460 /* look to see if there's any dirty pages */
1461 if (psInfo->proppage[i].isDirty)
1462 noPageDirty = FALSE;
1463 }
1464
1465 /*
1466 * Disable Apply button.
1467 */
1468 if (noPageDirty)
1469 EnableWindow(hwndApplyBtn, FALSE);
1470}
1471
1472/******************************************************************************
1473 * PROPSHEET_PressButton
1474 */
1475static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1476{
1477 switch (buttonID)
1478 {
1479 case PSBTN_APPLYNOW:
1480 PROPSHEET_Apply(hwndDlg, 0);
1481 break;
1482
1483 case PSBTN_BACK:
1484 PROPSHEET_Back(hwndDlg);
1485 break;
1486
1487 case PSBTN_CANCEL:
1488 PROPSHEET_Cancel(hwndDlg, 0);
1489 break;
1490
1491 case PSBTN_FINISH:
1492 PROPSHEET_Finish(hwndDlg);
1493 break;
1494
1495 case PSBTN_HELP:
1496 PROPSHEET_Help(hwndDlg);
1497 break;
1498
1499 case PSBTN_NEXT:
1500 PROPSHEET_Next(hwndDlg);
1501 break;
1502
1503 case PSBTN_OK:
1504 PROPSHEET_Apply(hwndDlg, 1);
1505 break;
1506
1507 //default:
1508 // FIXME("Invalid button index %d\n", buttonID);
1509 }
1510}
1511
1512/*************************************************************************
1513 * BOOL PROPSHEET_CanSetCurSel [Internal]
1514 *
1515 * Test weither the current page can be changed by sending a PSN_KILLACTIVE
1516 *
1517 * PARAMS
1518 * hwndDlg [I] handle to a Dialog hWnd
1519 *
1520 * RETURNS
1521 * TRUE if Current Selection can change
1522 *
1523 * NOTES
1524 */
1525static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1526{
1527 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1528 PropSheetInfoStr);
1529 HWND hwndPage;
1530 PSHNOTIFY psn;
1531
1532 if (!psInfo)
1533 return FALSE;
1534
1535 if (psInfo->active_page < 0)
1536 return TRUE;
1537
1538 /*
1539 * Notify the current page.
1540 */
1541 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1542 psn.hdr.code = PSN_KILLACTIVE;
1543 psn.hdr.hwndFrom = hwndDlg;
1544 psn.hdr.idFrom = 0;
1545 psn.lParam = 0;
1546
1547 return !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1548}
1549
1550/******************************************************************************
1551 * PROPSHEET_SetCurSel
1552 */
1553static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1554 int index,
1555 HPROPSHEETPAGE hpage)
1556{
1557 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1558 PropSheetInfoStr);
1559 HWND hwndPage;
1560 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1561
1562 /* hpage takes precedence over index */
1563 if (hpage != NULL)
1564 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1565
1566 if (index < 0 || index >= psInfo->nPages)
1567 {
1568 //TRACE("Could not find page to select!\n");
1569 return FALSE;
1570 }
1571
1572 hwndPage = psInfo->proppage[index].hwndPage;
1573
1574 /*
1575 * Notify the new page if it's already created.
1576 * If not it will get created and notified in PROPSHEET_ShowPage.
1577 */
1578 if (hwndPage)
1579 {
1580 int result;
1581 PSHNOTIFY psn;
1582
1583 psn.hdr.code = PSN_SETACTIVE;
1584 psn.hdr.hwndFrom = hwndDlg;
1585 psn.hdr.idFrom = 0;
1586 psn.lParam = 0;
1587
1588 result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1589
1590 /*
1591 * TODO: check return value.
1592 */
1593 }
1594
1595 /*
1596 * Display the new page.
1597 */
1598 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1599
1600 if (psInfo->proppage[index].hasHelp)
1601 EnableWindow(hwndHelp, TRUE);
1602 else
1603 EnableWindow(hwndHelp, FALSE);
1604
1605 return TRUE;
1606}
1607
1608/******************************************************************************
1609 * PROPSHEET_SetTitleA
1610 */
1611static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1612{
1613 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1614 char szTitle[256];
1615
1616 if (HIWORD(lpszText) == 0) {
1617 if (!LoadStringA(psInfo->ppshheader->hInstance,
1618 LOWORD(lpszText), szTitle, sizeof(szTitle)-1))
1619 return;
1620 lpszText = szTitle;
1621 }
1622 if (dwStyle & PSH_PROPTITLE)
1623 {
1624 char* dest;
1625 int lentitle = strlen(lpszText);
1626 int lenprop = strlen(psInfo->strPropertiesFor);
1627
1628 dest = (CHAR*)COMCTL32_Alloc(lentitle + lenprop + 1);
1629 strcpy(dest, psInfo->strPropertiesFor);
1630 strcat(dest, lpszText);
1631
1632 SetWindowTextA(hwndDlg, dest);
1633 COMCTL32_Free(dest);
1634 }
1635 else
1636 SetWindowTextA(hwndDlg, lpszText);
1637}
1638
1639/******************************************************************************
1640 * PROPSHEET_SetFinishTextA
1641 */
1642static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1643{
1644 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1645
1646 /* Set text, show and enable the Finish button */
1647 SetWindowTextA(hwndButton, lpszText);
1648 ShowWindow(hwndButton, SW_SHOW);
1649 EnableWindow(hwndButton, TRUE);
1650
1651 /* Make it default pushbutton */
1652 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1653
1654 /* Hide Back button */
1655 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1656 ShowWindow(hwndButton, SW_HIDE);
1657
1658 /* Hide Next button */
1659 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1660 ShowWindow(hwndButton, SW_HIDE);
1661}
1662
1663/******************************************************************************
1664 * PROPSHEET_QuerySiblings
1665 */
1666static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1667 WPARAM wParam, LPARAM lParam)
1668{
1669 int i = 0;
1670 HWND hwndPage;
1671 LRESULT msgResult = 0;
1672 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1673 PropSheetInfoStr);
1674
1675 while ((i < psInfo->nPages) && (msgResult == 0))
1676 {
1677 hwndPage = psInfo->proppage[i].hwndPage;
1678 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1679 i++;
1680 }
1681
1682 return msgResult;
1683}
1684
1685
1686/******************************************************************************
1687 * PROPSHEET_AddPage
1688 */
1689static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1690 HPROPSHEETPAGE hpage)
1691{
1692 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1693 PropSheetInfoStr);
1694 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1695 TCITEMA item;
1696 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1697 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1698
1699 /*
1700 * Allocate and fill in a new PropPageInfo entry.
1701 */
1702 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1703 sizeof(PropPageInfo) *
1704 (psInfo->nPages + 1));
1705
1706 PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages);
1707 psInfo->proppage[psInfo->nPages].hpage = hpage;
1708
1709 if (ppsp->dwFlags & PSP_PREMATURE)
1710 {
1711 /* Create the page but don't show it */
1712 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, (PROPSHEETPAGEA*)ppsp);
1713 }
1714
1715 /*
1716 * Add a new tab to the tab control.
1717 */
1718 item.mask = TCIF_TEXT;
1719 item.pszText = tabtext;
1720 item.cchTextMax = MAX_TABTEXT_LENGTH;
1721
1722 WideCharToMultiByte(CP_ACP, 0,
1723 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1724 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1725
1726 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1727 (LPARAM)&item);
1728
1729 psInfo->nPages++;
1730
1731 /* If it is the only page - show it */
1732 if(psInfo->nPages == 1)
1733 PROPSHEET_ShowPage(hwndDlg, 0, psInfo);
1734
1735 return TRUE;
1736}
1737
1738/******************************************************************************
1739 * PROPSHEET_RemovePage
1740 */
1741static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1742 int index,
1743 HPROPSHEETPAGE hpage)
1744{
1745 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1746 PropSheetInfoStr);
1747 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1748 PropPageInfo* oldPages;
1749
1750 if (!psInfo) {
1751 return FALSE;
1752 }
1753 oldPages = psInfo->proppage;
1754 /*
1755 * hpage takes precedence over index.
1756 */
1757 if (hpage != 0)
1758 {
1759 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1760 }
1761
1762 /* Make shure that index is within range */
1763 if (index < 0 || index >= psInfo->nPages)
1764 {
1765 //TRACE("Could not find page to remove!\n");
1766 return FALSE;
1767 }
1768
1769 //TRACE("total pages %d removing page %d active page %d\n",
1770 // psInfo->nPages, index, psInfo->active_page);
1771 /*
1772 * Check if we're removing the active page.
1773 */
1774 if (index == psInfo->active_page)
1775 {
1776 if (psInfo->nPages > 1)
1777 {
1778 if (index > 0)
1779 {
1780 /* activate previous page */
1781 PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1782 }
1783 else
1784 {
1785 /* activate the next page */
1786 PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1787 }
1788 }
1789 else
1790 {
1791 psInfo->active_page = -1;
1792 if (!psInfo->isModeless)
1793 {
1794 EndDialog(hwndDlg, FALSE);
1795 return TRUE;
1796 }
1797 }
1798 }
1799 else if (index < psInfo->active_page)
1800 psInfo->active_page--;
1801
1802 /* Destroy page dialog window */
1803 DestroyWindow(psInfo->proppage[index].hwndPage);
1804
1805 /* Free page resources */
1806 if(psInfo->proppage[index].hpage)
1807 {
1808 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[index].hpage;
1809
1810 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
1811 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
1812
1813 DestroyPropertySheetPage(psInfo->proppage[index].hpage);
1814 }
1815
1816 /* Remove the tab */
1817 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1818
1819 psInfo->nPages--;
1820 psInfo->proppage = (PropPageInfo*)COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1821
1822 if (index > 0)
1823 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1824
1825 if (index < psInfo->nPages)
1826 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1827 (psInfo->nPages - index) * sizeof(PropPageInfo));
1828
1829 COMCTL32_Free(oldPages);
1830
1831 return FALSE;
1832}
1833
1834/******************************************************************************
1835 * PROPSHEET_SetWizButtons
1836 *
1837 * This code will work if (and assumes that) the Next button is on top of the
1838 * Finish button. ie. Finish comes after Next in the Z order.
1839 * This means make sure the dialog template reflects this.
1840 *
1841 */
1842static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1843{
1844 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1845 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1846 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1847
1848 //TRACE("%ld\n", dwFlags);
1849
1850 EnableWindow(hwndBack, FALSE);
1851 EnableWindow(hwndNext, FALSE);
1852 EnableWindow(hwndFinish, FALSE);
1853
1854 if (dwFlags & PSWIZB_BACK)
1855 EnableWindow(hwndBack, TRUE);
1856
1857 if (dwFlags & PSWIZB_NEXT)
1858 {
1859 /* Hide the Finish button */
1860 ShowWindow(hwndFinish, SW_HIDE);
1861
1862 /* Show and enable the Next button */
1863 ShowWindow(hwndNext, SW_SHOW);
1864 EnableWindow(hwndNext, TRUE);
1865
1866 /* Set the Next button as the default pushbutton */
1867 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1868 }
1869
1870 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1871 {
1872 /* Hide the Next button */
1873 ShowWindow(hwndNext, SW_HIDE);
1874
1875 /* Show the Finish button */
1876 ShowWindow(hwndFinish, SW_SHOW);
1877
1878 if (dwFlags & PSWIZB_FINISH)
1879 EnableWindow(hwndFinish, TRUE);
1880
1881 /* Set the Finish button as the default pushbutton */
1882 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1883 }
1884}
1885
1886/******************************************************************************
1887 * PROPSHEET_GetPageIndex
1888 *
1889 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1890 * the array of PropPageInfo.
1891 */
1892static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1893{
1894 BOOL found = FALSE;
1895 int index = 0;
1896
1897 while ((index < psInfo->nPages) && (found == FALSE))
1898 {
1899 if (psInfo->proppage[index].hpage == hpage)
1900 found = TRUE;
1901 else
1902 index++;
1903 }
1904
1905 if (found == FALSE)
1906 index = -1;
1907
1908 return index;
1909}
1910
1911/******************************************************************************
1912 * PROPSHEET_CleanUp
1913 */
1914static void PROPSHEET_CleanUp(HWND hwndDlg)
1915{
1916 int i;
1917 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1918 PropSheetInfoStr);
1919
1920 //TRACE("\n");
1921 if (HIWORD(psInfo->ppshheader->pszCaption))
1922 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader->pszCaption);
1923
1924 COMCTL32_Free((LPVOID)psInfo->ppshheader);
1925
1926 for (i = 0; i < psInfo->nPages; i++)
1927 {
1928 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
1929
1930 if(psInfo->proppage[i].hwndPage)
1931 DestroyWindow(psInfo->proppage[i].hwndPage);
1932
1933 if(psp)
1934 {
1935 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
1936 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);
1937
1938 DestroyPropertySheetPage(psInfo->proppage[i].hpage);
1939 }
1940 }
1941
1942 COMCTL32_Free(psInfo->proppage);
1943 COMCTL32_Free(psInfo->strPropertiesFor);
1944 ImageList_Destroy(psInfo->hImageList);
1945
1946 GlobalFree((HGLOBAL)psInfo);
1947}
1948
1949/******************************************************************************
1950 * PropertySheetA (COMCTL32.84)(COMCTL32.83)
1951 */
1952INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1953{
1954 int bRet = 0;
1955 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1956 sizeof(PropSheetInfo));
1957 int i;
1958 BYTE* pByte;
1959
1960 dprintf(("COMCTL32: PropertySheetA"));
1961
1962 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1963
1964 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1965 lppsh->nPages);
1966 pByte = (BYTE*) psInfo->ppshheader->ppsp;
1967
1968 for (i = 0; i < lppsh->nPages; i++)
1969 {
1970 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1971 psInfo->proppage[i].hpage = psInfo->ppshheader->phpage[i];
1972 else
1973 {
1974 psInfo->proppage[i].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
1975 pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;
1976 }
1977
1978 PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage,
1979 psInfo, i);
1980 }
1981
1982 bRet = PROPSHEET_CreateDialog(psInfo);
1983
1984 return bRet;
1985}
1986
1987/******************************************************************************
1988 * PropertySheet32W (COMCTL32.85)
1989 */
1990INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1991{
1992 dprintf(("COMCTL32: PropertySheetW - empty stub!"));
1993
1994 return -1;
1995}
1996
1997/******************************************************************************
1998 * CreatePropertySheetPageA (COMCTL32.19)(COMCTL32.18)
1999 */
2000HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
2001 LPCPROPSHEETPAGEA lpPropSheetPage)
2002{
2003 PROPSHEETPAGEA* ppsp = (PROPSHEETPAGEA*)COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
2004
2005 dprintf(("COMCTL32: CreatePropertySheetPageA"));
2006
2007 *ppsp = *lpPropSheetPage;
2008
2009 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->pszTemplate ) )
2010 ppsp->pszTemplate = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszTemplate );
2011
2012 if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->pszIcon ) )
2013 ppsp->pszIcon = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszIcon );
2014
2015
2016 if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
2017 ppsp->pszTitle = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszTitle );
2018 else if ( !(ppsp->dwFlags & PSP_USETITLE) )
2019 ppsp->pszTitle = NULL;
2020
2021 return (HPROPSHEETPAGE)ppsp;
2022}
2023
2024/******************************************************************************
2025 * CreatePropertySheetPageW (COMCTL32.20)
2026 */
2027HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
2028{
2029 dprintf(("COMCTL32: CreatePropertySheetPageW - empty stub!"));
2030
2031 return 0;
2032}
2033
2034/******************************************************************************
2035 * DestroyPropertySheetPage (COMCTL32.24)
2036 */
2037BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
2038{
2039 PROPSHEETPAGEA *psp = (PROPSHEETPAGEA *)hPropPage;
2040
2041 dprintf(("COMCTL32: DestroyPropertySheetPage"));
2042
2043 if (!psp)
2044 return FALSE;
2045
2046 if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->pszTemplate ) )
2047 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTemplate);
2048
2049 if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->pszIcon ) )
2050 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszIcon);
2051
2052 if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
2053 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);
2054
2055 COMCTL32_Free(hPropPage);
2056
2057 return TRUE;
2058}
2059
2060/******************************************************************************
2061 * PROPSHEET_IsDialogMessage
2062 */
2063static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
2064{
2065 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, PropSheetInfoStr);
2066
2067 if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
2068 return FALSE;
2069
2070 if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
2071 {
2072 int new_page = 0;
2073 INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
2074
2075 if (!(dlgCode & DLGC_WANTMESSAGE))
2076 {
2077 switch (lpMsg->wParam)
2078 {
2079 case VK_TAB:
2080 if (GetKeyState(VK_SHIFT) & 0x8000)
2081 new_page = -1;
2082 else
2083 new_page = 1;
2084 break;
2085
2086 case VK_NEXT: new_page = 1; break;
2087 case VK_PRIOR: new_page = -1; break;
2088 }
2089 }
2090
2091 if (new_page)
2092 {
2093 if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
2094 {
2095 new_page += psInfo->active_page;
2096
2097 if (new_page < 0)
2098 new_page = psInfo->nPages - 1;
2099 else if (new_page >= psInfo->nPages)
2100 new_page = 0;
2101
2102 PROPSHEET_SetCurSel(hwnd, new_page, 0);
2103 }
2104
2105 return TRUE;
2106 }
2107 }
2108
2109 return IsDialogMessageA(hwnd, lpMsg);
2110}
2111
2112/******************************************************************************
2113 * PROPSHEET_DialogProc
2114 */
2115BOOL WINAPI
2116PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2117{
2118 switch (uMsg)
2119 {
2120 case WM_INITDIALOG:
2121 {
2122 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
2123 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
2124 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2125 LPCPROPSHEETPAGEA ppshpage;
2126 int idx;
2127
2128 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
2129
2130 /*
2131 * Small icon in the title bar.
2132 */
2133 if ((psInfo->ppshheader->dwFlags & PSH_USEICONID) ||
2134 (psInfo->ppshheader->dwFlags & PSH_USEHICON))
2135 {
2136 HICON hIcon;
2137 int icon_cx = GetSystemMetrics(SM_CXSMICON);
2138 int icon_cy = GetSystemMetrics(SM_CYSMICON);
2139
2140 if (psInfo->ppshheader->dwFlags & PSH_USEICONID)
2141 hIcon = LoadImageA(psInfo->ppshheader->hInstance,
2142 psInfo->ppshheader->pszIcon,
2143 IMAGE_ICON,
2144 icon_cx, icon_cy,
2145 LR_DEFAULTCOLOR);
2146 else
2147 hIcon = psInfo->ppshheader->hIcon;
2148
2149 SendMessageA(hwnd, WM_SETICON, 0, hIcon);
2150 }
2151
2152 if (psInfo->ppshheader->dwFlags & PSH_USEHICON)
2153 SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader->hIcon);
2154
2155 psInfo->strPropertiesFor = strCaption;
2156
2157 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
2158
2159 PROPSHEET_CreateTabControl(hwnd, psInfo);
2160
2161 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
2162 {
2163 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
2164 {
2165 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
2166 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
2167 }
2168 }
2169 else
2170 {
2171 if (PROPSHEET_SizeMismatch(hwnd, psInfo))
2172 {
2173 PROPSHEET_AdjustSize(hwnd, psInfo);
2174 PROPSHEET_AdjustButtons(hwnd, psInfo);
2175 }
2176 }
2177
2178 if (psInfo->useCallback)
2179 (*(psInfo->ppshheader->pfnCallback))(hwnd,
2180 PSCB_INITIALIZED, (LPARAM)0);
2181
2182 idx = psInfo->active_page;
2183 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[idx].hpage;
2184 psInfo->active_page = -1;
2185
2186 PROPSHEET_SetCurSel(hwnd, idx, psInfo->proppage[idx].hpage);
2187
2188 if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
2189 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
2190
2191 if (!HIWORD(psInfo->ppshheader->pszCaption) &&
2192 psInfo->ppshheader->hInstance)
2193 {
2194 char szText[256];
2195
2196 if (LoadStringA(psInfo->ppshheader->hInstance,
2197 (UINT)psInfo->ppshheader->pszCaption, szText, 255))
2198 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader->dwFlags, szText);
2199 }
2200 else
2201 {
2202 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader->dwFlags,
2203 psInfo->ppshheader->pszCaption);
2204 }
2205
2206 return TRUE;
2207 }
2208
2209 case WM_DESTROY:
2210 PROPSHEET_CleanUp(hwnd);
2211 return TRUE;
2212
2213 case WM_CLOSE:
2214 PROPSHEET_Cancel(hwnd, 1);
2215 return TRUE;
2216
2217 case WM_COMMAND:
2218 {
2219 WORD wID = LOWORD(wParam);
2220 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,PropSheetInfoStr);
2221
2222 switch (wID)
2223 {
2224 case IDOK:
2225 case IDC_APPLY_BUTTON:
2226 PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0);
2227 break;
2228
2229 case IDC_BACK_BUTTON:
2230 PROPSHEET_Back(hwnd);
2231 break;
2232
2233 case IDC_NEXT_BUTTON:
2234 PROPSHEET_Next(hwnd);
2235 break;
2236
2237 case IDC_FINISH_BUTTON:
2238 PROPSHEET_Finish(hwnd);
2239 break;
2240
2241 case IDCANCEL:
2242 PROPSHEET_Cancel(hwnd, 0);
2243 break;
2244
2245 case IDHELP:
2246 PROPSHEET_Help(hwnd);
2247 break;
2248
2249 default:
2250 if(psInfo->active_page != -1)
2251 {
2252 return SendMessageA(psInfo->proppage[psInfo->active_page].hwndPage,
2253 uMsg, wParam, lParam);
2254 }
2255 }
2256
2257 return TRUE;
2258 }
2259
2260 case WM_NOTIFY:
2261 {
2262 NMHDR* pnmh = (LPNMHDR) lParam;
2263
2264 if (pnmh->code == TCN_SELCHANGE)
2265 {
2266 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
2267 PROPSHEET_SetCurSel(hwnd, index, 0);
2268 }
2269
2270 if(pnmh->code == TCN_SELCHANGING)
2271 {
2272 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
2273 SetWindowLongA(hwnd, DWL_MSGRESULT, !bRet);
2274 return TRUE;
2275 }
2276
2277
2278 return 0;
2279 }
2280
2281 case PSM_GETCURRENTPAGEHWND:
2282 {
2283 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2284 PropSheetInfoStr);
2285 HWND hwndPage = 0;
2286
2287 if (psInfo->activeValid && psInfo->active_page != -1)
2288 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
2289
2290 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
2291
2292 return TRUE;
2293 }
2294
2295 case PSM_CHANGED:
2296 PROPSHEET_Changed(hwnd, (HWND)wParam);
2297 return TRUE;
2298
2299 case PSM_UNCHANGED:
2300 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
2301 return TRUE;
2302
2303 case PSM_GETTABCONTROL:
2304 {
2305 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2306
2307 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
2308
2309 return TRUE;
2310 }
2311
2312 case PSM_SETCURSEL:
2313 {
2314 BOOL msgResult;
2315
2316 msgResult = PROPSHEET_CanSetCurSel(hwnd);
2317 if(msgResult != FALSE)
2318 {
2319 msgResult = PROPSHEET_SetCurSel(hwnd,
2320 (int)wParam,
2321 (HPROPSHEETPAGE)lParam);
2322 }
2323
2324 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2325
2326 return TRUE;
2327 }
2328
2329 case PSM_CANCELTOCLOSE:
2330 {
2331 char buf[MAX_BUTTONTEXT_LENGTH];
2332 HWND hwndOK = GetDlgItem(hwnd, IDOK);
2333 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2334
2335 EnableWindow(hwndCancel, FALSE);
2336 if (LoadStringA(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
2337 SetWindowTextA(hwndOK, buf);
2338
2339 return FALSE;
2340 }
2341
2342 case PSM_RESTARTWINDOWS:
2343 {
2344 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2345 PropSheetInfoStr);
2346
2347 psInfo->restartWindows = TRUE;
2348 return TRUE;
2349 }
2350
2351 case PSM_REBOOTSYSTEM:
2352 {
2353 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2354 PropSheetInfoStr);
2355
2356 psInfo->rebootSystem = TRUE;
2357 return TRUE;
2358 }
2359
2360 case PSM_SETTITLEA:
2361 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2362 return TRUE;
2363
2364 case PSM_APPLY:
2365 {
2366 BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
2367
2368 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2369
2370 return TRUE;
2371 }
2372
2373 case PSM_QUERYSIBLINGS:
2374 {
2375 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2376
2377 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2378
2379 return TRUE;
2380 }
2381
2382 case PSM_ADDPAGE:
2383 {
2384 /*
2385 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2386 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2387 * on success or FALSE otherwise, as specified on MSDN Online.
2388 * Also see the MFC code for
2389 * CPropertySheet::AddPage(CPropertyPage* pPage).
2390 */
2391
2392 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2393
2394 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2395
2396 return TRUE;
2397 }
2398
2399 case PSM_REMOVEPAGE:
2400 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2401 return TRUE;
2402
2403 case PSM_ISDIALOGMESSAGE:
2404 {
2405 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
2406 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2407 return TRUE;
2408 }
2409
2410 case PSM_PRESSBUTTON:
2411 PROPSHEET_PressButton(hwnd, (int)wParam);
2412 return TRUE;
2413
2414 case PSM_SETFINISHTEXTA:
2415 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2416 return TRUE;
2417
2418 case PSM_SETWIZBUTTONS:
2419 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2420 return TRUE;
2421
2422 case PSM_SETTITLEW:
2423 //FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2424 return 0;
2425 case PSM_SETCURSELID:
2426 //FIXME("Unimplemented msg PSM_SETCURSELID\n");
2427 return 0;
2428 case PSM_SETFINISHTEXTW:
2429 //FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");
2430 return 0;
2431
2432 default:
2433 return FALSE;
2434 }
2435}
2436
Note: See TracBrowser for help on using the repository browser.