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

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

trackbar buddy fix, tooltip enhancements

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