Improve readability of version string
[TortoiseGit.git] / src / Utils / MiscUI / FilterEdit.cpp
blob1332a0d6ffa9d64a453934cb031a1088d621e246
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012, 2014, 2016 - TortoiseGit
4 // Copyright (C) 2007, 2012-2013 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "FilterEdit.h"
23 IMPLEMENT_DYNAMIC(CFilterEdit, CEdit)
25 CFilterEdit::CFilterEdit()
26 : m_hIconCancelNormal(nullptr)
27 , m_hIconCancelPressed(nullptr)
28 , m_hIconInfo(nullptr)
29 , m_bPressed(FALSE)
30 , m_bShowCancelButtonAlways(FALSE)
31 , m_iButtonClickedMessageId(WM_FILTEREDIT_INFOCLICKED)
32 , m_iCancelClickedMessageId(WM_FILTEREDIT_CANCELCLICKED)
33 , m_pValidator(nullptr)
34 , m_backColor(GetSysColor(COLOR_WINDOW))
35 , m_brBack(nullptr)
37 m_rcEditArea.SetRect(0, 0, 0, 0);
38 m_rcButtonArea.SetRect(0, 0, 0, 0);
39 m_rcInfoArea.SetRect(0, 0, 0, 0);
40 m_sizeInfoIcon.SetSize(0, 0);
41 m_sizeCancelIcon.SetSize(0, 0);
44 CFilterEdit::~CFilterEdit()
46 if (m_hIconCancelNormal)
47 DestroyIcon(m_hIconCancelNormal);
48 if (m_hIconCancelPressed)
49 DestroyIcon(m_hIconCancelPressed);
50 if (m_hIconInfo)
51 DestroyIcon(m_hIconInfo);
52 if (m_brBack)
53 DeleteObject(m_brBack);
56 BEGIN_MESSAGE_MAP(CFilterEdit, CEdit)
58 ON_MESSAGE(WM_SETFONT, OnSetFont)
59 ON_WM_SIZE()
60 ON_WM_ERASEBKGND()
61 ON_WM_KEYDOWN()
62 ON_WM_LBUTTONDOWN()
63 ON_WM_LBUTTONUP()
64 ON_WM_CREATE()
65 ON_WM_SETCURSOR()
66 ON_CONTROL_REFLECT_EX(EN_CHANGE, &CFilterEdit::OnEnChange)
67 ON_WM_CTLCOLOR_REFLECT()
68 ON_WM_PAINT()
69 ON_CONTROL_REFLECT(EN_KILLFOCUS, &CFilterEdit::OnEnKillfocus)
70 ON_CONTROL_REFLECT(EN_SETFOCUS, &CFilterEdit::OnEnSetfocus)
71 ON_MESSAGE(WM_PASTE, &CFilterEdit::OnPaste)
72 END_MESSAGE_MAP()
76 // CFilterEdit message handlers
78 void CFilterEdit::PreSubclassWindow( )
80 // We must have a multi line edit
81 // to be able to set the edit rect
82 ASSERT( GetStyle() & ES_MULTILINE );
84 ResizeWindow();
87 BOOL CFilterEdit::PreTranslateMessage( MSG* pMsg )
89 return CEdit::PreTranslateMessage(pMsg);
92 BOOL CFilterEdit::SetCancelBitmaps(UINT uCancelNormal, UINT uCancelPressed, BOOL bShowAlways)
94 m_bShowCancelButtonAlways = bShowAlways;
96 if (m_hIconCancelNormal)
97 DestroyIcon(m_hIconCancelNormal);
98 if (m_hIconCancelPressed)
99 DestroyIcon(m_hIconCancelPressed);
101 m_hIconCancelNormal = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(uCancelNormal), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
102 m_hIconCancelPressed = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(uCancelPressed), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
104 if (!m_hIconCancelNormal || !m_hIconCancelPressed)
105 return FALSE;
107 m_sizeCancelIcon = GetIconSize(m_hIconCancelNormal);
109 ResizeWindow();
110 return TRUE;
113 BOOL CFilterEdit::SetInfoIcon(UINT uInfo)
115 if (m_hIconInfo)
116 DestroyIcon(m_hIconInfo);
118 m_hIconInfo = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(uInfo), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
120 if (!m_hIconInfo)
121 return FALSE;
123 m_sizeInfoIcon = GetIconSize(m_hIconInfo);
125 ResizeWindow();
126 return TRUE;
129 BOOL CFilterEdit::SetCueBanner(LPCWSTR lpcwText)
131 if (lpcwText)
133 size_t len = _tcslen(lpcwText);
134 m_pCueBanner.reset(new TCHAR[len + 1]);
135 _tcscpy_s(m_pCueBanner.get(), len + 1, lpcwText);
136 InvalidateRect(nullptr, TRUE);
137 return TRUE;
139 return FALSE;
142 void CFilterEdit::ResizeWindow()
144 if (!::IsWindow(m_hWnd))
145 return;
147 RECT editrc, rc;
148 GetRect(&editrc);
149 GetClientRect(&rc);
150 editrc.left = rc.left + 4;
151 editrc.top = rc.top + 1;
152 editrc.right = rc.right - 4;
153 editrc.bottom = rc.bottom - 4;
155 m_rcEditArea.left = editrc.left + m_sizeInfoIcon.cx;
156 m_rcEditArea.right = editrc.right - m_sizeCancelIcon.cx - 5;
157 m_rcEditArea.top = editrc.top;
158 m_rcEditArea.bottom = editrc.bottom;
160 m_rcButtonArea.left = m_rcEditArea.right + 5;
161 m_rcButtonArea.right = rc.right;
162 m_rcButtonArea.top = (((rc.bottom)-m_sizeCancelIcon.cy)/2);
163 m_rcButtonArea.bottom = m_rcButtonArea.top + m_sizeCancelIcon.cy;
165 m_rcInfoArea.left = 0;
166 m_rcInfoArea.right = m_rcEditArea.left;
167 m_rcInfoArea.top = (((rc.bottom)-m_sizeInfoIcon.cy)/2);
168 m_rcInfoArea.bottom = m_rcInfoArea.top + m_sizeInfoIcon.cy;
170 SetRect(&m_rcEditArea);
173 void CFilterEdit::SetButtonClickedMessageId(UINT iButtonClickedMessageId, UINT iCancelClickedMessageId)
175 m_iButtonClickedMessageId = iButtonClickedMessageId;
176 m_iCancelClickedMessageId = iCancelClickedMessageId;
179 CSize CFilterEdit::GetIconSize(HICON hIcon)
181 CSize size(0, 0);
182 ICONINFO iconinfo;
183 if (GetIconInfo(hIcon, &iconinfo))
185 BITMAP bmp;
186 if (GetObject(iconinfo.hbmColor, sizeof(BITMAP), &bmp))
188 size.cx = bmp.bmWidth;
189 size.cy = bmp.bmHeight;
192 return size;
195 BOOL CFilterEdit::OnEraseBkgnd(CDC* pDC)
197 RECT rc;
198 GetClientRect(&rc);
199 pDC->FillSolidRect(&rc, m_backColor);
201 if (GetWindowTextLength() || m_bShowCancelButtonAlways)
203 if (!m_bPressed)
205 DrawIconEx(pDC->GetSafeHdc(), m_rcButtonArea.left, m_rcButtonArea.top, m_hIconCancelNormal,
206 m_sizeCancelIcon.cx, m_sizeCancelIcon.cy, 0, nullptr, DI_NORMAL);
208 else
210 DrawIconEx(pDC->GetSafeHdc(), m_rcButtonArea.left, m_rcButtonArea.top, m_hIconCancelPressed,
211 m_sizeCancelIcon.cx, m_sizeCancelIcon.cy, 0, nullptr, DI_NORMAL);
214 if (m_hIconInfo)
216 DrawIconEx(pDC->GetSafeHdc(), m_rcInfoArea.left, m_rcInfoArea.top, m_hIconInfo,
217 m_sizeInfoIcon.cx, m_sizeInfoIcon.cy, 0, nullptr, DI_NORMAL);
220 return TRUE;
223 void CFilterEdit::OnLButtonUp(UINT nFlags, CPoint point)
225 m_bPressed = FALSE;
226 InvalidateRect(nullptr);
227 if (m_rcButtonArea.PtInRect(point))
229 SetWindowText(_T(""));
230 CWnd *pOwner = GetOwner();
231 if (pOwner)
233 pOwner->SendMessage(m_iCancelClickedMessageId, (WPARAM)GetSafeHwnd(), 0);
235 Validate();
237 if (m_rcInfoArea.PtInRect(point))
239 CWnd *pOwner = GetOwner();
240 if (pOwner)
242 RECT rc = m_rcInfoArea;
243 ClientToScreen(&rc);
244 pOwner->SendMessage(m_iButtonClickedMessageId, (WPARAM)GetSafeHwnd(), (LPARAM)(LPRECT)&rc);
248 CEdit::OnLButtonUp(nFlags, point);
251 void CFilterEdit::OnLButtonDown(UINT nFlags, CPoint point)
253 m_bPressed = m_rcButtonArea.PtInRect(point);
254 //InvalidateRect(nullptr);
255 CEdit::OnLButtonDown(nFlags, point);
258 int CFilterEdit::OnCreate(LPCREATESTRUCT lpCreateStruct)
260 if (CEdit::OnCreate(lpCreateStruct) == -1)
261 return -1;
263 ResizeWindow();
265 return 0;
268 LRESULT CFilterEdit::OnSetFont( WPARAM wParam, LPARAM lParam )
270 DefWindowProc( WM_SETFONT, wParam, lParam );
272 ResizeWindow();
274 return 0;
277 void CFilterEdit::OnSize( UINT nType, int cx, int cy )
279 CEdit::OnSize( nType, cx, cy );
280 ResizeWindow();
283 BOOL CFilterEdit::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
285 CPoint pntCursor;
286 GetCursorPos(&pntCursor);
287 ScreenToClient(&pntCursor);
288 // if the cursor is not in the edit area, show the normal arrow cursor
289 if (!m_rcEditArea.PtInRect(pntCursor))
291 SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
292 return TRUE;
295 return CEdit::OnSetCursor(pWnd, nHitTest, message);
298 BOOL CFilterEdit::OnEnChange()
300 // check whether the entered text is valid
301 Validate();
302 InvalidateRect(nullptr);
303 return FALSE;
306 HBRUSH CFilterEdit::CtlColor(CDC* pDC, UINT /*nCtlColor*/)
308 if (m_backColor != GetSysColor(COLOR_WINDOW))
310 pDC->SetBkColor(m_backColor);
311 return m_brBack;
313 return nullptr;
316 void CFilterEdit::ValidateAndRedraw()
318 OnEnChange();
321 void CFilterEdit::Validate()
323 if (m_pValidator)
325 int len = GetWindowTextLength();
326 TCHAR * pBuf = new TCHAR[len+1];
327 GetWindowText(pBuf, len+1);
328 m_backColor = GetSysColor(COLOR_WINDOW);
329 if (!m_pValidator->Validate(pBuf))
331 // Use a background color slightly shifted to red.
332 // We do this by increasing red component and decreasing green and blue.
333 const int SHIFT_PRECENTAGE = 10;
334 int r = GetRValue(m_backColor);
335 int g = GetGValue(m_backColor);
336 int b = GetBValue(m_backColor);
338 r = min(r * (100 + SHIFT_PRECENTAGE) / 100, 255);
339 // Ensure that there is at least some redness.
340 r = max(r, 255 * SHIFT_PRECENTAGE / 100);
341 g = g * (100 - SHIFT_PRECENTAGE) / 100;
342 b = b * (100 - SHIFT_PRECENTAGE) / 100;
343 m_backColor = RGB(r, g, b);
344 if (m_brBack)
345 DeleteObject(m_brBack);
346 m_brBack = CreateSolidBrush(m_backColor);
348 delete [] pBuf;
352 void CFilterEdit::OnPaint()
354 LRESULT defres = Default();
356 DrawDimText();
357 if (defres)
359 // the Default() call did not process the WM_PAINT message!
360 // Validate the update region ourselves to avoid
361 // an endless loop repainting
362 CRect rc;
363 GetUpdateRect(&rc, FALSE);
364 if (!rc.IsRectEmpty())
365 ValidateRect(rc);
368 return;
371 void CFilterEdit::DrawDimText()
373 if (!m_pCueBanner.get())
374 return;
375 if (GetWindowTextLength())
376 return;
377 if (m_pCueBanner.get()[0] == 0)
378 return;
379 if (GetFocus() == this)
380 return;
382 CClientDC dcDraw(this);
383 CRect rRect;
384 int iState = dcDraw.SaveDC();
386 GetClientRect(&rRect);
387 rRect.OffsetRect(1, 1);
389 dcDraw.SelectObject((*GetFont()));
390 dcDraw.SetTextColor(GetSysColor(COLOR_GRAYTEXT));
391 dcDraw.SetBkColor(GetSysColor(COLOR_WINDOW));
392 dcDraw.DrawText(m_pCueBanner.get(), (int)_tcslen(m_pCueBanner.get()), &rRect, DT_CENTER | DT_VCENTER);
393 dcDraw.RestoreDC(iState);
394 return;
397 void CFilterEdit::OnEnKillfocus()
399 InvalidateRect(nullptr);
402 void CFilterEdit::OnEnSetfocus()
404 InvalidateRect(nullptr);
407 LRESULT CFilterEdit::OnPaste(WPARAM, LPARAM)
409 if (OpenClipboard())
411 HANDLE hData = GetClipboardData (CF_TEXT);
412 CString toInsert((const char*)GlobalLock(hData));
413 GlobalUnlock(hData);
414 CloseClipboard();
416 // elimate control chars, especially newlines
417 toInsert.Replace(_T('\t'), _T(' '));
419 // only insert first line
420 toInsert.Replace(_T('\r'), _T('\n'));
421 int pos = 0;
422 toInsert = toInsert.Tokenize(_T("\n"), pos);
423 toInsert.Trim();
425 // get the current text
426 CString text;
427 GetWindowText(text);
429 // construct the new text
430 int from, to;
431 GetSel(from, to);
432 text.Delete(from, to - from);
433 text.Insert(from, toInsert);
434 from += toInsert.GetLength();
436 // update & notify controls
437 SetWindowText(text);
438 SetSel(from, from, FALSE);
439 SetModify(TRUE);
441 GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), EN_CHANGE), (LPARAM)GetSafeHwnd());
443 return 0;