1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (c) 2003 by Andreas Kapust <info@akinstaller.de>; <http://www.codeproject.com/Articles/2607/AutoComplete-without-IAutoComplete>
4 // Copyright (C) 2009, 2012-2013, 2015-2016 - TortoiseGit
6 // Licensed under: The Code Project Open License (CPOL); <http://www.codeproject.com/info/cpol10.aspx>
8 // ACWnd.cpp: Implementierungsdatei
12 #include "ACListWnd.h"
13 #include "StringUtils.h"
18 static char THIS_FILE
[] = __FILE__
;
21 static UINT auIDStatusBar
[] =
26 #define _MAX_ENTRYS_ 8
27 #define _MODE_FIND_ALL_ (1L << 5)
29 /////////////////////////////////////////////////////////////////////////////
32 void DoPaintMessageLoop()
35 while (::PeekMessage(&message1
, nullptr, WM_PAINT
, WM_PAINT
, PM_REMOVE
))
37 ::TranslateMessage(&message1
);
38 ::DispatchMessage(&message1
);
42 /**********************************************************************/
44 CACListWnd::CACListWnd()
51 m_pEditParent
= nullptr;
52 m_LastSize
.SetRectEmpty();
57 SecureZeroMemory(&logfont
, sizeof(LOGFONT
));
60 /**********************************************************************/
62 CACListWnd::~CACListWnd()
64 m_SearchList
.RemoveAll();
65 m_DisplayList
.RemoveAll();
69 /*********************************************************************/
71 void CACListWnd::OnActivateApp(BOOL bActive
, DWORD dwThreadID
)
73 #if (_MSC_VER >= 1300)
74 CWnd::OnActivateApp(bActive
, dwThreadID
); //vc7 FIX 1.2
76 CWnd::OnActivateApp(bActive
, (HTASK
)dwThreadID
); //vc6 FIX 1.2
83 BEGIN_MESSAGE_MAP(CACListWnd
, CWnd
)
84 //{{AFX_MSG_MAP(CACListWnd)
101 ON_WM_GETMINMAXINFO()
106 /////////////////////////////////////////////////////////////////////////////
107 // Behandlungsroutinen für Nachrichten CACListWnd
109 void CACListWnd::DrawItem(CDC
* pDC
,long m_lItem
,long width
)
111 long y
= m_lItem
- m_lTopIndex
;
112 CRect
rcLabel(2,y
*m_ItemHeight
,width
,(y
+1)*m_ItemHeight
);
114 pDC
->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT
));
116 if(m_lItem
== m_lSelItem
)
119 pDC
->FillSolidRect(rcLabel
,::GetSysColor(COLOR_HIGHLIGHT
));
120 pDC
->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT
));
125 m_DisplayStr
= m_PrefixChar
+ m_DisplayList
.GetAt(m_lItem
);
127 m_DisplayStr
= m_DisplayList
.GetAt(m_lItem
);
129 pDC
->DrawText(m_DisplayStr
, -1, rcLabel
, DT_LEFT
| DT_SINGLELINE
|
130 DT_NOPREFIX
| DT_VCENTER
| DT_END_ELLIPSIS
);
133 /*********************************************************************/
135 void CACListWnd::OnPaint()
138 CRect rcWnd
,m_rect
, rc
;
139 CDC MemDC
, *pDC
= nullptr;
140 CBitmap m_bitmap
, *m_pOldBitmap
;
146 rc
.left
= rc
.right
-GetSystemMetrics(SM_CXHSCROLL
);
147 rc
.top
= rc
.bottom
-GetSystemMetrics(SM_CYVSCROLL
);
149 m_rect
.right
-= ScrollBarWidth();
151 MemDC
.CreateCompatibleDC(&dc
);
153 m_bitmap
.CreateCompatibleBitmap(&dc
, m_rect
.Width(), m_rect
.Height());
154 m_pOldBitmap
= MemDC
.SelectObject(&m_bitmap
);
156 MemDC
.SetWindowOrg(m_rect
.left
, m_rect
.top
);
158 long width
= rcWnd
.Width() - ScrollBarWidth();
160 MemDC
.FillSolidRect(rcWnd
,::GetSysColor(COLOR_WINDOW
));
161 MemDC
.SelectObject(GetStockObject(DEFAULT_GUI_FONT
));
162 MemDC
.SetBkMode(TRANSPARENT
);
164 for(i
= m_lTopIndex
; i
< m_lCount
;i
++)
166 DrawItem(&MemDC
,i
,width
);
170 CPen
m_Pen1(PS_SOLID
, 1, ::GetSysColor(COLOR_WINDOW
));
171 CPen
m_Pen2(PS_SOLID
, 1, ::GetSysColor(COLOR_BTNFACE
));
172 CPen
m_Pen3(PS_SOLID
, 1, ::GetSysColor(COLOR_3DSHADOW
));
176 if(m_VertBar
.IsWindowVisible())
177 dc
.FillSolidRect(rc
, ::GetSysColor(COLOR_BTNFACE
) );
181 CPen
*pOldPen
= (CPen
*)pDC
->SelectObject(&m_Pen1
);
184 width
= GetSystemMetrics(SM_CXHSCROLL
);
185 bottom
= (rcWnd
.bottom
-GetSystemMetrics(SM_CXHSCROLL
))-1;
188 for( i
= 0; i
< 20 ;i
++,a
++)
191 pDC
->SelectObject(&m_Pen1
);
193 pDC
->SelectObject(&m_Pen2
);
195 pDC
->SelectObject(&m_Pen3
);
199 pDC
->MoveTo(rc
.left
+ i
- 1, rcWnd
.bottom
);
200 pDC
->LineTo(rc
.left
+ i
+ width
, bottom
);
203 dc
.BitBlt(m_rect
.left
, m_rect
.top
, m_rect
.Width(), m_rect
.Height(),
204 &MemDC
, m_rect
.left
, m_rect
.top
, SRCCOPY
);
206 pDC
->SelectObject( pOldPen
);
207 MemDC
.SelectObject(m_pOldBitmap
);
210 /*********************************************************************/
212 void CACListWnd::Init(CWnd
*pWnd
)
214 VERIFY(m_VertBar
.Create(WS_VISIBLE
|SBS_VERT
|SBS_LEFTALIGN
,
215 CRect(0,0,GetSystemMetrics(SM_CYVSCROLL
),100),this,0));
218 m_pEditParent
= (CEdit
*)pWnd
;
220 m_lCount
= (long)m_DisplayList
.GetSize();
221 m_VertBar
.SetScrollPos(0,false);
228 m_pDC
->SelectObject(GetStockObject(DEFAULT_GUI_FONT
));
229 CSize m_Size
= m_pDC
->GetOutputTextExtent(L
"Hg");
230 m_ItemHeight
= m_Size
.cy
;
235 /*********************************************************************/
237 void CACListWnd::SetScroller()
240 GetClientRect(rcWnd
);
242 if(m_VertBar
.GetSafeHwnd())
246 rcBar
.left
= (rcWnd
.Width()-GetSystemMetrics(SM_CYVSCROLL
));
247 rcBar
.bottom
-= GetSystemMetrics(SM_CYHSCROLL
);
248 m_VertBar
.MoveWindow(rcBar
);
249 rcBar
.top
= rcWnd
.bottom
-20;
250 rcBar
.bottom
= rcWnd
.bottom
;
252 m_VertBar
.SetScrollPos(m_lTopIndex
,true);
256 /*********************************************************************/
258 void CACListWnd::OnSize(UINT nType
, int cx
, int cy
)
260 CWnd::OnSize(nType
, cx
, cy
);
264 if(!m_LastSize
.IsRectEmpty())
265 GetWindowRect(m_LastSize
);
268 /*********************************************************************/
270 long CACListWnd::ScrollBarWidth()
272 if(m_VertBar
.IsWindowVisible())
273 return GetSystemMetrics(SM_CYVSCROLL
);
278 /*********************************************************************/
280 void CACListWnd::SetProp()
287 CWnd::GetWindowRect(rcWnd
);
288 ScreenToClient(rcWnd
);
291 si
.cbSize
= sizeof(SCROLLINFO
);
292 si
.fMask
= SIF_PAGE
|SIF_RANGE
;
294 si
.nMax
= m_lCount
-1;
295 m_VisibleItems
= si
.nPage
= rcWnd
.Height()/m_ItemHeight
;
297 m_VertBar
.SetScrollRange(0,m_lCount
-1);
298 m_VertBar
.SetScrollInfo(&si
);
300 if(m_VisibleItems
> m_lCount
-1)
301 m_VertBar
.ShowWindow(false);
303 m_VertBar
.ShowWindow(true);
305 if(m_lTopIndex
+m_VisibleItems
> m_lCount
)
307 m_lTopIndex
= m_lCount
-m_VisibleItems
;
310 m_VertBar
.SetScrollPos(m_lTopIndex
,true);
314 /*********************************************************************/
316 BOOL
CACListWnd::OnEraseBkgnd(CDC
* /*pDC*/)
321 /*********************************************************************/
323 void CACListWnd::OnNcPaint()
326 CRect rectClient
, rectWindow
,rcWnd
;
328 GetClientRect(rectClient
);
329 GetWindowRect(rectWindow
);
330 ScreenToClient(rectWindow
);
332 rectClient
.OffsetRect(-(rectWindow
.left
), -(rectWindow
.top
));
333 dc
.ExcludeClipRect(rectClient
);
335 rectWindow
.OffsetRect(-rectWindow
.left
, -rectWindow
.top
);
337 dc
.FillSolidRect(rectWindow
,::GetSysColor(COLOR_WINDOWTEXT
));
340 /*********************************************************************/
342 void CACListWnd::OnKeyDown(UINT nChar
, UINT nRepCnt
, UINT nFlags
)
344 CWnd::OnKeyDown(nChar
, nRepCnt
, nFlags
);
346 if (nChar
== VK_ESCAPE
)
350 /*********************************************************************/
352 void CACListWnd::OnNcCalcSize(BOOL
/*bCalcValidRects*/, NCCALCSIZE_PARAMS FAR
* lpncsp
)
354 ::InflateRect(lpncsp
->rgrc
,
355 -GetSystemMetrics(SM_CXBORDER
), -GetSystemMetrics(SM_CYBORDER
));
358 /*********************************************************************/
360 int CACListWnd::HitTest(CPoint point
)
365 GetClientRect(rcWnd
);
366 long width
= rcWnd
.Width() - ScrollBarWidth();
368 for(int i
= m_lTopIndex
; i
< m_lCount
; i
++)
370 long y
= i
- m_lTopIndex
;
371 rcItem
.SetRect(2,y
*m_ItemHeight
,width
,(y
+1)*m_ItemHeight
);
373 if(PtInRect(&rcItem
, point
))
374 return (m_lSelItem
= (y
+m_lTopIndex
));
380 /*********************************************************************/
382 LRESULT
CACListWnd::OnNcHitTest(CPoint point
)
385 GetWindowRect(rectClient
);
387 rectClient
.left
= rectClient
.right
- GetSystemMetrics(SM_CYVSCROLL
);
388 rectClient
.top
= rectClient
.bottom
- GetSystemMetrics(SM_CXVSCROLL
);
390 if(rectClient
.PtInRect(point
))
391 return HTBOTTOMRIGHT
;
396 /*********************************************************************/
398 void CACListWnd::OnLButtonDown(UINT nFlags
, CPoint point
)
400 CWnd::OnLButtonDown(nFlags
, point
);
401 int sel
= HitTest(point
);
405 if(!EnsureVisible(sel
,true))
408 m_pEditParent
->SendMessage(ENAC_UPDATE
, WM_KEYDOWN
, GetDlgCtrlID());
409 DoPaintMessageLoop();
417 if(!rc
.PtInRect(point
))
422 /*********************************************************************/
424 void CACListWnd::OnRButtonDown(UINT nFlags
, CPoint point
)
426 CWnd::OnRButtonDown(nFlags
, point
);
430 /*********************************************************************/
432 BOOL
CACListWnd::OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
)
437 GetWindowRect(rectClient
);
438 ScreenToClient(&rectClient
);
440 rectClient
.left
= rectClient
.right
- GetSystemMetrics(SM_CYVSCROLL
);
441 rectClient
.top
= rectClient
.bottom
- GetSystemMetrics(SM_CXVSCROLL
);
444 GetCursorPos(&ptCursor
);
445 ScreenToClient(&ptCursor
);
447 if(rectClient
.PtInRect(ptCursor
)) // Vergrößerungs-Cursor
449 return CWnd::OnSetCursor(pWnd
, nHitTest
, message
);
452 ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW
));
456 /*********************************************************************/
458 void CACListWnd::InvalidateAndScroll()
460 m_VertBar
.SetScrollPos(m_lTopIndex
,true);
462 DoPaintMessageLoop();
465 /*********************************************************************/
467 bool CACListWnd::EnsureVisible(int item
, bool m_bWait
)
469 if(item
> m_lTopIndex
&& item
< m_lTopIndex
+ m_VisibleItems
)
470 return false; // ist visible
472 if(item
> m_lTopIndex
) // scroll down
475 for(int i
= m_lTopIndex
; i
< m_len
; i
++)
477 if(i
>= m_lCount
-m_VisibleItems
)
479 if(i
>= m_lCount
-m_VisibleItems
|| i
+ m_VisibleItems
> item
)
488 InvalidateAndScroll();
490 DoPaintMessageLoop();
493 InvalidateAndScroll();
497 if(item
< m_lTopIndex
) // scroll up
499 while(item
< m_lTopIndex
)
510 InvalidateAndScroll();
512 DoPaintMessageLoop();
516 InvalidateAndScroll();
523 /*********************************************************************/
525 bool CACListWnd::SelectItem(int item
)
532 EnsureVisible(m_lSelItem
,false);
539 if(!EnsureVisible(item
,true))
545 /*********************************************************************/
547 int CACListWnd::FindStringExact( int nStartAfter
, LPCTSTR lpszString
)
549 if(nStartAfter
> m_SearchList
.GetSize())
552 for(int i
= nStartAfter
+1; i
< m_SearchList
.GetSize(); i
++)
553 if(m_SearchList
.GetAt(i
).Compare(lpszString
) == 0)
558 /*********************************************************************/
561 * NEW: m_bDisplayOnly
563 int CACListWnd::FindString(int nStartAfter
, LPCTSTR lpszString
, bool m_bDisplayOnly
)
565 long m_AktCount
= (long)m_DisplayList
.GetSize();
569 CString m_Str1
,m_Str2
= lpszString
;
576 if(nStartAfter
> m_SearchList
.GetSize())
588 m_DisplayList
.RemoveAll();
592 for(int i
= nStartAfter
+1; i
< m_SearchList
.GetSize(); i
++)
595 m_Str1
= m_PrefixChar
;
599 m_Str1
+= m_SearchList
.GetAt(i
);
603 if(m_lMode
& _MODE_FIND_ALL_
)
605 if(m_Str1
.Find(m_Str2
) >= 0)
607 m_DisplayList
.Add(m_SearchList
.GetAt(i
));
610 else // _MODE_FIND_EXACT_
612 if (CStringUtils::StartsWith(m_Str1
, m_Str2
))
614 m_DisplayList
.Add(m_SearchList
.GetAt(i
));
619 m_lCount
= (long)m_DisplayList
.GetSize();
626 m_pEditParent
->GetWindowRect(rcWnd
);
634 iHeight
= m_lCount
*m_ItemHeight
+(GetSystemMetrics(SM_CYBORDER
)*2);
636 if(m_lCount
> _MAX_ENTRYS_
)
637 iHeight
= _MAX_ENTRYS_
*m_ItemHeight
+(GetSystemMetrics(SM_CYBORDER
)*2);
639 if(!m_LastSize
.IsRectEmpty())
641 iWight
= m_LastSize
.Width();
642 iHeight
= m_LastSize
.Height();
643 rcWnd
.top
+= rcWnd
.Height();
644 rcWnd
.right
= rcWnd
.left
+iWight
;
645 rcWnd
.bottom
= rcWnd
.top
+iHeight
;
647 SetWindowPos(&CWnd::wndTopMost
, rcWnd
.left
,
654 SetWindowPos(&CWnd::wndTopMost
, rcWnd
.left
,
655 rcWnd
.top
+ rcWnd
.Height(),
660 if(m_AktCount
!= m_DisplayList
.GetSize())
663 SortList(m_DisplayList
);
673 /*********************************************************************/
675 int CACListWnd::SelectString(LPCTSTR lpszString
)
677 int item
= FindString(-1, lpszString
);
682 /*********************************************************************/
684 bool CACListWnd::GetText(int item
, CString
& m_Text
)
686 if(item
< 0 || item
> m_SearchList
.GetSize())
688 m_Text
= m_SearchList
.GetAt(item
);
692 /*********************************************************************/
694 void CACListWnd::OnShowWindow(BOOL bShow
, UINT nStatus
)
698 m_nIDTimer
= (long)SetTimer(IDTimerInstall
, 200, nullptr);
699 m_pEditParent
->GetParent()->GetWindowRect(m_ParentRect
);
704 KillTimer(IDTimerInstall
);
710 CWnd::OnShowWindow(bShow
, nStatus
);
711 ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW
));
714 /*********************************************************************/
716 void CACListWnd::OnNcLButtonDown(UINT nHitTest
, CPoint point
)
718 if(OnNcHitTest(point
) == HTBOTTOMRIGHT
)
719 GetWindowRect(m_LastSize
);
720 CWnd::OnNcLButtonDown(nHitTest
, point
);
723 /*********************************************************************/
725 CString
CACListWnd::GetString()
727 int i
= (int)m_DisplayList
.GetSize();
731 if(i
<= m_lSelItem
|| m_lSelItem
== -1)
736 return m_DisplayList
.GetAt(i
);
739 /*********************************************************************/
741 void CACListWnd::OnVScroll(UINT nSBCode
, UINT nPos
, CScrollBar
* pScrollBar
)
743 CWnd::OnVScroll(nSBCode
, nPos
, pScrollBar
);
744 long m_oldlTopIndex
= m_lTopIndex
;
752 m_lTopIndex
-= m_VisibleItems
;
758 m_lTopIndex
+= m_VisibleItems
;
759 if(m_lTopIndex
>= m_lCount
-m_VisibleItems
)
760 m_lTopIndex
= m_lCount
-m_VisibleItems
;
771 if(m_lTopIndex
>= m_lCount
-m_VisibleItems
)
772 m_lTopIndex
= m_lCount
-m_VisibleItems
;
780 m_VertBar
.SetScrollPos(m_lTopIndex
,true);
782 if(m_oldlTopIndex
!= m_lTopIndex
)
786 /*********************************************************************/
788 CString
CACListWnd::GetNextString(int nChar
)
801 m_lSelItem
-= m_VisibleItems
;
807 m_lSelItem
+= m_VisibleItems
;
808 if(m_lSelItem
>= m_lCount
-1)
809 m_lSelItem
= m_lCount
-1;
817 m_lSelItem
= m_lCount
-1;
822 m_lSelItem
= m_lCount
-1;
824 if(m_lSelItem
>= m_lCount
)
827 if(EnsureVisible(m_lSelItem
,(m_lCount
> 50) ? false : true))
828 InvalidateAndScroll();
833 /*********************************************************************/
835 void CACListWnd::OnMouseMove(UINT nFlags
, CPoint point
)
837 CWnd::OnMouseMove(nFlags
, point
);
838 int sel
= HitTest(point
);
845 /*********************************************************************/
847 void CACListWnd::OnTimer(UINT_PTR nIDEvent
)
849 CWnd::OnTimer(nIDEvent
);
852 m_pEditParent
->GetParent()->GetWindowRect(m_ParentRect1
);
853 if(!m_ParentRect1
.EqualRect(m_ParentRect
))
857 /*********************************************************************/
859 void CACListWnd::OnGetMinMaxInfo(MINMAXINFO FAR
* lpMMI
)
864 long m_lMinY1
= GetSystemMetrics(SM_CYHSCROLL
)*2 + GetSystemMetrics(SM_CYSIZEFRAME
) + GetSystemMetrics(SM_CXHTHUMB
),
865 m_lMinY2
= m_lCount
* m_ItemHeight
+ (GetSystemMetrics(SM_CYBORDER
)*2);
867 if(m_VisibleItems
> m_lCount
-1 && m_lMinY2
< m_lMinY1
)
868 lpMMI
->ptMinTrackSize
.y
= m_lMinY2
;
870 lpMMI
->ptMinTrackSize
.y
= m_lMinY1
;
873 lpMMI
->ptMinTrackSize
.x
= GetSystemMetrics(SM_CXHSCROLL
)*4;
880 m_pEditParent
->GetWindowRect (&rc
);
881 lpMMI
->ptMinTrackSize
.x
= rc
.right
- rc
.left
;
885 CWnd::OnGetMinMaxInfo(lpMMI
);
888 /*********************************************************************/
890 int CACListWnd::CompareString(const void* p1
, const void* p2
)
892 return _stricmp( * ( char** ) p1
, * ( char** ) p2
);
895 /*********************************************************************/
897 void CACListWnd::SortList(CStringArray
& list
)
899 int m_Count
= (int)list
.GetSize();
904 CStringArray m_Liste1
;
907 LPCTSTR
* ppSortArray
= new LPCTSTR
[m_Count
+1];
910 for(i
=0; i
< m_Count
; i
++)
912 ppSortArray
[i
] = (LPCTSTR
)m_Liste1
.GetAt(i
);
917 qsort(ppSortArray
, m_Count
, sizeof(LPCTSTR
), CompareString
);
919 for(i
=0; i
< m_Count
; i
++)
921 list
.Add((LPCTSTR
) ppSortArray
[i
]);
923 m_Liste1
.RemoveAll();
924 delete [] ppSortArray
;
928 /*********************************************************************/
933 void CACListWnd::CopyList()
935 m_DisplayList
.Copy(m_SearchList
);
936 m_lCount
= (long)m_DisplayList
.GetSize();
938 FindString(0, L
"", true);
941 /*********************************************************************/