1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012, 2014, 2016-2018 - TortoiseGit
4 // Copyright (C) 2007, 2012-2014, 2018 - 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.
21 #include "FilterEdit.h"
24 const UINT
CFilterEdit::WM_FILTEREDIT_INFOCLICKED
= ::RegisterWindowMessage(L
"TGITWM_FILTEREDIT_INFOCLICKED");
25 const UINT
CFilterEdit::WM_FILTEREDIT_CANCELCLICKED
= ::RegisterWindowMessage(L
"TGITWM_FILTEREDIT_CANCELCLICKED");
27 IMPLEMENT_DYNAMIC(CFilterEdit
, CEdit
)
29 CFilterEdit::CFilterEdit()
30 : m_hIconCancelNormal(nullptr)
31 , m_hIconCancelPressed(nullptr)
32 , m_hIconInfo(nullptr)
34 , m_bShowCancelButtonAlways(FALSE
)
35 , m_iButtonClickedMessageId(WM_FILTEREDIT_INFOCLICKED
)
36 , m_iCancelClickedMessageId(WM_FILTEREDIT_CANCELCLICKED
)
37 , m_pValidator(nullptr)
38 , m_backColor(GetSysColor(COLOR_WINDOW
))
40 m_rcEditArea
.SetRect(0, 0, 0, 0);
41 m_rcButtonArea
.SetRect(0, 0, 0, 0);
42 m_rcInfoArea
.SetRect(0, 0, 0, 0);
43 m_sizeInfoIcon
.SetSize(0, 0);
44 m_sizeCancelIcon
.SetSize(0, 0);
47 CFilterEdit::~CFilterEdit()
49 if (m_hIconCancelNormal
)
50 DestroyIcon(m_hIconCancelNormal
);
51 if (m_hIconCancelPressed
)
52 DestroyIcon(m_hIconCancelPressed
);
54 DestroyIcon(m_hIconInfo
);
57 BEGIN_MESSAGE_MAP(CFilterEdit
, CEdit
)
59 ON_MESSAGE(WM_SETFONT
, OnSetFont
)
67 ON_CONTROL_REFLECT_EX(EN_CHANGE
, &CFilterEdit::OnEnChange
)
68 ON_WM_CTLCOLOR_REFLECT()
70 ON_CONTROL_REFLECT(EN_KILLFOCUS
, &CFilterEdit::OnEnKillfocus
)
71 ON_CONTROL_REFLECT(EN_SETFOCUS
, &CFilterEdit::OnEnSetfocus
)
72 ON_MESSAGE(WM_PASTE
, &CFilterEdit::OnPaste
)
73 ON_WM_SYSCOLORCHANGE()
78 // CFilterEdit message handlers
80 void CFilterEdit::PreSubclassWindow( )
82 // We must have a multi line edit
83 // to be able to set the edit rect
84 ASSERT( GetStyle() & ES_MULTILINE
);
89 BOOL
CFilterEdit::PreTranslateMessage( MSG
* pMsg
)
91 return CEdit::PreTranslateMessage(pMsg
);
94 BOOL
CFilterEdit::SetCancelBitmaps(UINT uCancelNormal
, UINT uCancelPressed
, int cx96dpi
, int cy96dpi
, BOOL bShowAlways
)
96 m_bShowCancelButtonAlways
= bShowAlways
;
98 if (m_hIconCancelNormal
)
99 DestroyIcon(m_hIconCancelNormal
);
100 if (m_hIconCancelPressed
)
101 DestroyIcon(m_hIconCancelPressed
);
103 m_hIconCancelNormal
= LoadDpiScaledIcon(uCancelNormal
, cx96dpi
, cy96dpi
);
104 m_hIconCancelPressed
= LoadDpiScaledIcon(uCancelPressed
, cx96dpi
, cy96dpi
);
106 if (!m_hIconCancelNormal
|| !m_hIconCancelPressed
)
109 m_sizeCancelIcon
= GetIconSize(m_hIconCancelNormal
);
115 BOOL
CFilterEdit::SetInfoIcon(UINT uInfo
, int cx96dpi
, int cy96dpi
)
118 DestroyIcon(m_hIconInfo
);
120 m_hIconInfo
= LoadDpiScaledIcon(uInfo
, cx96dpi
, cy96dpi
);
125 m_sizeInfoIcon
= GetIconSize(m_hIconInfo
);
131 BOOL
CFilterEdit::SetCueBanner(LPCWSTR lpcwText
)
135 m_sCueBanner
= lpcwText
;
136 InvalidateRect(nullptr, TRUE
);
139 m_sCueBanner
.Empty();
140 InvalidateRect(nullptr, TRUE
);
144 void CFilterEdit::ResizeWindow()
146 if (!::IsWindow(m_hWnd
))
152 editrc
.left
= rc
.left
+ 4;
153 editrc
.top
= rc
.top
+ 1;
154 editrc
.right
= rc
.right
- 4;
155 editrc
.bottom
= rc
.bottom
- 4;
158 HGDIOBJ oldFont
= dc
.SelectObject(GetFont()->GetSafeHandle());
159 TEXTMETRIC tm
= { 0 };
160 dc
.GetTextMetrics(&tm
);
161 dc
.SelectObject(oldFont
);
163 m_rcEditArea
.left
= editrc
.left
+ m_sizeInfoIcon
.cx
;
164 m_rcEditArea
.right
= editrc
.right
- m_sizeCancelIcon
.cx
- 5;
165 m_rcEditArea
.top
= (rc
.Height() - tm
.tmHeight
) / 2;
166 m_rcEditArea
.bottom
= m_rcEditArea
.top
+ tm
.tmHeight
;
168 m_rcButtonArea
.left
= m_rcEditArea
.right
+ 5;
169 m_rcButtonArea
.right
= rc
.right
;
170 m_rcButtonArea
.top
= (((rc
.bottom
)-m_sizeCancelIcon
.cy
)/2);
171 m_rcButtonArea
.bottom
= m_rcButtonArea
.top
+ m_sizeCancelIcon
.cy
;
173 m_rcInfoArea
.left
= 0;
174 m_rcInfoArea
.right
= m_rcEditArea
.left
;
175 m_rcInfoArea
.top
= (((rc
.bottom
)-m_sizeInfoIcon
.cy
)/2);
176 m_rcInfoArea
.bottom
= m_rcInfoArea
.top
+ m_sizeInfoIcon
.cy
;
178 SetRect(&m_rcEditArea
);
181 void CFilterEdit::SetButtonClickedMessageId(UINT iButtonClickedMessageId
, UINT iCancelClickedMessageId
)
183 m_iButtonClickedMessageId
= iButtonClickedMessageId
;
184 m_iCancelClickedMessageId
= iCancelClickedMessageId
;
187 CSize
CFilterEdit::GetIconSize(HICON hIcon
)
191 if (GetIconInfo(hIcon
, &iconinfo
))
194 if (GetObject(iconinfo
.hbmColor
, sizeof(BITMAP
), &bmp
))
196 size
.cx
= bmp
.bmWidth
;
197 size
.cy
= bmp
.bmHeight
;
203 BOOL
CFilterEdit::OnEraseBkgnd(CDC
* pDC
)
207 pDC
->FillSolidRect(&rc
, m_backColor
);
209 if (GetWindowTextLength() || m_bShowCancelButtonAlways
)
213 DrawIconEx(pDC
->GetSafeHdc(), m_rcButtonArea
.left
, m_rcButtonArea
.top
, m_hIconCancelNormal
,
214 m_sizeCancelIcon
.cx
, m_sizeCancelIcon
.cy
, 0, nullptr, DI_NORMAL
);
218 DrawIconEx(pDC
->GetSafeHdc(), m_rcButtonArea
.left
, m_rcButtonArea
.top
, m_hIconCancelPressed
,
219 m_sizeCancelIcon
.cx
, m_sizeCancelIcon
.cy
, 0, nullptr, DI_NORMAL
);
224 DrawIconEx(pDC
->GetSafeHdc(), m_rcInfoArea
.left
, m_rcInfoArea
.top
, m_hIconInfo
,
225 m_sizeInfoIcon
.cx
, m_sizeInfoIcon
.cy
, 0, nullptr, DI_NORMAL
);
231 void CFilterEdit::OnLButtonUp(UINT nFlags
, CPoint point
)
234 InvalidateRect(nullptr);
235 if (m_rcButtonArea
.PtInRect(point
))
238 CWnd
*pOwner
= GetOwner();
241 pOwner
->SendMessage(m_iCancelClickedMessageId
, (WPARAM
)GetSafeHwnd(), 0);
245 if (m_rcInfoArea
.PtInRect(point
))
247 CWnd
*pOwner
= GetOwner();
250 RECT rc
= m_rcInfoArea
;
252 pOwner
->SendMessage(m_iButtonClickedMessageId
, (WPARAM
)GetSafeHwnd(), (LPARAM
)(LPRECT
)&rc
);
256 CEdit::OnLButtonUp(nFlags
, point
);
259 void CFilterEdit::OnLButtonDown(UINT nFlags
, CPoint point
)
261 m_bPressed
= m_rcButtonArea
.PtInRect(point
);
262 //InvalidateRect(nullptr);
263 CEdit::OnLButtonDown(nFlags
, point
);
266 int CFilterEdit::OnCreate(LPCREATESTRUCT lpCreateStruct
)
268 if (CEdit::OnCreate(lpCreateStruct
) == -1)
276 LRESULT
CFilterEdit::OnSetFont( WPARAM wParam
, LPARAM lParam
)
278 DefWindowProc( WM_SETFONT
, wParam
, lParam
);
285 void CFilterEdit::OnSize( UINT nType
, int cx
, int cy
)
287 CEdit::OnSize( nType
, cx
, cy
);
291 BOOL
CFilterEdit::OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
)
294 GetCursorPos(&pntCursor
);
295 ScreenToClient(&pntCursor
);
296 // if the cursor is not in the edit area, show the normal arrow cursor
297 if (!m_rcEditArea
.PtInRect(pntCursor
))
299 SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW
));
303 return CEdit::OnSetCursor(pWnd
, nHitTest
, message
);
306 BOOL
CFilterEdit::OnEnChange()
308 // check whether the entered text is valid
310 InvalidateRect(nullptr);
314 HBRUSH
CFilterEdit::CtlColor(CDC
* pDC
, UINT
/*nCtlColor*/)
316 if (m_backColor
!= GetSysColor(COLOR_WINDOW
))
318 pDC
->SetBkColor(m_backColor
);
324 void CFilterEdit::ValidateAndRedraw()
329 void CFilterEdit::Validate()
335 m_backColor
= GetSysColor(COLOR_WINDOW
);
336 if (!m_pValidator
->Validate(text
))
338 // Use a background color slightly shifted to red.
339 // We do this by increasing red component and decreasing green and blue.
340 const int SHIFT_PRECENTAGE
= 10;
341 int r
= GetRValue(m_backColor
);
342 int g
= GetGValue(m_backColor
);
343 int b
= GetBValue(m_backColor
);
345 r
= min(r
* (100 + SHIFT_PRECENTAGE
) / 100, 255);
346 // Ensure that there is at least some redness.
347 r
= max(r
, 255 * SHIFT_PRECENTAGE
/ 100);
348 g
= g
* (100 - SHIFT_PRECENTAGE
) / 100;
349 b
= b
* (100 - SHIFT_PRECENTAGE
) / 100;
350 m_backColor
= RGB(r
, g
, b
);
351 m_brBack
.DeleteObject();
352 m_brBack
.CreateSolidBrush(m_backColor
);
357 void CFilterEdit::OnPaint()
359 LRESULT defres
= Default();
364 // the Default() call did not process the WM_PAINT message!
365 // Validate the update region ourselves to avoid
366 // an endless loop repainting
368 GetUpdateRect(&rc
, FALSE
);
369 if (!rc
.IsRectEmpty())
376 void CFilterEdit::DrawDimText()
378 if (m_sCueBanner
.IsEmpty())
380 if (GetWindowTextLength())
382 if (GetFocus() == this)
385 CClientDC
dcDraw(this);
386 int iState
= dcDraw
.SaveDC();
388 dcDraw
.SelectObject((*GetFont()));
389 dcDraw
.SetTextColor(GetSysColor(COLOR_GRAYTEXT
));
390 dcDraw
.SetBkColor(GetSysColor(COLOR_WINDOW
));
391 dcDraw
.DrawText(m_sCueBanner
, m_sCueBanner
.GetLength(), &m_rcEditArea
, DT_CENTER
| DT_VCENTER
);
392 dcDraw
.RestoreDC(iState
);
396 HICON
CFilterEdit::LoadDpiScaledIcon(UINT resourceId
, int cx96dpi
, int cy96dpi
)
398 int cx
= CDPIAware::Instance().PointsToPixelsX(cx96dpi
);
399 int cy
= CDPIAware::Instance().PointsToPixelsY(cy96dpi
);
401 return (HICON
)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(resourceId
), IMAGE_ICON
, cx
, cy
, LR_DEFAULTCOLOR
);
404 void CFilterEdit::OnEnKillfocus()
406 InvalidateRect(nullptr);
409 void CFilterEdit::OnEnSetfocus()
411 InvalidateRect(nullptr);
414 LRESULT
CFilterEdit::OnPaste(WPARAM
, LPARAM
)
418 HANDLE hData
= GetClipboardData (CF_TEXT
);
419 CString
toInsert((const char*)GlobalLock(hData
));
423 // elimate control chars, especially newlines
424 toInsert
.Replace(L
'\t', L
' ');
426 // only insert first line
427 toInsert
.Replace(L
'\r', L
'\n');
429 toInsert
= toInsert
.Tokenize(L
"\n", pos
);
432 // get the current text
436 // construct the new text
439 text
.Delete(from
, to
- from
);
440 text
.Insert(from
, toInsert
);
441 from
+= toInsert
.GetLength();
443 // update & notify controls
445 SetSel(from
, from
, FALSE
);
448 GetParent()->SendMessage(WM_COMMAND
, MAKEWPARAM(GetDlgCtrlID(), EN_CHANGE
), (LPARAM
)GetSafeHwnd());
453 void CFilterEdit::OnSysColorChange()
455 __super::OnSysColorChange();
456 m_backColor
= GetSysColor(COLOR_WINDOW
);
460 ULONG
CFilterEdit::GetGestureStatus(CPoint
/*ptTouch*/)