Fixed issue #2507: Support keyboard shortcuts in yes/no prompts
[TortoiseGit.git] / src / Utils / MiscUI / StandAloneDlg.h
blobbdcfa4b0face22aa427be0287d9bb886f65209cf
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2015 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #pragma once
21 #include "ResizableDialog.h"
22 #include "TaskbarUUID.h"
23 #include "Tooltip.h"
25 #pragma comment(lib, "htmlhelp.lib")
27 /**
28 * \ingroup TortoiseProc
30 * A template which can be used as the base-class of dialogs which form the main dialog
31 * of a 'dialog-style application'
32 * Just provides the boiler-plate code for dealing with application icons
34 * \remark Replace all references to CDialog or CResizableDialog in your dialog class with
35 * either CResizableStandAloneDialog, CStandAloneDialog or CStateStandAloneDialog, as appropriate
37 template <typename BaseType> class CStandAloneDialogTmpl : public BaseType
39 protected:
40 CStandAloneDialogTmpl(UINT nIDTemplate, CWnd* pParentWnd = NULL) : BaseType(nIDTemplate, pParentWnd)
42 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
44 virtual BOOL OnInitDialog()
46 BaseType::OnInitDialog();
48 // Set the icon for this dialog. The framework does this automatically
49 // when the application's main window is not a dialog
50 SetIcon(m_hIcon, TRUE); // Set big icon
51 SetIcon(m_hIcon, FALSE); // Set small icon
53 EnableToolTips();
54 m_tooltips.Create(this);
56 return FALSE;
59 virtual BOOL PreTranslateMessage(MSG* pMsg)
61 m_tooltips.RelayEvent(pMsg, this);
62 if (pMsg->message == WM_KEYDOWN)
64 int nVirtKey = (int) pMsg->wParam;
66 if (nVirtKey == 'A' && (GetKeyState(VK_CONTROL) & 0x8000 ) )
68 TCHAR buffer[129];
69 ::GetClassName(pMsg->hwnd, buffer,128);
71 if(_tcsnicmp(buffer,_T("EDIT"),128) == 0)
73 ::PostMessage(pMsg->hwnd,EM_SETSEL,0,-1);
74 return TRUE;
78 return BaseType::PreTranslateMessage(pMsg);
80 afx_msg void OnPaint()
82 if (IsIconic())
84 CPaintDC dc(this); // device context for painting
86 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
88 // Center icon in client rectangle
89 int cxIcon = GetSystemMetrics(SM_CXICON);
90 int cyIcon = GetSystemMetrics(SM_CYICON);
91 CRect rect;
92 GetClientRect(&rect);
93 int x = (rect.Width() - cxIcon + 1) / 2;
94 int y = (rect.Height() - cyIcon + 1) / 2;
96 // Draw the icon
97 dc.DrawIcon(x, y, m_hIcon);
99 else
101 BaseType::OnPaint();
105 * Wrapper around the CWnd::EnableWindow() method, but
106 * makes sure that a control that has the focus is not disabled
107 * before the focus is passed on to the next control.
109 BOOL DialogEnableWindow(UINT nID, BOOL bEnable)
111 CWnd * pwndDlgItem = GetDlgItem(nID);
112 if (pwndDlgItem == NULL)
113 return FALSE;
114 if (bEnable)
115 return pwndDlgItem->EnableWindow(bEnable);
116 if (GetFocus() == pwndDlgItem)
118 SendMessage(WM_NEXTDLGCTL, 0, FALSE);
120 return pwndDlgItem->EnableWindow(bEnable);
124 * Adjusts the size of a checkbox or radio button control.
125 * Since we always make the size of those bigger than 'necessary'
126 * for making sure that translated strings can fit in those too,
127 * this method can reduce the size of those controls again to only
128 * fit the text.
130 RECT AdjustControlSize(UINT nID)
132 CWnd * pwndDlgItem = GetDlgItem(nID);
133 // adjust the size of the control to fit its content
134 CString sControlText;
135 pwndDlgItem->GetWindowText(sControlText);
136 // next step: find the rectangle the control text needs to
137 // be displayed
139 CDC * pDC = pwndDlgItem->GetWindowDC();
140 RECT controlrect;
141 RECT controlrectorig;
142 pwndDlgItem->GetWindowRect(&controlrect);
143 ::MapWindowPoints(NULL, GetSafeHwnd(), (LPPOINT)&controlrect, 2);
144 controlrectorig = controlrect;
145 if (pDC)
147 CFont * font = pwndDlgItem->GetFont();
148 CFont * pOldFont = pDC->SelectObject(font);
149 if (pDC->DrawText(sControlText, -1, &controlrect, DT_WORDBREAK | DT_EDITCONTROL | DT_EXPANDTABS | DT_LEFT | DT_CALCRECT))
151 // now we have the rectangle the control really needs
152 if ((controlrectorig.right - controlrectorig.left) > (controlrect.right - controlrect.left))
154 // we're dealing with radio buttons and check boxes,
155 // which means we have to add a little space for the checkbox
156 // the value of 3 pixels added here is necessary in case certain visual styles have
157 // been disabled. Without this, the width is calculated too short.
158 const int checkWidth = GetSystemMetrics(SM_CXMENUCHECK) + 2*GetSystemMetrics(SM_CXEDGE) + 3;
159 controlrectorig.right = controlrectorig.left + (controlrect.right - controlrect.left) + checkWidth;
160 pwndDlgItem->MoveWindow(&controlrectorig);
163 pDC->SelectObject(pOldFont);
164 ReleaseDC(pDC);
166 return controlrectorig;
170 * Adjusts the size of a static control.
171 * \param nID control ID
172 * \param rc the position of the control where this control shall
173 * be positioned next to on its right side.
174 * \param spacing number of pixels to add to rc.right
176 RECT AdjustStaticSize(UINT nID, RECT rc, long spacing)
178 CWnd * pwndDlgItem = GetDlgItem(nID);
179 // adjust the size of the control to fit its content
180 CString sControlText;
181 pwndDlgItem->GetWindowText(sControlText);
182 // next step: find the rectangle the control text needs to
183 // be displayed
185 CDC * pDC = pwndDlgItem->GetWindowDC();
186 RECT controlrect;
187 RECT controlrectorig;
188 pwndDlgItem->GetWindowRect(&controlrect);
189 ::MapWindowPoints(NULL, GetSafeHwnd(), (LPPOINT)&controlrect, 2);
190 controlrect.right += 200; // in case the control needs to be bigger than it currently is (e.g., due to translations)
191 controlrectorig = controlrect;
193 long height = controlrectorig.bottom-controlrectorig.top;
194 long width = controlrectorig.right-controlrectorig.left;
195 controlrectorig.left = rc.right + spacing;
196 controlrectorig.right = controlrectorig.left + width;
197 controlrectorig.bottom = rc.bottom;
198 controlrectorig.top = controlrectorig.bottom - height;
200 if (pDC)
202 CFont * font = pwndDlgItem->GetFont();
203 CFont * pOldFont = pDC->SelectObject(font);
204 if (pDC->DrawText(sControlText, -1, &controlrect, DT_WORDBREAK | DT_EDITCONTROL | DT_EXPANDTABS | DT_LEFT | DT_CALCRECT))
206 // now we have the rectangle the control really needs
207 controlrectorig.right = controlrectorig.left + (controlrect.right - controlrect.left);
208 pwndDlgItem->MoveWindow(&controlrectorig);
210 pDC->SelectObject(pOldFont);
211 ReleaseDC(pDC);
213 return controlrectorig;
217 * Display a balloon with close button, anchored at a given edit control on this dialog.
219 void ShowEditBalloon(UINT nIdControl, UINT nIdText, UINT nIdTitle, int nIcon = TTI_WARNING)
221 CString text(MAKEINTRESOURCE(nIdText));
222 CString title(MAKEINTRESOURCE(nIdTitle));
223 ShowEditBalloon(nIdControl, text, title, nIcon);
225 void ShowEditBalloon(UINT nIdControl, const CString& text, const CString& title, int nIcon = TTI_WARNING)
227 EDITBALLOONTIP bt;
228 bt.cbStruct = sizeof(bt);
229 bt.pszText = text;
230 bt.pszTitle = title;
231 bt.ttiIcon = nIcon;
232 SendDlgItemMessage(nIdControl, EM_SHOWBALLOONTIP, 0, (LPARAM)&bt);
236 * Refreshes the cursor by forcing a WM_SETCURSOR message.
238 void RefreshCursor()
240 POINT pt;
241 GetCursorPos(&pt);
242 SetCursorPos(pt.x, pt.y);
245 protected:
246 CToolTips m_tooltips;
248 DECLARE_MESSAGE_MAP()
250 private:
251 HCURSOR OnQueryDragIcon()
253 return static_cast<HCURSOR>(m_hIcon);
256 virtual void HtmlHelp(DWORD_PTR dwData, UINT nCmd = 0x000F)
258 CWinApp* pApp = AfxGetApp();
259 ASSERT_VALID(pApp);
260 ASSERT(pApp->m_pszHelpFilePath != NULL);
261 // to call HtmlHelp the m_fUseHtmlHelp must be set in
262 // the application's constructor
263 ASSERT(pApp->m_eHelpType == afxHTMLHelp);
265 CWaitCursor wait;
267 PrepareForHelp();
268 // run the HTML Help engine
269 if (!::HtmlHelp(m_hWnd, pApp->m_pszHelpFilePath, nCmd, dwData))
271 AfxMessageBox(AFX_IDP_FAILED_TO_LAUNCH_HELP);
275 afx_msg LRESULT OnTaskbarButtonCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
277 SetUUIDOverlayIcon(m_hWnd);
278 return 0;
281 HICON m_hIcon;
284 class CStateDialog : public CDialog, public CResizableWndState
286 public:
287 CStateDialog()
288 : CDialog()
289 , m_bEnableSaveRestore(false)
290 , m_bRectOnly(false)
292 CStateDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL)
293 : CDialog(nIDTemplate, pParentWnd)
294 , m_bEnableSaveRestore(false)
295 , m_bRectOnly(false)
297 CStateDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL)
298 : CDialog(lpszTemplateName, pParentWnd)
299 , m_bEnableSaveRestore(false)
300 , m_bRectOnly(false)
302 virtual ~CStateDialog() {};
304 private:
305 // flags
306 bool m_bEnableSaveRestore;
307 bool m_bRectOnly;
309 // internal status
310 CString m_sSection; // section name (identifies a parent window)
312 protected:
313 // section to use in app's profile
314 void EnableSaveRestore(LPCTSTR pszSection, bool bRectOnly = FALSE)
316 m_sSection = pszSection;
318 m_bEnableSaveRestore = true;
319 m_bRectOnly = bRectOnly;
321 // restore immediately
322 LoadWindowRect(pszSection, bRectOnly);
325 virtual CWnd* GetResizableWnd() const
327 // make the layout know its parent window
328 return CWnd::FromHandle(m_hWnd);
331 afx_msg void OnDestroy()
333 if (m_bEnableSaveRestore)
334 SaveWindowRect(m_sSection, m_bRectOnly);
335 CDialog::OnDestroy();
338 DECLARE_MESSAGE_MAP()
342 class CResizableStandAloneDialog : public CStandAloneDialogTmpl<CResizableDialog>
344 public:
345 CResizableStandAloneDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL);
347 private:
348 DECLARE_DYNAMIC(CResizableStandAloneDialog)
350 protected:
351 afx_msg void OnSizing(UINT fwSide, LPRECT pRect);
352 afx_msg void OnMoving(UINT fwSide, LPRECT pRect);
353 afx_msg void OnNcMButtonUp(UINT nHitTest, CPoint point);
354 afx_msg void OnNcRButtonUp(UINT nHitTest, CPoint point);
356 DECLARE_MESSAGE_MAP()
358 private:
359 bool m_bVertical;
360 bool m_bHorizontal;
361 CRect m_rcOrgWindowRect;
364 class CStandAloneDialog : public CStandAloneDialogTmpl<CDialog>
366 public:
367 CStandAloneDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL);
368 protected:
369 DECLARE_MESSAGE_MAP()
370 private:
371 DECLARE_DYNAMIC(CStandAloneDialog)
374 class CStateStandAloneDialog : public CStandAloneDialogTmpl<CStateDialog>
376 public:
377 CStateStandAloneDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL);
378 protected:
379 DECLARE_MESSAGE_MAP()
380 private:
381 DECLARE_DYNAMIC(CStateStandAloneDialog)