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

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

Corel 20000317 merge, ccbase finished, bug fixes

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