De-clutter the mirror selection listbox
[cygwin-setup.git] / proppage.cc
blob8da1c52e1a720fc9ec795114788756ca983ec3a0
1 /*
2 * Copyright (c) 2001, 2002, 2003 Gary R. Van Sickle.
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.
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
12 * Written by Gary R. Van Sickle <g.r.vansickle@worldnet.att.net>
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.
19 #include "proppage.h"
20 #include "propsheet.h"
21 #include "win32.h"
22 #include <shellapi.h>
23 #include "resource.h"
24 #include "state.h"
26 #include "getopt++/BoolOption.h"
27 #include "Exception.h"
28 #include "LogSingleton.h"
30 bool PropertyPage::DoOnceForSheet = true;
33 Sizing information for some controls that are common to all pages.
35 static ControlAdjuster::ControlInfo DefaultControlsInfo[] = {
36 {IDC_HEADICON, CP_RIGHT, CP_TOP},
37 {IDC_HEADSEPARATOR, CP_STRETCH, CP_TOP},
38 {0, CP_LEFT, CP_TOP}
41 PropertyPage::PropertyPage ()
43 proc = NULL;
44 cmdproc = NULL;
45 IsFirst = false;
46 IsLast = false;
48 sizeProcessor.AddControlInfo (DefaultControlsInfo);
51 PropertyPage::~PropertyPage ()
55 bool PropertyPage::Create (int TemplateID)
57 return Create (NULL, NULL, TemplateID);
60 bool PropertyPage::Create (DLGPROC dlgproc, int TemplateID)
62 return Create (dlgproc, NULL, TemplateID);
65 bool
66 PropertyPage::Create (DLGPROC dlgproc,
67 BOOL (*cproc) (HWND h, int id, HWND hwndctl,
68 UINT code), int TemplateID)
70 memset(&psp, 0, sizeof (PROPSHEETPAGE));
71 psp.dwSize = sizeof (PROPSHEETPAGE);
72 psp.dwFlags = 0;
73 psp.hInstance = GetInstance ();
74 psp.pfnDlgProc = FirstDialogProcReflector;
75 psp.pszTemplate = MAKEINTRESOURCE(TemplateID);
76 psp.lParam = (LPARAM) this;
77 psp.pfnCallback = NULL;
79 proc = dlgproc;
80 cmdproc = cproc;
82 return true;
85 INT_PTR CALLBACK
86 PropertyPage::FirstDialogProcReflector (HWND hwnd, UINT message,
87 WPARAM wParam, LPARAM lParam)
89 PropertyPage *This;
91 if (message != WM_INITDIALOG)
93 // Don't handle anything until we get a WM_INITDIALOG message, which
94 // will have our 'this' pointer with it.
95 return FALSE;
98 This = (PropertyPage *) (((PROPSHEETPAGE *) lParam)->lParam);
100 SetWindowLongPtr (hwnd, DWLP_USER, (LONG_PTR) This);
101 SetWindowLongPtr (hwnd, DWLP_DLGPROC, (LONG_PTR) DialogProcReflector);
103 This->SetHWND (hwnd);
104 return This->DialogProc (message, wParam, lParam);
107 INT_PTR CALLBACK
108 PropertyPage::DialogProcReflector (HWND hwnd, UINT message, WPARAM wParam,
109 LPARAM lParam)
111 PropertyPage *This;
113 This = (PropertyPage *) GetWindowLongPtr (hwnd, DWLP_USER);
115 return This->DialogProc (message, wParam, lParam);
118 INT_PTR CALLBACK
119 PropertyPage::DialogProc (UINT message, WPARAM wParam, LPARAM lParam)
123 if (proc != NULL)
125 proc (GetHWND (), message, wParam, lParam);
128 switch (message)
130 case WM_INITDIALOG:
132 OnInit ();
134 setTitleFont ();
136 // Call it here so it stores the initial client rect.
137 sizeProcessor.UpdateSize (GetHWND ());
139 // TRUE = Set focus to default control (in wParam).
140 return TRUE;
142 case WM_NOTIFY:
144 NMHDR *pNmHdr = (NMHDR *) lParam;
146 // offer to subclass first
147 LRESULT result = 0;
148 if (OnNotify (pNmHdr, &result))
150 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, result);
151 return TRUE;
154 switch (pNmHdr->code)
156 case PSN_APPLY:
158 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, PSNRET_NOERROR);
159 return TRUE;
161 case PSN_SETACTIVE:
163 if (DoOnceForSheet)
165 // Tell our parent PropSheet what its own HWND is.
166 GetOwner ()->SetHWNDFromPage (((NMHDR FAR *) lParam)->
167 hwndFrom);
168 GetOwner ()->CenterWindow ();
169 DoOnceForSheet = false;
172 GetOwner ()->AdjustPageSize (GetHWND ());
174 // Set the wizard buttons apropriately
175 if (IsFirst)
177 // Disable "Back" on first page.
178 GetOwner ()->SetButtons (PSWIZB_NEXT);
180 else if (IsLast)
182 // Disable "Next", enable "Finish" on last page
183 GetOwner ()->SetButtons (PSWIZB_BACK | PSWIZB_FINISH);
185 else
187 // Middle page, enable both "Next" and "Back" buttons
188 GetOwner ()->SetButtons (PSWIZB_BACK | PSWIZB_NEXT);
191 if(!wantsActivation())
193 ::SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, -1);
194 return TRUE;
197 OnActivate ();
199 if (unattended_mode)
201 // -2 == disable unattended mode, display page
202 // -1 == display page but stay in unattended mode (progress bars)
203 // 0 == skip to next page (in propsheet sequence)
204 // IDD_* == skip to specified page
205 long nextwindow = OnUnattended();
206 if (nextwindow == -2)
208 unattended_mode = attended;
209 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, 0);
210 return TRUE;
212 else if (nextwindow == -1)
214 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, 0);
215 return TRUE;
217 else if (nextwindow == 0)
219 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, -1);
220 return TRUE;
222 else
224 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, nextwindow);
225 return TRUE;
228 else
230 // 0 == Accept activation, -1 = Don't accept
231 ::SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, 0);
232 return TRUE;
236 break;
237 case PSN_KILLACTIVE:
239 OnDeactivate ();
240 // FALSE = Allow deactivation
241 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, FALSE);
242 return TRUE;
244 case PSN_WIZNEXT:
246 LONG retval;
247 retval = OnNext ();
248 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, retval);
249 return TRUE;
251 case PSN_WIZBACK:
253 LONG retval;
254 retval = OnBack ();
255 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, retval);
256 return TRUE;
258 case PSN_WIZFINISH:
260 OnFinish ();
261 // False = Allow the wizard to finish
262 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, FALSE);
263 return TRUE;
265 case TTN_GETDISPINFO:
267 return TooltipNotificationHandler (lParam);
269 default:
271 // Unrecognized notification
272 return FALSE;
276 break;
277 case WM_COMMAND:
279 bool retval;
281 retval =
282 OnMessageCmd (LOWORD (wParam), (HWND) lParam, HIWORD (wParam));
283 if (retval == true)
285 // Handled, return 0
286 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, 0);
287 return TRUE;
289 else if (cmdproc != NULL)
291 cmdproc (GetHWND(), LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
292 return 0;
294 break;
296 case WM_SIZE:
298 sizeProcessor.UpdateSize (GetHWND ());
299 break;
301 case WM_CTLCOLORSTATIC:
303 // check for text controls that we've url-ified that are initializing
304 int id;
305 std::map <int, ClickableURL>::iterator theURL;
307 // get the ID of the control, and look it up in our list
308 if ((id = GetDlgCtrlID ((HWND)lParam)) == 0 ||
309 (theURL = urls.find (id)) == urls.end ())
311 // nope sorry, don't know nothing about this control
312 return FALSE;
314 // set FG = blue, BG = default background for a dialog
315 SetTextColor ((HDC)wParam, RGB (0, 0, 255));
316 SetBkColor ((HDC)wParam, GetSysColor (COLOR_BTNFACE));
318 // get the current font, add underline, and set it back
319 if (theURL->second.font == 0)
321 TEXTMETRIC tm;
323 GetTextMetrics ((HDC)wParam, &tm);
324 LOGFONT lf;
325 memset ((void *)&lf, 0, sizeof(LOGFONT));
326 lf.lfUnderline = TRUE;
327 lf.lfHeight = tm.tmHeight;
328 lf.lfWeight = tm.tmWeight;
329 lf.lfItalic = tm.tmItalic;
330 lf.lfStrikeOut = tm.tmStruckOut;
331 lf.lfCharSet = tm.tmCharSet;
332 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
333 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
334 lf.lfQuality = DEFAULT_QUALITY;
335 lf.lfPitchAndFamily = tm.tmPitchAndFamily;
336 GetTextFace ((HDC)wParam, LF_FACESIZE, lf.lfFaceName);
337 if ((theURL->second.font = CreateFontIndirect (&lf)) == NULL)
338 Log (LOG_PLAIN) << "Warning: unable to set font for url "
339 << theURL->second.url << endLog;
342 // apply the font
343 SelectObject ((HDC)wParam, theURL->second.font);
345 // make a brush if we have not yet
346 if (theURL->second.brush == NULL)
347 theURL->second.brush = CreateSolidBrush
348 (GetSysColor (COLOR_BTNFACE));
350 return (INT_PTR) theURL->second.brush;
352 case WM_MOUSEWHEEL:
353 // we do this so that derived classes that wish to process this message
354 // do not need to reimplement the entire WinProc, they can just
355 // provice an OnMouseWheel. (Note that mousewheel events are delivered
356 // to the parent of the window that received the scroll, so it would
357 // not work to just process this message there.)
358 return OnMouseWheel (message, wParam, lParam);
360 case WM_TIMER:
361 // similar delegation as with WM_MOUSEWHEEL
362 return OnTimerMessage (message, wParam, lParam);
364 default:
365 break;
368 if ((message >= WM_APP) && (message < 0xC000))
370 // It's a private app message
371 return OnMessageApp (message, wParam, lParam);
374 TOPLEVEL_CATCH(GetHWND (), "DialogProc");
376 // Wasn't handled
377 return FALSE;
380 INT_PTR CALLBACK
381 PropertyPage::OnMouseWheel (UINT message, WPARAM wParam, LPARAM lParam)
383 return 1; // not handled; define in a derived class to support this
386 INT_PTR CALLBACK
387 PropertyPage::OnTimerMessage (UINT message, WPARAM wParam, LPARAM lParam)
389 return 1; // not handled; define in a derived class to support this
392 void
393 PropertyPage::setTitleFont ()
395 // These font settings will just silently fail when the resource id
396 // is not present on a page.
397 // Set header title font of each internal page
398 SetDlgItemFont(IDC_STATIC_HEADER_TITLE, "MS Shell Dlg", 8, FW_BOLD);
399 // Set the font for the IDC_STATIC_WELCOME_TITLE
400 SetDlgItemFont(IDC_STATIC_WELCOME_TITLE, "Arial", 12, FW_BOLD);
403 std::map <int, PropertyPage::ClickableURL> PropertyPage::urls;
405 void
406 PropertyPage::makeClickable (int id, std::string link)
407 // turns a static text control in this dialog into a hyperlink
409 // get the handle of the specified control
410 HWND hctl = ::GetDlgItem (GetHWND (), id);
411 if (hctl == NULL)
412 return; // invalid ID
414 if (urls.find (id) != urls.end ())
415 return; // already done this one
417 ClickableURL c;
418 c.url = link;
419 c.font = NULL; // these will be created as needed
420 c.brush = NULL;
421 if ((c.origWinProc = reinterpret_cast<WNDPROC>(SetWindowLongPtr (hctl,
422 GWLP_WNDPROC, (LONG_PTR) & PropertyPage::urlWinProc))) == 0)
423 return; // failure
425 // add this to 'urls' so that the dialog and control winprocs know about it
426 urls[id] = c;
428 // set a tooltip for the link
429 AddTooltip (id, link.c_str());
432 LRESULT CALLBACK
433 PropertyPage::urlWinProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
434 // a winproc that we use to subclass a static text control to make a URL
436 int id;
437 std::map <int, ClickableURL>::iterator theURL;
439 // get the ID of the control, and look it up in our list
440 if ((id = GetDlgCtrlID (hwnd)) == 0 ||
441 (theURL = urls.find (id)) == urls.end ())
443 // we were called for a control that we weren't installed on
444 // punt to default winproc
445 return DefWindowProc (hwnd, uMsg, wParam, lParam);
447 switch (uMsg)
449 case WM_LBUTTONDOWN:
451 // they clicked our URL! yay!
452 intptr_t rc = (intptr_t) ShellExecute (hwnd, "open",
453 theURL->second.url.c_str (), NULL, NULL, SW_SHOWNORMAL);
455 if (rc <= 32)
456 Log (LOG_PLAIN) << "Unable to launch browser for URL " <<
457 theURL->second.url << " (rc = " << rc << ")" << endLog;
458 break;
460 case WM_SETCURSOR:
462 // show the hand cursor when they hover
463 // note: apparently the hand cursor isn't available
464 // on very old versions of win95? So, check return of LoadCursor
465 // and don't attempt SetCursor if it failed
466 HCURSOR c = LoadCursor (NULL, reinterpret_cast<LPCSTR>(IDC_HAND));
467 if (c)
468 SetCursor (c);
469 return TRUE;
471 case WM_NCHITTEST:
473 // normally, a static control returns HTTRANSPARENT for this
474 // which means that we would never receive the SETCURSOR message
475 return HTCLIENT;
477 case WM_DESTROY:
479 // clean up
480 WNDPROC saveWinProc = theURL->second.origWinProc;
481 DeleteObject (theURL->second.font);
482 DeleteObject (theURL->second.brush);
483 urls.erase (id);
484 return CallWindowProc (saveWinProc, hwnd, uMsg, wParam, lParam);
488 // pass on control to the previous winproc
489 return CallWindowProc (theURL->second.origWinProc, hwnd, uMsg, wParam, lParam);