]> cygwin.com Git - cygwin-apps/setup.git/blame - proppage.cc
2005-05-21 Brian Dessent <brian@dessent.net>
[cygwin-apps/setup.git] / proppage.cc
CommitLineData
df62e023 1/*
25130a4d 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 PropertyPage class. It works closely with the
17// PropSheet class to implement a single page of the property sheet.
18
19#include "proppage.h"
20#include "propsheet.h"
21#include "win32.h"
daab12c7 22#include <shellapi.h>
b7301c43 23#include "resource.h"
f2ff9838
RC
24#include "state.h"
25
26#include "getopt++/BoolOption.h"
4d7a6eeb 27#include "Exception.h"
daab12c7 28#include "LogSingleton.h"
df62e023
RC
29
30bool PropertyPage::DoOnceForSheet = true;
31
ee91d9be
RC
32/*
33 Sizing information for some controls that are common to all pages.
34 */
35static ControlAdjuster::ControlInfo DefaultControlsInfo[] = {
a8d753b6
RC
36 {IDC_HEADICON, CP_RIGHT, CP_TOP},
37 {IDC_HEADSEPARATOR, CP_STRETCH, CP_TOP},
38 {0, CP_LEFT, CP_TOP}
ee91d9be
RC
39};
40
df62e023
RC
41PropertyPage::PropertyPage ()
42{
43 proc = NULL;
44 cmdproc = NULL;
45 IsFirst = false;
46 IsLast = false;
ee91d9be
RC
47
48 sizeProcessor.AddControlInfo (DefaultControlsInfo);
df62e023
RC
49}
50
51PropertyPage::~PropertyPage ()
52{
53}
54
55bool PropertyPage::Create (int TemplateID)
56{
57 return Create (NULL, NULL, TemplateID);
58}
59
60bool PropertyPage::Create (DLGPROC dlgproc, int TemplateID)
61{
62 return Create (dlgproc, NULL, TemplateID);
63}
64
65bool
2f3a74d1 66PropertyPage::Create (DLGPROC dlgproc,
df62e023
RC
67 BOOL (*cproc) (HWND h, int id, HWND hwndctl,
68 UINT code), int TemplateID)
69{
70 psp.dwSize = sizeof (PROPSHEETPAGE);
71 psp.dwFlags = 0;
72 psp.hInstance = GetInstance ();
73 psp.pfnDlgProc = FirstDialogProcReflector;
5039f845 74 psp.pszTemplate = MAKEINTRESOURCE(TemplateID);
df62e023
RC
75 psp.lParam = (LPARAM) this;
76 psp.pfnCallback = NULL;
77
78 proc = dlgproc;
79 cmdproc = cproc;
80
81 return true;
82}
83
84BOOL CALLBACK
85PropertyPage::FirstDialogProcReflector (HWND hwnd, UINT message,
86 WPARAM wParam, LPARAM lParam)
87{
88 PropertyPage *This;
89
90 if (message != WM_INITDIALOG)
91 {
92 // Don't handle anything until we get a WM_INITDIALOG message, which
106d8160 93 // will have our 'this' pointer with it.
df62e023
RC
94 return FALSE;
95 }
96
97 This = (PropertyPage *) (((PROPSHEETPAGE *) lParam)->lParam);
98
99 SetWindowLong (hwnd, DWL_USER, (DWORD) This);
100 SetWindowLong (hwnd, DWL_DLGPROC, (DWORD) DialogProcReflector);
101
102 This->SetHWND (hwnd);
103 return This->DialogProc (message, wParam, lParam);
104}
105
106BOOL CALLBACK
107PropertyPage::DialogProcReflector (HWND hwnd, UINT message, WPARAM wParam,
108 LPARAM lParam)
109{
110 PropertyPage *This;
111
112 This = (PropertyPage *) GetWindowLong (hwnd, DWL_USER);
113
114 return This->DialogProc (message, wParam, lParam);
115}
116
117BOOL CALLBACK
118PropertyPage::DialogProc (UINT message, WPARAM wParam, LPARAM lParam)
119{
4d7a6eeb
MB
120 try
121 {
122 if (proc != NULL)
df62e023
RC
123 {
124 proc (GetHWND (), message, wParam, lParam);
125 }
126
4d7a6eeb 127 bool retval;
df62e023 128
4d7a6eeb 129 switch (message)
df62e023 130 {
4d7a6eeb
MB
131 case WM_INITDIALOG:
132 {
133 OnInit ();
134
135 setTitleFont ();
136
137 // Call it here so it stores the initial client rect.
138 sizeProcessor.UpdateSize (GetHWND ());
139
140 // TRUE = Set focus to default control (in wParam).
141 return TRUE;
4d7a6eeb
MB
142 }
143 case WM_NOTIFY:
144 switch (((NMHDR FAR *) lParam)->code)
145 {
146 case PSN_APPLY:
37f49caf
BD
147 {
148 SetWindowLong (GetHWND (), DWL_MSGRESULT, PSNRET_NOERROR);
149 return TRUE;
150 }
4d7a6eeb
MB
151 case PSN_SETACTIVE:
152 {
153 if (DoOnceForSheet)
154 {
155 // Tell our parent PropSheet what its own HWND is.
156 GetOwner ()->SetHWNDFromPage (((NMHDR FAR *) lParam)->
157 hwndFrom);
158 GetOwner ()->CenterWindow ();
159 DoOnceForSheet = false;
160 }
161
162 GetOwner ()->AdjustPageSize (GetHWND ());
163
164 // Set the wizard buttons apropriately
165 if (IsFirst)
166 {
167 // Disable "Back" on first page.
168 GetOwner ()->SetButtons (PSWIZB_NEXT);
169 }
170 else if (IsLast)
171 {
172 // Disable "Next", enable "Finish" on last page
173 GetOwner ()->SetButtons (PSWIZB_BACK | PSWIZB_FINISH);
174 }
175 else
176 {
177 // Middle page, enable both "Next" and "Back" buttons
178 GetOwner ()->SetButtons (PSWIZB_BACK | PSWIZB_NEXT);
179 }
180
181 if(!wantsActivation())
182 {
183 ::SetWindowLong (GetHWND (), DWL_MSGRESULT, -1);
184 return TRUE;
185 }
186
187 OnActivate ();
188
189 if (unattended_mode)
190 {
191 // -2 == disable unattended mode, display page
192 // -1 == display page but stay in unattended mode (progress bars)
193 // 0 == skip to next page
194 // IDD_* == skip to specified page
195 long nextwindow = OnUnattended();
196 if (nextwindow == -2)
197 {
198 unattended_mode = false;
199 SetWindowLong (GetHWND (), DWL_MSGRESULT, 0);
200 return TRUE;
201 }
202 else if (nextwindow == -1)
203 {
204 SetWindowLong (GetHWND (), DWL_MSGRESULT, 0);
205 return TRUE;
206 }
207 else if (nextwindow == 0)
208 {
209 SetWindowLong (GetHWND (), DWL_MSGRESULT, -1);
210 return TRUE;
211 }
212 else
213 {
214 SetWindowLong (GetHWND (), DWL_MSGRESULT, nextwindow);
215 return TRUE;
216 }
217 }
218 else
219 {
220 // 0 == Accept activation, -1 = Don't accept
221 ::SetWindowLong (GetHWND (), DWL_MSGRESULT, 0);
222 return TRUE;
223 }
224
225 }
226 break;
227 case PSN_KILLACTIVE:
37f49caf
BD
228 {
229 OnDeactivate ();
230 // FALSE = Allow deactivation
231 SetWindowLong (GetHWND (), DWL_MSGRESULT, FALSE);
232 return TRUE;
233 }
4d7a6eeb
MB
234 case PSN_WIZNEXT:
235 {
236 LONG retval;
237 retval = OnNext ();
238 SetWindowLong (GetHWND (), DWL_MSGRESULT, retval);
239 return TRUE;
240 }
4d7a6eeb
MB
241 case PSN_WIZBACK:
242 {
243 LONG retval;
244 retval = OnBack ();
245 SetWindowLong (GetHWND (), DWL_MSGRESULT, retval);
246 return TRUE;
247 }
4d7a6eeb 248 case PSN_WIZFINISH:
37f49caf
BD
249 {
250 retval = OnFinish ();
251 // False = Allow the wizard to finish
252 SetWindowLong (GetHWND (), DWL_MSGRESULT, FALSE);
253 return TRUE;
254 }
255 case TTN_GETDISPINFO:
256 {
257 return TooltipNotificationHandler (lParam);
258 }
4d7a6eeb 259 default:
37f49caf
BD
260 {
261 // Unrecognized notification
262 return FALSE;
263 }
4d7a6eeb
MB
264 }
265 break;
266 case WM_COMMAND:
267 {
268 bool retval;
269
270 retval =
271 OnMessageCmd (LOWORD (wParam), (HWND) lParam, HIWORD (wParam));
272 if (retval == true)
273 {
274 // Handled, return 0
275 SetWindowLong (GetHWND (), DWL_MSGRESULT, 0);
276 return TRUE;
277 }
278 else if (cmdproc != NULL)
279 {
4875ac88
MB
280 cmdproc (GetHWND(), LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
281 return 0;
4d7a6eeb
MB
282 }
283 break;
284 }
285 case WM_SIZE:
286 {
287 sizeProcessor.UpdateSize (GetHWND ());
288 break;
289 }
daab12c7
BD
290 case WM_CTLCOLORSTATIC:
291 {
292 // check for text controls that we've url-ified that are initializing
293 int id;
294 std::map <int, ClickableURL>::iterator theURL;
295
296 // get the ID of the control, and look it up in our list
297 if ((id = GetDlgCtrlID ((HWND)lParam)) == 0 ||
298 (theURL = urls.find (id)) == urls.end ())
299
300 // nope sorry, don't know nothing about this control
301 return FALSE;
302
303 // set FG = blue, BG = default background for a dialog
304 SetTextColor ((HDC)wParam, RGB (0, 0, 255));
305 SetBkColor ((HDC)wParam, GetSysColor (COLOR_BTNFACE));
306
307 // get the current font, add underline, and set it back
308 if (theURL->second.font == 0)
309 {
310 TEXTMETRIC tm;
311
312 GetTextMetrics ((HDC)wParam, &tm);
313 LOGFONT lf;
314 memset ((void *)&lf, 0, sizeof(LOGFONT));
315 lf.lfUnderline = TRUE;
316 lf.lfHeight = tm.tmHeight;
317 lf.lfWeight = tm.tmWeight;
318 lf.lfItalic = tm.tmItalic;
319 lf.lfStrikeOut = tm.tmStruckOut;
320 lf.lfCharSet = tm.tmCharSet;
321 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
322 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
323 lf.lfQuality = DEFAULT_QUALITY;
324 lf.lfPitchAndFamily = tm.tmPitchAndFamily;
325 GetTextFace ((HDC)wParam, LF_FACESIZE, lf.lfFaceName);
326 if ((theURL->second.font = CreateFontIndirect (&lf)) == NULL)
327 log(LOG_PLAIN) << "Warning: unable to set font for url "
328 << theURL->second.url << endLog;
329 }
330
331 // apply the font
332 SelectObject ((HDC)wParam, theURL->second.font);
333
334 // make a brush if we have not yet
335 if (theURL->second.brush == NULL)
336 theURL->second.brush = CreateSolidBrush
337 (GetSysColor (COLOR_BTNFACE));
338
339 // now this is really crazy, but apparently MSDN says we are to
340 // cast this brush as a BOOL and return it (?!)
341 return (BOOL)theURL->second.brush;
342 }
82306ac2
BD
343 case WM_MOUSEWHEEL:
344 // we do this so that derived classes that wish to process this message
345 // do not need to reimplement the entire WinProc, they can just
346 // provice an OnMouseWheel. (Note that mousewheel events are delivered
347 // to the parent of the window that received the scroll, so it would
348 // not work to just process this message there.)
349 return OnMouseWheel (message, wParam, lParam);
350 break;
4d7a6eeb
MB
351 default:
352 break;
df62e023
RC
353 }
354
4d7a6eeb 355 if ((message >= WM_APP) && (message < 0xC000))
df62e023
RC
356 {
357 // It's a private app message
358 return OnMessageApp (message, wParam, lParam);
359 }
4d7a6eeb
MB
360 }
361 TOPLEVEL_CATCH("DialogProc");
df62e023
RC
362
363 // Wasn't handled
364 return FALSE;
365}
25130a4d 366
82306ac2
BD
367BOOL CALLBACK
368PropertyPage::OnMouseWheel (UINT message, WPARAM wParam, LPARAM lParam)
369{
370 return 1; // not handled; define in a derived class to support this
371}
372
25130a4d
MB
373void
374PropertyPage::setTitleFont ()
375{
376 // These font settings will just silently fail when the resource id
377 // is not present on a page.
378 // Set header title font of each internal page
379 SetDlgItemFont(IDC_STATIC_HEADER_TITLE, "MS Shell Dlg", 8, FW_BOLD);
380 // Set the font for the IDC_STATIC_WELCOME_TITLE
381 SetDlgItemFont(IDC_STATIC_WELCOME_TITLE, "Arial", 12, FW_BOLD);
382}
daab12c7
BD
383
384std::map <int, PropertyPage::ClickableURL> PropertyPage::urls;
385
386void
387PropertyPage::makeClickable (int id, String link)
388// turns a static text control in this dialog into a hyperlink
389{
390 // get the handle of the specified control
391 HWND hctl = ::GetDlgItem (GetHWND (), id);
392 if (hctl == NULL)
393 return; // invalid ID
394
395 if (urls.find (id) != urls.end ())
396 return; // already done this one
397
398 ClickableURL c;
399 c.url = link;
400 c.font = NULL; // these will be created as needed
401 c.brush = NULL;
402 if ((c.origWinProc = reinterpret_cast<WNDPROC>(SetWindowLongPtr (hctl,
403 GWLP_WNDPROC, (LONG_PTR) & PropertyPage::urlWinProc))) == 0)
404 return; // failure
405
406 // add this to 'urls' so that the dialog and control winprocs know about it
407 urls[id] = c;
37f49caf
BD
408
409 // set a tooltip for the link
410 AddTooltip (id, link.c_str());
daab12c7
BD
411}
412
413LRESULT CALLBACK
414PropertyPage::urlWinProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
415// a winproc that we use to subclass a static text control to make a URL
416{
417 int id;
418 std::map <int, ClickableURL>::iterator theURL;
419
420 // get the ID of the control, and look it up in our list
421 if ((id = GetDlgCtrlID (hwnd)) == 0 ||
422 (theURL = urls.find (id)) == urls.end ())
423
424 // we were called for a control that we weren't installed on
425 // punt to default winproc
426 return DefWindowProc (hwnd, uMsg, wParam, lParam);
427
428 switch (uMsg)
429 {
430 case WM_LBUTTONDOWN:
431 {
432 // they clicked our URL! yay!
433 int rc = (int)ShellExecute (hwnd, "open",
d2a3615c 434 theURL->second.url.c_str (), NULL, NULL, SW_SHOWNORMAL);
daab12c7
BD
435
436 if (rc <= 32)
437 log(LOG_PLAIN) << "Unable to launch browser for URL " <<
438 theURL->second.url << " (rc = " << rc << ")" << endLog;
439 break;
440 }
441 case WM_SETCURSOR:
442 {
443 // show the hand cursor when they hover
444 // note: apparently the hand cursor isn't available
445 // on very old versions of win95? So, check return of LoadCursor
446 // and don't attempt SetCursor if it failed
447 HCURSOR c = LoadCursor (NULL, reinterpret_cast<LPCSTR>(IDC_HAND));
448 if (c)
449 SetCursor (c);
450 return TRUE;
451 }
452 case WM_NCHITTEST:
453 {
454 // normally, a static control returns HTTRANSPARENT for this
455 // which means that we would never receive the SETCURSOR message
456 return HTCLIENT;
457 }
458 case WM_DESTROY:
459 {
460 // clean up
461 WNDPROC saveWinProc = theURL->second.origWinProc;
462 DeleteObject (theURL->second.font);
463 DeleteObject (theURL->second.brush);
464 urls.erase (id);
465 return CallWindowProc (saveWinProc, hwnd, uMsg, wParam, lParam);
466 }
467 }
468
469 // pass on control to the previous winproc
470 return CallWindowProc (theURL->second.origWinProc, hwnd, uMsg, wParam, lParam);
471}
This page took 0.085827 seconds and 5 git commands to generate.