]> cygwin.com Git - cygwin-apps/setup.git/blame - propsheet.cc
Move some non-localizable string from resources
[cygwin-apps/setup.git] / propsheet.cc
CommitLineData
df62e023 1/*
56a7c49e 2 * Copyright (c) 2001, 2002, 2003 Gary R. Van Sickle.
df62e023
RC
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Gary R. Van Sickle <g.r.vansickle@worldnet.att.net>
13 *
14 */
15
16// This is the implementation of the PropSheet class. This class encapsulates
17// a Windows property sheet / wizard and interfaces with the PropertyPage class.
18// It's named PropSheet instead of PropertySheet because the latter conflicts with
19// the Windows function of the same name.
20
21#include "propsheet.h"
22#include "proppage.h"
62489576 23#include "resource.h"
ee91d9be
RC
24#include "RECTWrapper.h"
25#include "ControlAdjuster.h"
00fa5f6c 26#include "choose.h"
17d64747 27#include "msg.h"
df62e023 28
b7301c43
RC
29// Sort of a "hidden" Windows structure. Used in the PropSheetCallback.
30#include <pshpack1.h>
31typedef struct DLGTEMPLATEEX
32{
33 WORD dlgVer;
34 WORD signature;
35 DWORD helpID;
36 DWORD exStyle;
37 DWORD style;
38 WORD cDlgItems;
39 short x;
40 short y;
41 short cx;
42 short cy;
43}
44DLGTEMPLATEEX, *LPDLGTEMPLATEEX;
45#include <poppack.h>
df62e023
RC
46
47PropSheet::PropSheet ()
48{
df62e023
RC
49}
50
51PropSheet::~PropSheet ()
52{
53}
54
55HPROPSHEETPAGE *
56PropSheet::CreatePages ()
57{
58 HPROPSHEETPAGE *retarray;
59
60 // Create the return array
56a7c49e 61 retarray = new HPROPSHEETPAGE[PropertyPages.size()];
df62e023
RC
62
63 // Create the pages with CreatePropertySheetPage().
64 // We do it here rather than in the PropertyPages themselves
65 // because, for reasons known only to Microsoft, these handles will be
66 // destroyed by the property sheet before the PropertySheet() call returns,
67 // at least if it's modal (don't know about modeless).
56a7c49e
MB
68 unsigned int i;
69 for (i = 0; i < PropertyPages.size(); i++)
df62e023
RC
70 {
71 retarray[i] =
72 CreatePropertySheetPage (PropertyPages[i]->GetPROPSHEETPAGEPtr ());
73
74 // Set position info
75 if (i == 0)
76 {
77 PropertyPages[i]->YouAreFirst ();
78 }
56a7c49e 79 else if (i == PropertyPages.size() - 1)
df62e023
RC
80 {
81 PropertyPages[i]->YouAreLast ();
82 }
83 else
84 {
85 PropertyPages[i]->YouAreMiddle ();
86 }
87 }
88
89 return retarray;
90}
91
ee91d9be
RC
92// Stuff needed by the PropSheet wndproc hook
93struct PropSheetData
94{
95 WNDPROC oldWndProc;
96 bool clientRectValid;
97 RECTWrapper lastClientRect;
98 bool gotPage;
99 RECTWrapper pageRect;
4b6e5406
RC
100 bool hasMinRect;
101 RECTWrapper minRect;
30718d6f 102
ee91d9be
RC
103 PropSheetData ()
104 {
105 oldWndProc = 0;
106 clientRectValid = false;
107 gotPage = false;
4b6e5406 108 hasMinRect = false;
ee91d9be 109 }
30718d6f 110
ee91d9be
RC
111// @@@ Ugly. Really only works because only one PS is used now.
112 static PropSheetData& Instance()
113 {
114 static PropSheetData TheInstance;
30718d6f 115 return TheInstance;
ee91d9be
RC
116 }
117};
118
119static ControlAdjuster::ControlInfo PropSheetControlsInfo[] = {
a8d753b6
RC
120 {0x3023, CP_RIGHT, CP_BOTTOM}, // Back
121 {0x3024, CP_RIGHT, CP_BOTTOM}, // Next
122 {0x3025, CP_RIGHT, CP_BOTTOM}, // Finish
123 {0x3026, CP_STRETCH, CP_BOTTOM}, // Line above buttons
124 { 2, CP_RIGHT, CP_BOTTOM}, // Cancel
125 {0, CP_LEFT, CP_TOP}
ee91d9be
RC
126};
127
128static bool IsDialog (HWND hwnd)
129{
130 char className[7];
131 GetClassName (hwnd, className, sizeof (className));
30718d6f 132
ee91d9be
RC
133 return (strcmp (className, "#32770") == 0);
134}
135
136BOOL CALLBACK EnumPages (HWND hwnd, LPARAM lParam)
137{
138 // Is it really a dialog?
139 if (IsDialog (hwnd))
140 {
141 PropSheetData& psd = PropSheetData::Instance();
30718d6f
CF
142 SetWindowPos (hwnd, 0, psd.pageRect.left, psd.pageRect.top,
143 psd.pageRect.width (), psd.pageRect.height (),
ee91d9be
RC
144 SWP_NOACTIVATE | SWP_NOZORDER);
145 }
146
147 return TRUE;
148}
149
30718d6f 150static LRESULT CALLBACK PropSheetWndProc (HWND hwnd, UINT uMsg,
ee91d9be
RC
151 WPARAM wParam, LPARAM lParam)
152{
153 PropSheetData& psd = PropSheetData::Instance();
154 switch (uMsg)
155 {
c8356810 156 case WM_SYSCOMMAND:
f2558685
CF
157 if ((wParam & 0xfff0) == SC_CLOSE)
158 goto areyousure;
159 break;
c8356810 160 case WM_COMMAND:
f2558685 161 if (wParam != 2)
c8356810 162 break;
f2558685 163 areyousure:
17d64747 164 if (mbox(hwnd, IDS_CONFIRM_EXIT, MB_YESNO) == IDNO)
f2558685
CF
165 return 0;
166 break;
ee91d9be
RC
167 case WM_SIZE:
168 {
30718d6f
CF
169 RECTWrapper clientRect;
170 GetClientRect (hwnd, &clientRect);
171
ee91d9be 172 /*
30718d6f
CF
173 When the window is minimized, the client rect is reduced to
174 (0,0-0,0), which causes child adjusting to screw slightly up. Work
4b6e5406
RC
175 around by not adjusting child upon minimization - it isn't really
176 needed then, anyway.
ee91d9be 177 */
4b6e5406 178 if (wParam != SIZE_MINIMIZED)
ee91d9be 179 {
ee91d9be 180 /*
4b6e5406
RC
181 The first time we get a WM_SIZE, the client rect will be all zeros.
182 */
183 if (psd.clientRectValid)
184 {
185 const int dX =
186 clientRect.width () - psd.lastClientRect.width ();
187 const int dY =
188 clientRect.height () - psd.lastClientRect.height ();
30718d6f
CF
189
190 ControlAdjuster::AdjustControls (hwnd, PropSheetControlsInfo,
4b6e5406 191 dX, dY);
30718d6f 192
4b6e5406
RC
193 psd.pageRect.right += dX;
194 psd.pageRect.bottom += dY;
30718d6f 195
4b6e5406
RC
196 /*
197 The pages are child windows, but don't have IDs.
30718d6f 198 So change them by enumerating all childs and adjust all
4b6e5406
RC
199 dialogs among them.
200 */
201 if (psd.gotPage)
30718d6f 202 EnumChildWindows (hwnd, &EnumPages, 0);
4b6e5406
RC
203 }
204 else
205 {
206 psd.clientRectValid = true;
207 }
208 /*
209 Store away the current size and use it as the minmal window size.
ee91d9be 210 */
4b6e5406
RC
211 if (!psd.hasMinRect)
212 {
213 GetWindowRect (hwnd, &psd.minRect);
6bfd5236 214 psd.hasMinRect = true;
4b6e5406 215 }
30718d6f 216
4b6e5406 217 psd.lastClientRect = clientRect;
ee91d9be 218 }
4b6e5406
RC
219 }
220 break;
221 case WM_GETMINMAXINFO:
222 {
223 if (psd.hasMinRect)
ee91d9be 224 {
4b6e5406
RC
225 LPMINMAXINFO mmi = (LPMINMAXINFO)lParam;
226 mmi->ptMinTrackSize.x = psd.minRect.width ();
227 mmi->ptMinTrackSize.y = psd.minRect.height ();
ee91d9be 228 }
ee91d9be
RC
229 }
230 break;
231 }
30718d6f
CF
232
233 return CallWindowProc (psd.oldWndProc,
ee91d9be
RC
234 hwnd, uMsg, wParam, lParam);
235}
236
b7301c43
RC
237static int CALLBACK
238PropSheetProc (HWND hwndDlg, UINT uMsg, LPARAM lParam)
239{
240 switch (uMsg)
241 {
242 case PSCB_PRECREATE:
243 {
30718d6f 244 LONG additionalStyle =
ee91d9be 245 (WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME);
b7301c43
RC
246 // Add a minimize box to the sheet/wizard.
247 if (((LPDLGTEMPLATEEX) lParam)->signature == 0xFFFF)
248 {
ee91d9be 249 ((LPDLGTEMPLATEEX) lParam)->style |= additionalStyle;
b7301c43
RC
250 }
251 else
252 {
ee91d9be 253 ((LPDLGTEMPLATE) lParam)->style |= additionalStyle;
b7301c43
RC
254 }
255 }
256 return TRUE;
ee91d9be
RC
257 case PSCB_INITIALIZED:
258 {
d1b5a517
JT
259 /*
260 PropSheet() with PSH_USEICONID only sets the small icon,
261 so we must set the big icon ourselves
262 */
263 SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_CYGWIN)));
30718d6f 264 /*
ee91d9be
RC
265 Hook into the window proc.
266 We need to catch some messages for resizing.
267 */
30718d6f 268 PropSheetData::Instance().oldWndProc =
ee91d9be 269 (WNDPROC)GetWindowLongPtr (hwndDlg, GWLP_WNDPROC);
30718d6f 270 SetWindowLongPtr (hwndDlg, GWLP_WNDPROC,
ee91d9be 271 (LONG_PTR)&PropSheetWndProc);
00fa5f6c 272 ChooserPage::SetHwndDialog (hwndDlg);
ee91d9be
RC
273 }
274 return TRUE;
b7301c43
RC
275 }
276 return TRUE;
277}
278
b7301c43
RC
279bool
280PropSheet::Create (const Window * Parent, DWORD Style)
df62e023 281{
b7301c43 282 PROPSHEETHEADER p;
df62e023
RC
283
284 PageHandles = CreatePages ();
285
67fb0b58 286 p.dwSize = sizeof (PROPSHEETHEADER);
62489576
MB
287 p.dwFlags = PSH_NOAPPLYNOW | PSH_WIZARD | PSH_USECALLBACK
288 /*| PSH_MODELESS */ | PSH_USEICONID;
df62e023
RC
289 if (Parent != NULL)
290 {
291 p.hwndParent = Parent->GetHWND ();
292 }
293 else
294 {
295 p.hwndParent = NULL;
296 }
297 p.hInstance = GetInstance ();
56a7c49e 298 p.nPages = PropertyPages.size();
62489576 299 p.pszIcon = MAKEINTRESOURCE(IDI_CYGWIN);
df62e023
RC
300 p.nStartPage = 0;
301 p.phpage = PageHandles;
b7301c43 302 p.pfnCallback = PropSheetProc;
df62e023 303
58ee6135 304 // The winmain event loop actually resides in here.
df62e023
RC
305 PropertySheet (&p);
306
df62e023
RC
307 SetHWND (NULL);
308
309
310 return true;
311}
312
313void
314PropSheet::SetHWNDFromPage (HWND h)
315{
316 // If we're a modal dialog, there's no way for us to know our window handle unless
317 // one of our pages tells us through this function.
318 SetHWND (h);
319}
320
ee91d9be
RC
321/*
322 Adjust the size of a page so that it fits nicely into the window.
323 */
324void
325PropSheet::AdjustPageSize (HWND page)
326{
327 PropSheetData& psd = PropSheetData::Instance();
328 if (!psd.clientRectValid) return;
329
330 /*
331 It's probably not obvious what's done here:
332 When this method is called the first time, the first page is already
333 created and sized, but at the coordinates (0,0). The sheet, however,
334 isn't in it's final size. My guess is that the sheet first creates the
30718d6f 335 page, and then resizes itself to have the right metrics to contain the
ee91d9be 336 page and moves it to it's position. For our purposes, however, we need
4b6e5406 337 the final metrics of the page. So, the first time this method is called,
ee91d9be
RC
338 we basically grab the size of the page, but calculate the top/left coords
339 ourselves.
340 */
30718d6f 341
ee91d9be
RC
342 if (!psd.gotPage)
343 {
344 psd.gotPage = true;
345
346 RECTWrapper& pageRect = psd.pageRect;
347 ::GetWindowRect (page, &pageRect);
348 // We want client coords.
349 ::ScreenToClient (page, (LPPOINT)&pageRect.left);
350 ::ScreenToClient (page, (LPPOINT)&pageRect.right);
351
352 LONG dialogBaseUnits = ::GetDialogBaseUnits ();
353 // The margins in DUs are a result of "educated guesses" and T&E.
354 int marginX = MulDiv (5, LOWORD(dialogBaseUnits), 4);
355 int marginY = MulDiv (5, HIWORD(dialogBaseUnits), 8);
356
357 pageRect.move (marginX, marginY);
358 }
359
30718d6f
CF
360 SetWindowPos (page, 0, psd.pageRect.left, psd.pageRect.top,
361 psd.pageRect.width (), psd.pageRect.height (),
ee91d9be
RC
362 SWP_NOACTIVATE | SWP_NOZORDER);
363}
364
df62e023
RC
365void
366PropSheet::AddPage (PropertyPage * p)
367{
368 // Add a page to the property sheet.
369 p->YouAreBeingAddedToASheet (this);
56a7c49e 370 PropertyPages.push_back(p);
df62e023
RC
371}
372
b7301c43
RC
373bool
374PropSheet::SetActivePage (int i)
df62e023
RC
375{
376 // Posts a message to the message queue, so this won't block
db09d718 377 return static_cast < bool > (PropSheet_SetCurSel (GetHWND (), NULL, i));
df62e023
RC
378}
379
b7301c43
RC
380bool
381PropSheet::SetActivePageByID (int resource_id)
df62e023
RC
382{
383 // Posts a message to the message queue, so this won't block
384 return static_cast < bool >
db09d718 385 (PropSheet_SetCurSelByID (GetHWND (), resource_id));
df62e023
RC
386}
387
388void
389PropSheet::SetButtons (DWORD flags)
390{
391 // Posts a message to the message queue, so this won't block
db09d718 392 PropSheet_SetWizButtons (GetHWND (), flags);
df62e023
RC
393}
394
395void
396PropSheet::PressButton (int button)
397{
db09d718 398 PropSheet_PressButton (GetHWND (), button);
df62e023 399}
This page took 0.185585 seconds and 5 git commands to generate.