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

Last change on this file since 1402 was 1402, checked in by sandervl, 26 years ago

Fixes + native win32 resources

File size: 52.6 KB
Line 
1/* $Id: propsheet.c,v 1.10 1999-10-22 18:04:11 sandervl Exp $ */
2/*
3 * Property Sheets
4 *
5 * Copyright 1998 Francis Beaudet
6 * Copyright 1999 Thuy Nguyen
7 * Copyright 1999 Achim Hasenmueller
8 * Copyright 1999 Christoph Bratschi
9 *
10 * TODO:
11 * - Tab order
12 * - Unicode property sheets
13 */
14
15/* WINE 990923 level */
16
17/* CB: Odin problems:
18 - trap in PROPSHEET_DialogProc (tab control creation)
19*/
20
21#include <string.h>
22#include "winbase.h"
23#include "commctrl.h"
24#include "prsht.h"
25#include "winnls.h"
26#include "comctl32.h"
27
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 int index; /* corresponds to the index in ppshheader->ppsp */
44 HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
45 HWND hwndPage;
46 BOOL isDirty;
47 LPCWSTR pszText;
48 BOOL hasHelp;
49 BOOL useCallback;
50} PropPageInfo;
51
52typedef struct tagPropSheetInfo
53{
54 LPSTR strPropertiesFor;
55 int nPages;
56 int active_page;
57 LPCPROPSHEETHEADERA ppshheader;
58 BOOL isModeless;
59 BOOL hasHelp;
60 BOOL hasApply;
61 BOOL useCallback;
62 BOOL restartWindows;
63 BOOL rebootSystem;
64 PropPageInfo* proppage;
65 int x;
66 int y;
67 int width;
68 int height;
69 HIMAGELIST hImageList;
70} PropSheetInfo;
71
72typedef struct
73{
74 int x;
75 int y;
76} PADDING_INFO;
77
78/******************************************************************************
79 * Defines and global variables
80 */
81
82const char * PropSheetInfoStr = "PropertySheetInfo";
83
84#define MAX_CAPTION_LENGTH 255
85#define MAX_TABTEXT_LENGTH 255
86
87
88/******************************************************************************
89 * Prototypes
90 */
91static BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo);
92static BOOL PROPSHEET_IsTooSmall(HWND hwndDlg, PropSheetInfo* psInfo);
93static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);
94static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);
95static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
96 PropSheetInfo * psInfo);
97static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
98 PropSheetInfo * psInfo,
99 int index);
100static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
101 PropSheetInfo * psInfo);
102static int PROPSHEET_CreatePage(HWND hwndParent, int index,
103 const PropSheetInfo * psInfo,
104 LPCPROPSHEETPAGEA ppshpage,
105 BOOL showPage);
106static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);
107static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
108static BOOL PROPSHEET_Back(HWND hwndDlg);
109static BOOL PROPSHEET_Next(HWND hwndDlg);
110static BOOL PROPSHEET_Finish(HWND hwndDlg);
111static BOOL PROPSHEET_Apply(HWND hwndDlg);
112static void PROPSHEET_Cancel(HWND hwndDlg);
113static void PROPSHEET_Help(HWND hwndDlg);
114static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
115static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
116static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
117static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText);
118static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
119static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
120 int index,
121 HPROPSHEETPAGE hpage);
122static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
123 WPARAM wParam, LPARAM lParam);
124static LPCPROPSHEETPAGEA PROPSHEET_GetPSPPage(const PropSheetInfo * psInfo,
125 int index);
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);
136
137BOOL WINAPI
138PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
139
140
141/******************************************************************************
142 * PROPSHEET_CollectSheetInfo
143 *
144 * Collect relevant data.
145 */
146static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
147 PropSheetInfo * psInfo)
148{
149 DWORD dwFlags = lppsh->dwFlags;
150
151 psInfo->hasHelp = dwFlags & PSH_HASHELP;
152 psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
153 psInfo->useCallback = dwFlags & PSH_USECALLBACK;
154 psInfo->isModeless = dwFlags & PSH_MODELESS;
155 psInfo->ppshheader = lppsh;
156 psInfo->nPages = lppsh->nPages;
157
158 if (dwFlags & PSH_USEPSTARTPAGE)
159 {
160// TRACE(propsheet, "PSH_USEPSTARTPAGE is on");
161 psInfo->active_page = 0;
162 }
163 else
164 psInfo->active_page = lppsh->u2.nStartPage;
165
166 psInfo->restartWindows = FALSE;
167 psInfo->rebootSystem = FALSE;
168 psInfo->hImageList = 0;
169
170 return TRUE;
171}
172
173/******************************************************************************
174 * PROPSHEET_CollectPageInfo
175 *
176 * Collect property sheet data.
177 * With code taken from DIALOG_ParseTemplate32.
178 */
179BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
180 PropSheetInfo * psInfo,
181 int index)
182{
183 DLGTEMPLATE* pTemplate;
184 const WORD* p;
185 DWORD dwFlags;
186 int width, height;
187
188 if (psInfo->ppshheader->dwFlags & PSH_PROPSHEETPAGE)
189 psInfo->proppage[index].hpage = 0;
190 psInfo->proppage[index].hwndPage = 0;
191 psInfo->proppage[index].isDirty = FALSE;
192
193 /*
194 * Process property page flags.
195 */
196 dwFlags = lppsp->dwFlags;
197 psInfo->proppage[index].useCallback = dwFlags & PSP_USECALLBACK;
198 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
199
200 /* as soon as we have a page with the help flag, set the sheet flag on */
201 if (psInfo->proppage[index].hasHelp)
202 psInfo->hasHelp = TRUE;
203
204 /*
205 * Process page template.
206 */
207 if (dwFlags & PSP_DLGINDIRECT)
208 pTemplate = (DLGTEMPLATE*)lppsp->u1.pResource;
209 else
210 {
211 HRSRC hResource = FindResourceA(lppsp->hInstance,
212 lppsp->u1.pszTemplate,
213 RT_DIALOGA);
214 HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
215 hResource);
216 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
217 }
218
219 /*
220 * Extract the size of the page and the caption.
221 */
222 p = (const WORD *)pTemplate;
223
224 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
225 {
226 /* DIALOGEX template */
227
228 p++; /* dlgVer */
229 p++; /* signature */
230 p += 2; /* help ID */
231 p += 2; /* ext style */
232 p += 2; /* style */
233 }
234 else
235 {
236 /* DIALOG template */
237
238 p += 2; /* style */
239 p += 2; /* ext style */
240 }
241
242 p++; /* nb items */
243 p++; /* x */
244 p++; /* y */
245 width = (WORD)*p; p++;
246 height = (WORD)*p; p++;
247
248 /* remember the largest width and height */
249 if (width > psInfo->width)
250 psInfo->width = width;
251
252 if (height > psInfo->height)
253 psInfo->height = height;
254
255 /* menu */
256 switch ((WORD)*p)
257 {
258 case 0x0000:
259 p++;
260 break;
261 case 0xffff:
262 p += 2;
263 break;
264 default:
265 p += lstrlenW( (LPCWSTR)p ) + 1;
266 break;
267 }
268
269 /* class */
270 switch ((WORD)*p)
271 {
272 case 0x0000:
273 p++;
274 break;
275 case 0xffff:
276 p += 2;
277 break;
278 default:
279 p += lstrlenW( (LPCWSTR)p ) + 1;
280 break;
281 }
282
283 /* Extract the caption */
284 psInfo->proppage[index].pszText = (LPCWSTR)p;
285// TRACE(propsheet, "Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
286 p += lstrlenW((LPCWSTR)p) + 1;
287
288 if (dwFlags & PSP_USETITLE)
289 {
290//AH: todo
291// psInfo->proppage[index].pszText = HEAP_strdupAtoW(GetProcessHeap(),
292// 0,
293// lppsp->pszTitle);
294 }
295
296 /*
297 * Build the image list for icons
298 */
299 if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
300 {
301 HICON hIcon;
302 int icon_cx = GetSystemMetrics(SM_CXSMICON);
303 int icon_cy = GetSystemMetrics(SM_CYSMICON);
304
305 if (dwFlags & PSP_USEICONID)
306 hIcon = LoadImageA(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
307 icon_cx, icon_cy, LR_DEFAULTCOLOR);
308 else
309 hIcon = lppsp->u2.hIcon;
310
311 if (psInfo->hImageList == 0)
312 psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
313
314 ImageList_AddIcon(psInfo->hImageList, hIcon);
315 }
316
317 return TRUE;
318}
319
320/******************************************************************************
321 * PROPSHEET_CreateDialog
322 *
323 * Creates the actual property sheet.
324 */
325
326//AH: WINE 990923 not merged due to changes from CB
327
328BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
329{
330 LRESULT ret;
331 LPCVOID template;
332 HRSRC hRes;
333
334 if (psInfo->useCallback)
335 (*(psInfo->ppshheader->pfnCallback))(0, PSCB_PRECREATE, (LPARAM)template);
336
337 if (!(hRes = FindResourceA(COMCTL32_hModule,
338 MAKEINTRESOURCEA(IDD_PROPSHEET),
339 RT_DIALOGA)))
340 return FALSE;
341
342 if (!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
343 return FALSE;
344
345 if (psInfo->useCallback)
346 (*(psInfo->ppshheader->pfnCallback))(0, PSCB_PRECREATE, (LPARAM)template);
347
348 if (psInfo->ppshheader->dwFlags & PSH_MODELESS)
349 ret = CreateDialogIndirectParamA(psInfo->ppshheader->hInstance,
350 (LPDLGTEMPLATEA) template,
351 psInfo->ppshheader->hwndParent,
352 (DLGPROC) PROPSHEET_DialogProc,
353 (LPARAM)psInfo);
354 else
355 ret = DialogBoxIndirectParamA(psInfo->ppshheader->hInstance,
356 (LPDLGTEMPLATEA) template,
357 psInfo->ppshheader->hwndParent,
358 (DLGPROC) PROPSHEET_DialogProc,
359 (LPARAM)psInfo);
360
361 return ret;
362}
363
364/******************************************************************************
365 * PROPSHEET_IsTooSmall
366 *
367 * Verify that the resource property sheet is big enough.
368 */
369static BOOL PROPSHEET_IsTooSmall(HWND hwndDlg, PropSheetInfo* psInfo)
370{
371 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
372 RECT rcOrigTab, rcPage;
373
374 /*
375 * Original tab size.
376 */
377 GetClientRect(hwndTabCtrl, &rcOrigTab);
378// TRACE(propsheet, "orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
379// rcOrigTab.right, rcOrigTab.bottom);
380
381 /*
382 * Biggest page size.
383 */
384 rcPage.left = psInfo->x;
385 rcPage.top = psInfo->y;
386 rcPage.right = psInfo->width;
387 rcPage.bottom = psInfo->height;
388
389 MapDialogRect(hwndDlg, &rcPage);
390// TRACE(propsheet, "biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
391// rcPage.right, rcPage.bottom);
392
393 if (rcPage.right > rcOrigTab.right)
394 return TRUE;
395
396 if (rcPage.bottom > rcOrigTab.bottom)
397 return TRUE;
398
399 return FALSE;
400}
401
402/******************************************************************************
403 * PROPSHEET_IsTooSmallWizard
404 *
405 * Verify that the default property sheet is big enough.
406 */
407static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
408{
409 RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
410 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
411 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
412
413 GetClientRect(hwndDlg, &rcSheetClient);
414 GetWindowRect(hwndDlg, &rcSheetRect);
415 GetWindowRect(hwndLine, &rcLine);
416
417 /* Remove the space below the sunken line */
418 rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
419
420 /* Remove the buffer zone all around the edge */
421 rcSheetClient.bottom -= (padding.y * 2);
422 rcSheetClient.right -= (padding.x * 2);
423
424 /*
425 * Biggest page size.
426 */
427 rcPage.left = psInfo->x;
428 rcPage.top = psInfo->y;
429 rcPage.right = psInfo->width;
430 rcPage.bottom = psInfo->height;
431
432 MapDialogRect(hwndDlg, &rcPage);
433// TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
434// rcPage.right, rcPage.bottom);
435
436 if (rcPage.right > rcSheetClient.right)
437 return TRUE;
438
439 if (rcPage.bottom > rcSheetClient.bottom)
440 return TRUE;
441
442 return FALSE;
443}
444
445/******************************************************************************
446 * PROPSHEET_AdjustSize
447 *
448 * Resizes the property sheet and the tab control to fit the largest page.
449 */
450static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
451{
452 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
453 HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
454 RECT rc;
455 int tabOffsetX, tabOffsetY, buttonHeight;
456 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
457
458 /* Get the height of buttons */
459 GetClientRect(hwndButton, &rc);
460 buttonHeight = rc.bottom;
461
462 /*
463 * Biggest page size.
464 */
465 rc.left = psInfo->x;
466 rc.top = psInfo->y;
467 rc.right = psInfo->width;
468 rc.bottom = psInfo->height;
469
470 MapDialogRect(hwndDlg, &rc);
471
472 /*
473 * Resize the tab control.
474 */
475 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
476
477 tabOffsetX = -(rc.left);
478 tabOffsetY = -(rc.top);
479
480 rc.right -= rc.left;
481 rc.bottom -= rc.top;
482 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
483 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
484
485 GetClientRect(hwndTabCtrl, &rc);
486
487// TRACE(propsheet, "tab client rc %d %d %d %d\n",
488// rc.left, rc.top, rc.right, rc.bottom);
489
490 rc.right += ((padding.x * 2) + tabOffsetX);
491 rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
492
493 /*
494 * Resize the property sheet.
495 */
496 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
497 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
498
499 return TRUE;
500}
501
502/******************************************************************************
503 * PROPSHEET_AdjustSizeWizard
504 *
505 * Resizes the property sheet to fit the largest page.
506 */
507static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
508{
509 HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
510 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
511 RECT rc;
512 int buttonHeight, lineHeight;
513 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
514
515 /* Get the height of buttons */
516 GetClientRect(hwndButton, &rc);
517 buttonHeight = rc.bottom;
518
519 GetClientRect(hwndLine, &rc);
520 lineHeight = rc.bottom;
521
522 /*
523 * Biggest page size.
524 */
525 rc.left = psInfo->x;
526 rc.top = psInfo->y;
527 rc.right = psInfo->width;
528 rc.bottom = psInfo->height;
529
530 MapDialogRect(hwndDlg, &rc);
531
532// TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
533
534 /* Make room */
535 rc.right += (padding.x * 2);
536 rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
537
538 /*
539 * Resize the property sheet.
540 */
541 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
542 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
543
544 return TRUE;
545}
546
547/******************************************************************************
548 * PROPSHEET_AdjustButtons
549 *
550 * Adjusts the buttons' positions.
551 */
552static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
553{
554 HWND hwndButton = GetDlgItem(hwndParent, IDOK);
555 RECT rcSheet;
556 int x, y;
557 int num_buttons = 2;
558 int buttonWidth, buttonHeight;
559 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
560
561 if (psInfo->hasApply)
562 num_buttons++;
563
564 if (psInfo->hasHelp)
565 num_buttons++;
566
567 /*
568 * Obtain the size of the buttons.
569 */
570 GetClientRect(hwndButton, &rcSheet);
571 buttonWidth = rcSheet.right;
572 buttonHeight = rcSheet.bottom;
573
574 /*
575 * Get the size of the property sheet.
576 */
577 GetClientRect(hwndParent, &rcSheet);
578
579 /*
580 * All buttons will be at this y coordinate.
581 */
582 y = rcSheet.bottom - (padding.y + buttonHeight);
583
584 /*
585 * Position OK button.
586 */
587 hwndButton = GetDlgItem(hwndParent, IDOK);
588
589 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
590
591 SetWindowPos(hwndButton, 0, x, y, 0, 0,
592 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
593
594 /*
595 * Position Cancel button.
596 */
597 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
598
599 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
600
601 SetWindowPos(hwndButton, 0, x, y, 0, 0,
602 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
603
604 /*
605 * Position Apply button.
606 */
607 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
608
609 if (psInfo->hasApply)
610 {
611 if (psInfo->hasHelp)
612 x = rcSheet.right - ((padding.x + buttonWidth) * 2);
613 else
614 x = rcSheet.right - (padding.x + buttonWidth);
615
616 SetWindowPos(hwndButton, 0, x, y, 0, 0,
617 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
618
619 EnableWindow(hwndButton, FALSE);
620 }
621 else
622 ShowWindow(hwndButton, SW_HIDE);
623
624 /*
625 * Position Help button.
626 */
627 hwndButton = GetDlgItem(hwndParent, IDHELP);
628
629 if (psInfo->hasHelp)
630 {
631 x = rcSheet.right - (padding.x + buttonWidth);
632
633 SetWindowPos(hwndButton, 0, x, y, 0, 0,
634 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
635 }
636 else
637 ShowWindow(hwndButton, SW_HIDE);
638
639 return TRUE;
640}
641
642/******************************************************************************
643 * PROPSHEET_AdjustButtonsWizard
644 *
645 * Adjusts the buttons' positions.
646 */
647static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
648 PropSheetInfo* psInfo)
649{
650 HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
651 HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
652 RECT rcSheet;
653 int x, y;
654 int num_buttons = 3;
655 int buttonWidth, buttonHeight, lineHeight, lineWidth;
656 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
657
658 if (psInfo->hasHelp)
659 num_buttons++;
660
661 /*
662 * Obtain the size of the buttons.
663 */
664 GetClientRect(hwndButton, &rcSheet);
665 buttonWidth = rcSheet.right;
666 buttonHeight = rcSheet.bottom;
667
668 GetClientRect(hwndLine, &rcSheet);
669 lineHeight = rcSheet.bottom;
670
671 /*
672 * Get the size of the property sheet.
673 */
674 GetClientRect(hwndParent, &rcSheet);
675
676 /*
677 * All buttons will be at this y coordinate.
678 */
679 y = rcSheet.bottom - (padding.y + buttonHeight);
680
681 /*
682 * Position the Next and the Finish buttons.
683 */
684 hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
685
686 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
687
688 SetWindowPos(hwndButton, 0, x, y, 0, 0,
689 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
690
691 hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
692
693 SetWindowPos(hwndButton, 0, x, y, 0, 0,
694 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
695
696 ShowWindow(hwndButton, SW_HIDE);
697
698 /*
699 * Position the Back button.
700 */
701 hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
702
703 x -= buttonWidth;
704
705 SetWindowPos(hwndButton, 0, x, y, 0, 0,
706 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
707
708 /*
709 * Position the Cancel button.
710 */
711 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
712
713 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
714
715 SetWindowPos(hwndButton, 0, x, y, 0, 0,
716 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
717
718 /*
719 * Position Help button.
720 */
721 hwndButton = GetDlgItem(hwndParent, IDHELP);
722
723 if (psInfo->hasHelp)
724 {
725 x = rcSheet.right - (padding.x + buttonWidth);
726
727 SetWindowPos(hwndButton, 0, x, y, 0, 0,
728 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
729 }
730 else
731 ShowWindow(hwndButton, SW_HIDE);
732
733 /*
734 * Position and resize the sunken line.
735 */
736 x = padding.x;
737 y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
738
739 GetClientRect(hwndParent, &rcSheet);
740 lineWidth = rcSheet.right - (padding.x * 2);
741
742 SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
743 SWP_NOZORDER | SWP_NOACTIVATE);
744
745 return TRUE;
746}
747
748/******************************************************************************
749 * PROPSHEET_GetPaddingInfo
750 *
751 * Returns the layout information.
752 */
753static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
754{
755 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
756 RECT rcTab;
757 POINT tl;
758 PADDING_INFO padding;
759
760 GetWindowRect(hwndTab, &rcTab);
761
762 tl.x = rcTab.left;
763 tl.y = rcTab.top;
764
765 ScreenToClient(hwndDlg, &tl);
766
767 padding.x = tl.x;
768 padding.y = tl.y;
769
770 return padding;
771}
772
773/******************************************************************************
774 * PROPSHEET_GetPaddingInfoWizard
775 *
776 * Returns the layout information.
777 * Horizontal spacing is the distance between the Cancel and Help buttons.
778 * Vertical spacing is the distance between the line and the buttons.
779 */
780static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg)
781{
782 PADDING_INFO padding;
783 RECT rc;
784 HWND hwndControl;
785 POINT ptHelp, ptCancel, ptLine;
786
787 /* Help button */
788 hwndControl = GetDlgItem(hwndDlg, IDHELP);
789 GetWindowRect(hwndControl, &rc);
790
791 ptHelp.x = rc.left;
792 ptHelp.y = rc.top;
793
794 ScreenToClient(hwndDlg, &ptHelp);
795
796 /* Cancel button */
797 hwndControl = GetDlgItem(hwndDlg, IDCANCEL);
798 GetWindowRect(hwndControl, &rc);
799
800 ptCancel.x = rc.right;
801 ptCancel.y = rc.top;
802
803 ScreenToClient(hwndDlg, &ptCancel);
804
805 /* Line */
806 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
807 GetWindowRect(hwndControl, &rc);
808
809 ptLine.x = 0;
810 ptLine.y = rc.bottom;
811
812 ScreenToClient(hwndDlg, &ptLine);
813
814 padding.x = ptHelp.x - ptCancel.x;
815 padding.y = ptHelp.y - ptLine.y;
816
817 return padding;
818}
819
820/******************************************************************************
821 * PROPSHEET_CreateTabControl
822 *
823 * Insert the tabs in the tab control.
824 */
825static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
826 PropSheetInfo * psInfo)
827{
828 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
829 TCITEMA item;
830 int i, nTabs;
831 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
832
833 item.mask = TCIF_TEXT;
834 item.pszText = tabtext;
835 item.cchTextMax = MAX_TABTEXT_LENGTH;
836
837 nTabs = psInfo->ppshheader->nPages;
838
839 /*
840 * Set the image list for icons.
841 */
842 if (psInfo->hImageList)
843 {
844 item.mask |= TCIF_IMAGE;
845 SendMessageA(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
846 }
847
848 for (i = 0; i < nTabs; i++)
849 {
850 item.iImage = i;
851
852 WideCharToMultiByte(CP_ACP, 0,
853 (LPCWSTR)psInfo->proppage[i].pszText,
854 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
855
856 SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
857 }
858
859 return TRUE;
860}
861
862/******************************************************************************
863 * PROPSHEET_CreatePage
864 *
865 * Creates a page.
866 */
867static int PROPSHEET_CreatePage(HWND hwndParent,
868 int index,
869 const PropSheetInfo * psInfo,
870 LPCPROPSHEETPAGEA ppshpage,
871 BOOL showPage)
872{
873 DLGTEMPLATE* pTemplate;
874 HWND hwndPage;
875 RECT rc;
876 PropPageInfo* ppInfo = psInfo->proppage;
877 PADDING_INFO padding;
878 HWND hwndAfter;
879
880// TRACE(propsheet, "index %d\n", index);
881
882 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
883 pTemplate = (DLGTEMPLATE*)ppshpage->u1.pResource;
884 else
885 {
886 HRSRC hResource = FindResourceA(ppshpage->hInstance,
887 ppshpage->u1.pszTemplate,
888 RT_DIALOGA);
889 HGLOBAL hTemplate = LoadResource(ppshpage->hInstance, hResource);
890 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
891 }
892
893 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
894 {
895 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD;
896 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
897 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
898 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
899 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
900 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
901 }
902 else
903 {
904 pTemplate->style |= WS_CHILD;
905 pTemplate->style &= ~DS_MODALFRAME;
906 pTemplate->style &= ~WS_CAPTION;
907 pTemplate->style &= ~WS_SYSMENU;
908 pTemplate->style &= ~WS_POPUP;
909 pTemplate->style &= ~WS_DISABLED;
910
911 }
912
913 if (psInfo->proppage[index].useCallback)
914 (*(ppshpage->pfnCallback))(hwndParent,
915 PSPCB_CREATE,
916 (LPPROPSHEETPAGEA)ppshpage);
917
918 hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
919 pTemplate,
920 hwndParent,
921 ppshpage->pfnDlgProc,
922 (LPARAM)ppshpage);
923
924 ppInfo[index].hwndPage = hwndPage;
925
926 rc.left = psInfo->x;
927 rc.top = psInfo->y;
928 rc.right = psInfo->width;
929 rc.bottom = psInfo->height;
930
931 MapDialogRect(hwndParent, &rc);
932
933 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
934 {
935 GetWindowRect(hwndParent, &rc);
936 padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
937 hwndAfter = hwndParent;
938 }
939 else
940 {
941 /*
942 * Ask the Tab control to fit this page in.
943 */
944
945 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
946 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
947 padding = PROPSHEET_GetPaddingInfo(hwndParent);
948 hwndAfter = HWND_TOP;
949 }
950
951 SetWindowPos(hwndPage, hwndAfter,
952 rc.left + padding.x,
953 rc.top + padding.y,
954 0, 0, SWP_NOSIZE);
955
956 if (showPage)
957 {
958 NMHDR hdr;
959
960 hdr.hwndFrom = hwndParent;
961 hdr.code = PSN_SETACTIVE;
962
963 /*
964 * Send the notification before showing the page.
965 */
966 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
967
968 ShowWindow(hwndPage, SW_SHOW);
969 }
970 else
971 ShowWindow(hwndPage, SW_HIDE);
972
973 return TRUE;
974}
975
976/******************************************************************************
977 * PROPSHEET_ShowPage
978 *
979 * Displays or creates the specified page.
980 */
981static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
982{
983 if (index == psInfo->active_page)
984 return TRUE;
985
986 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
987
988 if (psInfo->proppage[index].hwndPage != 0)
989 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
990 else
991 {
992 LPCPROPSHEETPAGEA ppshpage = PROPSHEET_GetPSPPage(psInfo, index);
993 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage, TRUE);
994 }
995
996 psInfo->active_page = index;
997
998 return TRUE;
999}
1000
1001/******************************************************************************
1002 * PROPSHEET_Back
1003 */
1004static BOOL PROPSHEET_Back(HWND hwndDlg)
1005{
1006 BOOL res;
1007 NMHDR hdr;
1008 HWND hwndPage;
1009 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1010 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1011 PropSheetInfoStr);
1012
1013 hdr.code = PSN_WIZBACK;
1014
1015 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1016
1017 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr) == -1)
1018 return FALSE;
1019
1020 res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, 0);
1021
1022 /* if we went to page 0, disable Back button */
1023 if (res && (psInfo->active_page == 0))
1024 EnableWindow(hwndBack, FALSE);
1025
1026 return TRUE;
1027}
1028
1029/******************************************************************************
1030 * PROPSHEET_Next
1031 */
1032static BOOL PROPSHEET_Next(HWND hwndDlg)
1033{
1034 NMHDR hdr;
1035 HWND hwndPage;
1036 LRESULT msgResult = 0;
1037 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1038 PropSheetInfoStr);
1039
1040 hdr.code = PSN_WIZNEXT;
1041
1042 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1043
1044 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1045
1046// TRACE("msg result %ld\n", msgResult);
1047
1048 if (msgResult == -1)
1049 return FALSE;
1050
1051 PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 0);
1052
1053 return TRUE;
1054}
1055
1056/******************************************************************************
1057 * PROPSHEET_Finish
1058 */
1059static BOOL PROPSHEET_Finish(HWND hwndDlg)
1060{
1061 NMHDR hdr;
1062 HWND hwndPage;
1063 LRESULT msgResult = 0;
1064 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1065 PropSheetInfoStr);
1066
1067 hdr.code = PSN_WIZFINISH;
1068
1069 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1070
1071 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1072
1073// TRACE("msg result %ld\n", msgResult);
1074
1075 if (msgResult != 0)
1076 return FALSE;
1077
1078 if (psInfo->isModeless)
1079 psInfo->active_page = -1;
1080 else
1081 EndDialog(hwndDlg, TRUE);
1082
1083 return TRUE;
1084}
1085
1086/******************************************************************************
1087 * PROPSHEET_Apply
1088 */
1089static BOOL PROPSHEET_Apply(HWND hwndDlg)
1090{
1091 int i;
1092 NMHDR hdr;
1093 HWND hwndPage;
1094 LRESULT msgResult;
1095 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1096 PropSheetInfoStr);
1097
1098 hdr.hwndFrom = hwndDlg;
1099
1100 /*
1101 * Send PSN_KILLACTIVE to the current page.
1102 */
1103 hdr.code = PSN_KILLACTIVE;
1104
1105 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1106
1107 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr) != FALSE)
1108 return FALSE;
1109
1110 /*
1111 * Send PSN_APPLY to all pages.
1112 */
1113 hdr.code = PSN_APPLY;
1114
1115 for (i = 0; i < psInfo->nPages; i++)
1116 {
1117 hwndPage = psInfo->proppage[i].hwndPage;
1118 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1119
1120 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1121 return FALSE;
1122 }
1123
1124 return TRUE;
1125}
1126
1127/******************************************************************************
1128 * PROPSHEET_Cancel
1129 */
1130static void PROPSHEET_Cancel(HWND hwndDlg)
1131{
1132 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1133 PropSheetInfoStr);
1134 HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1135 NMHDR hdr;
1136
1137 hdr.hwndFrom = hwndDlg;
1138 hdr.code = PSN_QUERYCANCEL;
1139
1140 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr))
1141 return;
1142
1143 hdr.code = PSN_RESET;
1144
1145 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1146
1147 if (psInfo->isModeless)
1148 psInfo->active_page = -1; /* makes PSM_GETCURRENTPAGEHWND return NULL */
1149 else
1150 EndDialog(hwndDlg, FALSE);
1151}
1152
1153/******************************************************************************
1154 * PROPSHEET_Help
1155 */
1156static void PROPSHEET_Help(HWND hwndDlg)
1157{
1158 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1159 PropSheetInfoStr);
1160 HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1161 NMHDR hdr;
1162
1163 hdr.hwndFrom = hwndDlg;
1164 hdr.code = PSN_HELP;
1165
1166 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1167}
1168
1169/******************************************************************************
1170 * PROPSHEET_Changed
1171 */
1172static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1173{
1174 int i;
1175 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1176 PropSheetInfoStr);
1177 if (!psInfo) return;
1178 /*
1179 * Set the dirty flag of this page.
1180 */
1181 for (i = 0; i < psInfo->nPages; i++)
1182 {
1183 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1184 psInfo->proppage[i].isDirty = TRUE;
1185 }
1186
1187 /*
1188 * Enable the Apply button.
1189 */
1190 if (psInfo->hasApply)
1191 {
1192 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1193
1194 EnableWindow(hwndApplyBtn, TRUE);
1195 }
1196}
1197
1198/******************************************************************************
1199 * PROPSHEET_UnChanged
1200 */
1201static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1202{
1203 int i;
1204 BOOL noPageDirty = TRUE;
1205 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1206 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1207 PropSheetInfoStr);
1208
1209 for (i = 0; i < psInfo->nPages; i++)
1210 {
1211 /* set the specified page as clean */
1212 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1213 psInfo->proppage[i].isDirty = FALSE;
1214
1215 /* look to see if there's any dirty pages */
1216 if (psInfo->proppage[i].isDirty)
1217 noPageDirty = FALSE;
1218 }
1219
1220 /*
1221 * Disable Apply button.
1222 */
1223 if (noPageDirty)
1224 EnableWindow(hwndApplyBtn, FALSE);
1225}
1226
1227/******************************************************************************
1228 * PROPSHEET_PressButton
1229 */
1230static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1231{
1232 switch (buttonID)
1233 {
1234 case PSBTN_APPLYNOW:
1235 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
1236 break;
1237 case PSBTN_BACK:
1238 PROPSHEET_Back(hwndDlg);
1239 break;
1240 case PSBTN_CANCEL:
1241 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
1242 break;
1243 case PSBTN_FINISH:
1244 PROPSHEET_Finish(hwndDlg);
1245 break;
1246 case PSBTN_HELP:
1247 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
1248 break;
1249 case PSBTN_NEXT:
1250 PROPSHEET_Next(hwndDlg);
1251 break;
1252 case PSBTN_OK:
1253 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
1254 break;
1255 default:
1256// FIXME(propsheet, "Invalid button index %d\n", buttonID);
1257 break;
1258 }
1259}
1260
1261/******************************************************************************
1262 * PROPSHEET_SetCurSel
1263 */
1264static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1265 int index,
1266 HPROPSHEETPAGE hpage)
1267{
1268 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1269 PropSheetInfoStr);
1270 HWND hwndPage;
1271 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1272 NMHDR hdr;
1273
1274 /*
1275 * Notify the current page.
1276 */
1277 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1278
1279 hdr.hwndFrom = hwndDlg;
1280 hdr.code = PSN_KILLACTIVE;
1281
1282 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr))
1283 return FALSE;
1284
1285 /*
1286 * hpage takes precedence over index.
1287 */
1288 if (hpage != NULL)
1289 {
1290 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1291
1292 if (index == -1)
1293 {
1294 //TRACE("Could not find page to remove!\n");
1295 return FALSE;
1296 }
1297 }
1298
1299 hwndPage = psInfo->proppage[index].hwndPage;
1300
1301 /*
1302 * Notify the new page if it's already created.
1303 * If not it will get created and notified in PROPSHEET_ShowPage.
1304 */
1305 if (hwndPage)
1306 {
1307 int result;
1308 hdr.code = PSN_SETACTIVE;
1309
1310 result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1311 /*
1312 * TODO: check return value.
1313 */
1314 }
1315
1316 /*
1317 * Display the new page.
1318 */
1319 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1320
1321 if (psInfo->proppage[index].hasHelp)
1322 EnableWindow(hwndHelp, TRUE);
1323 else
1324 EnableWindow(hwndHelp, FALSE);
1325
1326 return TRUE;
1327}
1328
1329/******************************************************************************
1330 * PROPSHEET_SetTitleA
1331 */
1332static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1333{
1334 if (dwStyle & PSH_PROPTITLE)
1335 {
1336 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1337 PropSheetInfoStr);
1338 char* dest;
1339 int lentitle = strlen(lpszText);
1340 int lenprop = strlen(psInfo->strPropertiesFor);
1341
1342 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
1343 strcpy(dest, psInfo->strPropertiesFor);
1344 strcat(dest, lpszText);
1345
1346 SetWindowTextA(hwndDlg, dest);
1347 COMCTL32_Free(dest);
1348 }
1349 else
1350 SetWindowTextA(hwndDlg, lpszText);
1351}
1352
1353/******************************************************************************
1354 * PROPSHEET_SetFinishTextA
1355 */
1356static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1357{
1358 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1359
1360 /* Set text, show and enable the Finish button */
1361 SetWindowTextA(hwndButton, lpszText);
1362 ShowWindow(hwndButton, SW_SHOW);
1363 EnableWindow(hwndButton, TRUE);
1364
1365 /* Make it default pushbutton */
1366 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1367
1368 /* Hide Back button */
1369 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1370 ShowWindow(hwndButton, SW_HIDE);
1371
1372 /* Hide Next button */
1373 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1374 ShowWindow(hwndButton, SW_HIDE);
1375}
1376
1377/******************************************************************************
1378 * PROPSHEET_QuerySiblings
1379 */
1380static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1381 WPARAM wParam, LPARAM lParam)
1382{
1383 int i = 0;
1384 HWND hwndPage;
1385 LRESULT msgResult = 0;
1386 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1387 PropSheetInfoStr);
1388
1389 while ((i < psInfo->nPages) && (msgResult == 0))
1390 {
1391 hwndPage = psInfo->proppage[i].hwndPage;
1392 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1393 i++;
1394 }
1395
1396 return msgResult;
1397}
1398
1399/******************************************************************************
1400 * PROPSHEET_GetPSPPage
1401 */
1402static LPCPROPSHEETPAGEA PROPSHEET_GetPSPPage(const PropSheetInfo * psInfo,
1403 int index)
1404{
1405 BOOL usePSP = psInfo->ppshheader->dwFlags & PSH_PROPSHEETPAGE;
1406 LPCPROPSHEETPAGEA lppsp;
1407 int realIndex = psInfo->proppage[index].index;
1408
1409 if (usePSP)
1410 {
1411 BYTE* pByte;
1412
1413 lppsp = psInfo->ppshheader->u3.ppsp;
1414
1415 pByte = (BYTE*) lppsp;
1416
1417 pByte += (lppsp->dwSize * realIndex);
1418 lppsp = (LPCPROPSHEETPAGEA)pByte;
1419 }
1420 else
1421 lppsp = (LPCPROPSHEETPAGEA) psInfo->ppshheader->u3.phpage[realIndex];
1422
1423 return lppsp;
1424}
1425
1426/******************************************************************************
1427 * PROPSHEET_AddPage
1428 */
1429static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1430 HPROPSHEETPAGE hpage)
1431{
1432 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1433 PropSheetInfoStr);
1434 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1435 TCITEMA item;
1436 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1437 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1438
1439 /*
1440 * Allocate and fill in a new PropPageInfo entry.
1441 */
1442 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1443 sizeof(PropPageInfo) *
1444 (psInfo->nPages + 1));
1445
1446 PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages);
1447 psInfo->proppage[psInfo->nPages].index = -1;
1448 psInfo->proppage[psInfo->nPages].hpage = hpage;
1449
1450 /*
1451 * Create the page but don't show it.
1452 */
1453 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp, FALSE);
1454
1455 /*
1456 * Add a new tab to the tab control.
1457 */
1458 item.mask = TCIF_TEXT;
1459 item.pszText = tabtext;
1460 item.cchTextMax = MAX_TABTEXT_LENGTH;
1461
1462 WideCharToMultiByte(CP_ACP, 0,
1463 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1464 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1465
1466 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1467 (LPARAM)&item);
1468
1469 psInfo->nPages++;
1470
1471 return FALSE;
1472}
1473
1474/******************************************************************************
1475 * PROPSHEET_RemovePage
1476 */
1477static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1478 int index,
1479 HPROPSHEETPAGE hpage)
1480{
1481 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1482 PropSheetInfoStr);
1483 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1484 PropPageInfo* oldPages = psInfo->proppage;
1485
1486 /*
1487 * hpage takes precedence over index.
1488 */
1489 if (hpage != 0)
1490 {
1491 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1492
1493 if (index == -1)
1494 {
1495// TRACE(propsheet, "Could not find page to remove!\n");
1496 return FALSE;
1497 }
1498 }
1499
1500// TRACE(propsheet, "total pages %d removing page %d active page %d\n",
1501// psInfo->nPages, index, psInfo->active_page);
1502 /*
1503 * Check if we're removing the active page.
1504 */
1505 if (index == psInfo->active_page)
1506 {
1507 if (psInfo->nPages > 1)
1508 {
1509 if (index > 0)
1510 {
1511 /* activate previous page */
1512 PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1513 }
1514 else
1515 {
1516 /* activate the next page */
1517 PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1518 }
1519 }
1520 else
1521 {
1522// TRACE(propsheet, "Removing the only page, close the dialog!\n");
1523
1524 if (psInfo->isModeless)
1525 psInfo->active_page = -1;
1526 else
1527 EndDialog(hwndDlg, FALSE);
1528
1529 return TRUE;
1530 }
1531 }
1532
1533 if (index < psInfo->active_page)
1534 psInfo->active_page--;
1535
1536 /* Remove the tab */
1537 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1538
1539 psInfo->nPages--;
1540 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1541
1542 if (index > 0)
1543 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1544
1545 if (index < psInfo->nPages)
1546 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1547 (psInfo->nPages - index) * sizeof(PropPageInfo));
1548
1549 COMCTL32_Free(oldPages);
1550
1551 return FALSE;
1552}
1553
1554/******************************************************************************
1555 * PROPSHEET_SetWizButtons
1556 *
1557 * This code will work if (and assumes that) the Next button is on top of the
1558 * Finish button. ie. Finish comes after Next in the Z order.
1559 * This means make sure the dialog template reflects this.
1560 *
1561 */
1562static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1563{
1564 HWND hwndButton;
1565
1566// TRACE("%ld\n", dwFlags);
1567
1568 if (dwFlags & PSWIZB_BACK)
1569 {
1570 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1571 EnableWindow(hwndButton, TRUE);
1572 }
1573
1574 if (dwFlags & PSWIZB_NEXT)
1575 {
1576 /* Hide the Finish button */
1577 hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1578 ShowWindow(hwndButton, SW_HIDE);
1579
1580 /* Show and enable the Next button */
1581 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1582
1583 ShowWindow(hwndButton, SW_SHOW);
1584 EnableWindow(hwndButton, TRUE);
1585
1586 /* Set the Next button as the default pushbutton */
1587 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1588 }
1589
1590 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1591 {
1592 /* Hide the Next button */
1593 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1594 ShowWindow(hwndButton, SW_HIDE);
1595
1596 /* Show the Finish button */
1597 hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1598 ShowWindow(hwndButton, SW_SHOW);
1599
1600 if (dwFlags & PSWIZB_FINISH)
1601 EnableWindow(hwndButton, TRUE);
1602 else
1603 EnableWindow(hwndButton, FALSE);
1604
1605 /* Set the Finish button as the default pushbutton */
1606 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1607 }
1608}
1609
1610/******************************************************************************
1611 * PROPSHEET_GetPageIndex
1612 *
1613 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1614 * the array of PropPageInfo.
1615 */
1616static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1617{
1618 BOOL found = FALSE;
1619 int index = 0;
1620
1621 while ((index < psInfo->nPages) && (found == FALSE))
1622 {
1623 if (psInfo->proppage[index].hpage == hpage)
1624 found = TRUE;
1625 else
1626 index++;
1627 }
1628
1629 if (found == FALSE)
1630 index = -1;
1631
1632 return index;
1633}
1634
1635/******************************************************************************
1636 * PROPSHEET_CleanUp
1637 */
1638static void PROPSHEET_CleanUp(HWND hwndDlg)
1639{
1640 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1641 PropSheetInfoStr);
1642 COMCTL32_Free(psInfo->proppage);
1643 COMCTL32_Free(psInfo->strPropertiesFor);
1644 ImageList_Destroy(psInfo->hImageList);
1645
1646 GlobalFree((HGLOBAL)psInfo);
1647}
1648
1649/******************************************************************************
1650 * PropertySheetA (COMCTL32.84)(COMCTL32.83)
1651 */
1652INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1653{
1654 int bRet = 0;
1655 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1656 sizeof(PropSheetInfo));
1657 LPCPROPSHEETPAGEA lppsp;
1658 int i;
1659
1660 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1661
1662 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1663 lppsh->nPages);
1664
1665 for (i = 0; i < lppsh->nPages; i++)
1666 {
1667 psInfo->proppage[i].index = i;
1668 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1669 psInfo->proppage[i].hpage = psInfo->ppshheader->u3.phpage[i];
1670 lppsp = PROPSHEET_GetPSPPage(psInfo, i);
1671 PROPSHEET_CollectPageInfo(lppsp, psInfo, i);
1672 }
1673
1674 bRet = PROPSHEET_CreateDialog(psInfo);
1675
1676 return bRet;
1677}
1678
1679/******************************************************************************
1680 * PropertySheet32W (COMCTL32.85)
1681 */
1682INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1683{
1684// FIXME(propsheet, "(%p): stub\n", propertySheetHeader);
1685
1686 return -1;
1687}
1688
1689/******************************************************************************
1690 * CreatePropertySheetPageA (COMCTL32.19)(COMCTL32.18)
1691 */
1692HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1693 LPCPROPSHEETPAGEA lpPropSheetPage)
1694{
1695 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1696
1697 *ppsp = *lpPropSheetPage;
1698
1699 return (HPROPSHEETPAGE)ppsp;
1700}
1701
1702/******************************************************************************
1703 * CreatePropertySheetPageW (COMCTL32.20)
1704 */
1705HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1706{
1707// FIXME(propsheet, "(%p): stub\n", lpPropSheetPage);
1708
1709 return 0;
1710}
1711
1712/******************************************************************************
1713 * DestroyPropertySheetPage (COMCTL32.24)
1714 */
1715BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
1716{
1717 COMCTL32_Free(hPropPage);
1718
1719 return TRUE;
1720}
1721
1722/******************************************************************************
1723 * PROPSHEET_DialogProc
1724 */
1725BOOL WINAPI
1726PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1727{
1728 switch (uMsg)
1729 {
1730 case WM_INITDIALOG:
1731 {
1732 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
1733 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
1734 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1735 LPCPROPSHEETPAGEA ppshpage;
1736
1737 /*
1738 * Small icon in the title bar.
1739 */
1740 if ((psInfo->ppshheader->dwFlags & PSH_USEICONID) ||
1741 (psInfo->ppshheader->dwFlags & PSH_USEHICON))
1742 {
1743 HICON hIcon;
1744 int icon_cx = GetSystemMetrics(SM_CXSMICON);
1745 int icon_cy = GetSystemMetrics(SM_CYSMICON);
1746
1747 if (psInfo->ppshheader->dwFlags & PSH_USEICONID)
1748 hIcon = LoadImageA(psInfo->ppshheader->hInstance,
1749 psInfo->ppshheader->u1.pszIcon,
1750 IMAGE_ICON,
1751 icon_cx, icon_cy,
1752 LR_DEFAULTCOLOR);
1753 else
1754 hIcon = psInfo->ppshheader->u1.hIcon;
1755
1756 SendMessageA(hwnd, WM_SETICON, 0, hIcon);
1757 }
1758
1759 if (psInfo->ppshheader->dwFlags & PSH_USEHICON)
1760 SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader->u1.hIcon);
1761
1762 psInfo->strPropertiesFor = strCaption;
1763
1764 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
1765
1766 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
1767 {
1768 HWND hwndBack = GetDlgItem(hwnd, IDC_BACK_BUTTON);
1769
1770 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
1771 {
1772 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
1773 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
1774 }
1775
1776 /* Disable Back button if we start at page 0 */
1777 if (psInfo->active_page == 0)
1778 EnableWindow(hwndBack, FALSE);
1779 }
1780 else
1781 {
1782 PROPSHEET_CreateTabControl(hwnd, psInfo);
1783
1784 if (PROPSHEET_IsTooSmall(hwnd, psInfo))
1785 {
1786 PROPSHEET_AdjustSize(hwnd, psInfo);
1787 PROPSHEET_AdjustButtons(hwnd, psInfo);
1788 }
1789 }
1790
1791 ppshpage = PROPSHEET_GetPSPPage(psInfo, psInfo->active_page);
1792 PROPSHEET_CreatePage(hwnd, psInfo->active_page, psInfo, ppshpage, TRUE);
1793
1794 if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
1795 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
1796
1797 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
1798
1799 PROPSHEET_SetTitleA(hwnd,
1800 psInfo->ppshheader->dwFlags,
1801 psInfo->ppshheader->pszCaption);
1802
1803 return TRUE;
1804 }
1805
1806 case WM_DESTROY:
1807 PROPSHEET_CleanUp(hwnd);
1808 return TRUE;
1809
1810 case WM_CLOSE:
1811 PROPSHEET_Cancel(hwnd);
1812 return TRUE;
1813
1814 case WM_COMMAND:
1815 {
1816 WORD wID = LOWORD(wParam);
1817
1818 switch (wID)
1819 {
1820 case IDOK:
1821 case IDC_APPLY_BUTTON:
1822 {
1823 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
1824
1825 if (PROPSHEET_Apply(hwnd) == FALSE)
1826 break;
1827
1828 EnableWindow(hwndApplyBtn, FALSE);
1829
1830 if (wID == IDOK)
1831 {
1832 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1833 PropSheetInfoStr);
1834 int result = TRUE;
1835
1836 if (psInfo->restartWindows)
1837 result = ID_PSRESTARTWINDOWS;
1838
1839 /* reboot system takes precedence over restart windows */
1840 if (psInfo->rebootSystem)
1841 result = ID_PSREBOOTSYSTEM;
1842
1843 if (psInfo->isModeless)
1844 psInfo->active_page = -1;
1845 else
1846 EndDialog(hwnd, result);
1847 }
1848
1849 break;
1850 }
1851
1852 case IDC_BACK_BUTTON:
1853 PROPSHEET_Back(hwnd);
1854 break;
1855
1856 case IDC_NEXT_BUTTON:
1857 PROPSHEET_Next(hwnd);
1858 break;
1859
1860 case IDC_FINISH_BUTTON:
1861 PROPSHEET_Finish(hwnd);
1862 break;
1863
1864 case IDCANCEL:
1865 PROPSHEET_Cancel(hwnd);
1866 break;
1867
1868 case IDHELP:
1869 PROPSHEET_Help(hwnd);
1870 break;
1871 }
1872
1873 return TRUE;
1874 }
1875
1876 case WM_NOTIFY:
1877 {
1878 NMHDR* pnmh = (LPNMHDR) lParam;
1879
1880 if (pnmh->code == TCN_SELCHANGE)
1881 {
1882 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
1883 PROPSHEET_SetCurSel(hwnd, index, 0);
1884 }
1885
1886 return 0;
1887 }
1888
1889 case PSM_GETCURRENTPAGEHWND:
1890 {
1891 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1892 PropSheetInfoStr);
1893 HWND hwndPage = 0;
1894
1895 if (psInfo->active_page != -1)
1896 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1897
1898 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
1899
1900 return TRUE;
1901 }
1902
1903 case PSM_CHANGED:
1904 PROPSHEET_Changed(hwnd, (HWND)wParam);
1905 return TRUE;
1906
1907 case PSM_UNCHANGED:
1908 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
1909 return TRUE;
1910
1911 case PSM_GETTABCONTROL:
1912 {
1913 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1914
1915 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
1916
1917 return TRUE;
1918 }
1919
1920 case PSM_SETCURSEL:
1921 {
1922 BOOL msgResult;
1923
1924 msgResult = PROPSHEET_SetCurSel(hwnd,
1925 (int)wParam,
1926 (HPROPSHEETPAGE)lParam);
1927
1928 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1929
1930 return TRUE;
1931 }
1932
1933 case PSM_CANCELTOCLOSE:
1934 {
1935 HWND hwndOK = GetDlgItem(hwnd, IDOK);
1936 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
1937
1938 EnableWindow(hwndCancel, FALSE);
1939 SetWindowTextA(hwndOK, "Close"); /* FIXME: hardcoded string */
1940
1941 return TRUE;
1942 }
1943
1944 case PSM_RESTARTWINDOWS:
1945 {
1946 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1947 PropSheetInfoStr);
1948
1949 psInfo->restartWindows = TRUE;
1950 return TRUE;
1951 }
1952
1953 case PSM_REBOOTSYSTEM:
1954 {
1955 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1956 PropSheetInfoStr);
1957
1958 psInfo->rebootSystem = TRUE;
1959 return TRUE;
1960 }
1961
1962 case PSM_SETTITLEA:
1963 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
1964 return TRUE;
1965
1966 case PSM_APPLY:
1967 {
1968 BOOL msgResult = PROPSHEET_Apply(hwnd);
1969
1970 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1971
1972 return TRUE;
1973 }
1974
1975 case PSM_QUERYSIBLINGS:
1976 {
1977 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
1978
1979 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1980
1981 return TRUE;
1982 }
1983
1984 case PSM_ADDPAGE:
1985 PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
1986 return TRUE;
1987
1988 case PSM_REMOVEPAGE:
1989 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
1990 return TRUE;
1991
1992 case PSM_ISDIALOGMESSAGE:
1993 {
1994// FIXME("Unimplemented msg PSM_ISDIALOGMESSAGE\n");
1995 return 0;
1996 }
1997
1998 case PSM_PRESSBUTTON:
1999 PROPSHEET_PressButton(hwnd, (int)wParam);
2000 return TRUE;
2001
2002 case PSM_SETFINISHTEXTA:
2003 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2004 return TRUE;
2005
2006 case PSM_SETWIZBUTTONS:
2007 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2008 return TRUE;
2009
2010 case PSM_SETTITLEW:
2011// FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2012 return 0;
2013 case PSM_SETCURSELID:
2014// FIXME("Unimplemented msg PSM_SETCURSELID\n");
2015 return 0;
2016 case PSM_SETFINISHTEXTW:
2017// FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");
2018 return 0;
2019
2020 default:
2021 return FALSE;
2022 }
2023}
2024
Note: See TracBrowser for help on using the repository browser.