1 /*
2 ** @(#) $Id$
3 **
4 ** W3C Web Commander can be found at "http://www.w3.org/WinCom/"
5 **
6 ** Copyright � 1995-1998 World Wide Web Consortium, (Massachusetts
7 ** Institute of Technology, Institut National de Recherche en
8 ** Informatique et en Automatique, Keio University). All Rights
9 ** Reserved. This program is distributed under the W3C's Software
10 ** Intellectual Property License. This program is distributed in the hope
11 ** that it will be useful, but WITHOUT ANY WARRANTY; without even the
12 ** implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 ** PURPOSE. See W3C License http://www.w3.org/Consortium/Legal/ for more
14 ** details.
15 **
16 ** ListVwEx.cpp : implementation of the CListViewEx class
17 */
18
19 #include "stdafx.h"
20 #include "ListVwEx.h"
21 #include "Links.h"
22
23 #ifdef _DEBUG
24 #define new DEBUG_NEW
25 #undef THIS_FILE
26 static char THIS_FILE[] = __FILE__;
27 #endif
28
29 /////////////////////////////////////////////////////////////////////////////
30 // CListViewEx
31
IMPLEMENT_DYNCREATE(CListViewEx,CListView)32 IMPLEMENT_DYNCREATE(CListViewEx, CListView)
33
34 BEGIN_MESSAGE_MAP(CListViewEx, CListView)
35 //{{AFX_MSG_MAP(CListViewEx)
36 ON_WM_SIZE()
37 ON_WM_PAINT()
38 ON_WM_SETFOCUS()
39 ON_WM_KILLFOCUS()
40 //}}AFX_MSG_MAP
41 ON_MESSAGE(LVM_SETIMAGELIST, OnSetImageList)
42 ON_MESSAGE(LVM_SETTEXTCOLOR, OnSetTextColor)
43 ON_MESSAGE(LVM_SETTEXTBKCOLOR, OnSetTextBkColor)
44 ON_MESSAGE(LVM_SETBKCOLOR, OnSetBkColor)
45 END_MESSAGE_MAP()
46
47 /////////////////////////////////////////////////////////////////////////////
48 // CListViewEx construction/destruction
49
50 CListViewEx::CListViewEx()
51 {
52 m_bFullRowSel = TRUE;
53 m_bClientWidthSel = TRUE;
54
55 m_cxClient = 0;
56 m_cxStateImageOffset = 0;
57
58 m_clrText = ::GetSysColor(COLOR_WINDOWTEXT);
59 m_clrTextBk = ::GetSysColor(COLOR_WINDOW);
60 m_clrBkgnd = ::GetSysColor(COLOR_WINDOW);
61 }
62
~CListViewEx()63 CListViewEx::~CListViewEx()
64 {
65 }
66
PreCreateWindow(CREATESTRUCT & cs)67 BOOL CListViewEx::PreCreateWindow(CREATESTRUCT& cs)
68 {
69 // default is report view and full row selection
70 cs.style &= ~LVS_TYPEMASK;
71 cs.style |= LVS_REPORT | LVS_OWNERDRAWFIXED;
72 m_bFullRowSel = TRUE;
73
74 return(CListView::PreCreateWindow(cs));
75 }
76
SetFullRowSel(BOOL bFullRowSel)77 BOOL CListViewEx::SetFullRowSel(BOOL bFullRowSel)
78 {
79 // no painting during change
80 LockWindowUpdate();
81
82 m_bFullRowSel = bFullRowSel;
83
84 BOOL bRet;
85
86 if (m_bFullRowSel)
87 bRet = ModifyStyle(0L, LVS_OWNERDRAWFIXED);
88 else
89 bRet = ModifyStyle(LVS_OWNERDRAWFIXED, 0L);
90
91 // repaint window if we are not changing view type
92 if (bRet && (GetStyle() & LVS_TYPEMASK) == LVS_REPORT)
93 Invalidate();
94
95 // repaint changes
96 UnlockWindowUpdate();
97
98 return(bRet);
99 }
100
GetFullRowSel()101 BOOL CListViewEx::GetFullRowSel()
102 {
103 return(m_bFullRowSel);
104 }
105
106 /////////////////////////////////////////////////////////////////////////////
107 // CListViewEx drawing
108
109 // offsets for first and other columns
110 #define OFFSET_FIRST 2
111 #define OFFSET_OTHER 6
112
DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)113 void CListViewEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
114 {
115 CListCtrl& ListCtrl=GetListCtrl();
116 CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
117 CRect rcItem(lpDrawItemStruct->rcItem);
118 UINT uiFlags = ILD_TRANSPARENT;
119 CImageList* pImageList;
120 int nItem = lpDrawItemStruct->itemID;
121 BOOL bFocus = (GetFocus() == this);
122 COLORREF clrTextSave, clrBkSave;
123 COLORREF clrImage = m_clrBkgnd;
124 static _TCHAR szBuff[MAX_PATH];
125 LPCTSTR pszText;
126
127 // get item data
128
129 LV_ITEM lvi;
130 lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
131 lvi.iItem = nItem;
132 lvi.iSubItem = 0;
133 lvi.pszText = szBuff;
134 lvi.cchTextMax = sizeof(szBuff);
135 lvi.stateMask = 0xFFFF; // get all state flags
136 ListCtrl.GetItem(&lvi);
137
138 BOOL bSelected = (bFocus || (GetStyle() & LVS_SHOWSELALWAYS)) && lvi.state & LVIS_SELECTED;
139 bSelected = bSelected || (lvi.state & LVIS_DROPHILITED);
140
141 // set colors if item is selected
142
143 CRect rcAllLabels;
144 ListCtrl.GetItemRect(nItem, rcAllLabels, LVIR_BOUNDS);
145
146 CRect rcLabel;
147 ListCtrl.GetItemRect(nItem, rcLabel, LVIR_LABEL);
148
149 rcAllLabels.left = rcLabel.left;
150 if (m_bClientWidthSel && rcAllLabels.right<m_cxClient)
151 rcAllLabels.right = m_cxClient;
152
153 if (bSelected)
154 {
155 clrTextSave = pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
156 clrBkSave = pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
157
158 pDC->FillRect(rcAllLabels, &CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
159 }
160 else
161 pDC->FillRect(rcAllLabels, &CBrush(m_clrTextBk));
162
163 // set color and mask for the icon
164
165 if (lvi.state & LVIS_CUT)
166 {
167 clrImage = m_clrBkgnd;
168 uiFlags |= ILD_BLEND50;
169 }
170 else if (bSelected)
171 {
172 clrImage = ::GetSysColor(COLOR_HIGHLIGHT);
173 uiFlags |= ILD_BLEND50;
174 }
175
176 // draw state icon
177
178 UINT nStateImageMask = lvi.state & LVIS_STATEIMAGEMASK;
179 if (nStateImageMask)
180 {
181 int nImage = (nStateImageMask>>12) - 1;
182 pImageList = ListCtrl.GetImageList(LVSIL_STATE);
183 if (pImageList)
184 {
185 pImageList->Draw(pDC, nImage,
186 CPoint(rcItem.left, rcItem.top), ILD_TRANSPARENT);
187 }
188 }
189
190 // draw normal and overlay icon
191
192 CRect rcIcon;
193 ListCtrl.GetItemRect(nItem, rcIcon, LVIR_ICON);
194
195 pImageList = ListCtrl.GetImageList(LVSIL_SMALL);
196 if (pImageList)
197 {
198 UINT nOvlImageMask=lvi.state & LVIS_OVERLAYMASK;
199 if (rcItem.left<rcItem.right-1)
200 {
201 ImageList_DrawEx(pImageList->m_hImageList, lvi.iImage,
202 pDC->m_hDC,rcIcon.left,rcIcon.top, 16, 16,
203 m_clrBkgnd, clrImage, uiFlags | nOvlImageMask);
204 }
205 }
206
207 // draw item label
208
209 ListCtrl.GetItemRect(nItem, rcItem, LVIR_LABEL);
210 rcItem.right -= m_cxStateImageOffset;
211
212 pszText = MakeShortString(pDC, szBuff,
213 rcItem.right-rcItem.left, 2*OFFSET_FIRST);
214
215 rcLabel = rcItem;
216 rcLabel.left += OFFSET_FIRST;
217 rcLabel.right -= OFFSET_FIRST;
218
219 pDC->DrawText(pszText,-1,rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
220
221 // draw labels for extra columns
222
223 LV_COLUMN lvc;
224 lvc.mask = LVCF_FMT | LVCF_WIDTH;
225
226 for(int nColumn = 1; ListCtrl.GetColumn(nColumn, &lvc); nColumn++)
227 {
228 rcItem.left = rcItem.right;
229 rcItem.right += lvc.cx;
230
231 int nRetLen = ListCtrl.GetItemText(nItem, nColumn,
232 szBuff, sizeof(szBuff));
233 if (nRetLen == 0)
234 continue;
235
236 pszText = MakeShortString(pDC, szBuff,
237 rcItem.right - rcItem.left, 2*OFFSET_OTHER);
238
239 UINT nJustify = DT_LEFT;
240
241 if(pszText == szBuff)
242 {
243 switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
244 {
245 case LVCFMT_RIGHT:
246 nJustify = DT_RIGHT;
247 break;
248 case LVCFMT_CENTER:
249 nJustify = DT_CENTER;
250 break;
251 default:
252 break;
253 }
254 }
255
256 rcLabel = rcItem;
257 rcLabel.left += OFFSET_OTHER;
258 rcLabel.right -= OFFSET_OTHER;
259
260 pDC->DrawText(pszText, -1, rcLabel,
261 nJustify | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
262 }
263
264 // draw focus rectangle if item has focus
265
266 if (lvi.state & LVIS_FOCUSED && bFocus)
267 pDC->DrawFocusRect(rcAllLabels);
268
269 // set original colors if item was selected
270
271 if (bSelected)
272 {
273 pDC->SetTextColor(clrTextSave);
274 pDC->SetBkColor(clrBkSave);
275 }
276 }
277
MakeShortString(CDC * pDC,LPCTSTR lpszLong,int nColumnLen,int nOffset)278 LPCTSTR CListViewEx::MakeShortString(CDC* pDC, LPCTSTR lpszLong, int nColumnLen, int nOffset)
279 {
280 static const _TCHAR szThreeDots[] = _T("...");
281
282 int nStringLen = lstrlen(lpszLong);
283
284 if(nStringLen == 0 ||
285 (pDC->GetTextExtent(lpszLong, nStringLen).cx + nOffset) <= nColumnLen)
286 {
287 return(lpszLong);
288 }
289
290 static _TCHAR szShort[MAX_PATH];
291
292 lstrcpy(szShort,lpszLong);
293 int nAddLen = pDC->GetTextExtent(szThreeDots,sizeof(szThreeDots)).cx;
294
295 for(int i = nStringLen-1; i > 0; i--)
296 {
297 szShort[i] = 0;
298 if((pDC->GetTextExtent(szShort, i).cx + nOffset + nAddLen)
299 <= nColumnLen)
300 {
301 break;
302 }
303 }
304
305 lstrcat(szShort, szThreeDots);
306 return(szShort);
307 }
308
RepaintSelectedItems()309 void CListViewEx::RepaintSelectedItems()
310 {
311 CListCtrl& ListCtrl = GetListCtrl();
312 CRect rcItem, rcLabel;
313
314 // invalidate focused item so it can repaint properly
315
316 int nItem = ListCtrl.GetNextItem(-1, LVNI_FOCUSED);
317
318 if(nItem != -1)
319 {
320 ListCtrl.GetItemRect(nItem, rcItem, LVIR_BOUNDS);
321 ListCtrl.GetItemRect(nItem, rcLabel, LVIR_LABEL);
322 rcItem.left = rcLabel.left;
323
324 InvalidateRect(rcItem, FALSE);
325 }
326
327 // if selected items should not be preserved, invalidate them
328
329 if(!(GetStyle() & LVS_SHOWSELALWAYS))
330 {
331 for(nItem = ListCtrl.GetNextItem(-1, LVNI_SELECTED);
332 nItem != -1; nItem = ListCtrl.GetNextItem(nItem, LVNI_SELECTED))
333 {
334 ListCtrl.GetItemRect(nItem, rcItem, LVIR_BOUNDS);
335 ListCtrl.GetItemRect(nItem, rcLabel, LVIR_LABEL);
336 rcItem.left = rcLabel.left;
337
338 InvalidateRect(rcItem, FALSE);
339 }
340 }
341
342 // update changes
343
344 UpdateWindow();
345 }
346
347 /////////////////////////////////////////////////////////////////////////////
348 // CListViewEx diagnostics
349
350 #ifdef _DEBUG
351
Dump(CDumpContext & dc) const352 void CListViewEx::Dump(CDumpContext& dc) const
353 {
354 CListView::Dump(dc);
355
356 dc << "m_bFullRowSel = " << (UINT)m_bFullRowSel;
357 dc << "\n";
358 dc << "m_cxStateImageOffset = " << m_cxStateImageOffset;
359 dc << "\n";
360 }
361
362 #endif //_DEBUG
363
364 /////////////////////////////////////////////////////////////////////////////
365 // CListViewEx message handlers
366
OnSetImageList(WPARAM wParam,LPARAM lParam)367 LRESULT CListViewEx::OnSetImageList(WPARAM wParam, LPARAM lParam)
368 {
369 if( (int) wParam == LVSIL_STATE)
370 {
371 int cx, cy;
372
373 if(::ImageList_GetIconSize((HIMAGELIST)lParam, &cx, &cy))
374 m_cxStateImageOffset = cx;
375 else
376 m_cxStateImageOffset = 0;
377 }
378
379 return(Default());
380 }
381
OnSetTextColor(WPARAM wParam,LPARAM lParam)382 LRESULT CListViewEx::OnSetTextColor(WPARAM wParam, LPARAM lParam)
383 {
384 m_clrText = (COLORREF)lParam;
385 return(Default());
386 }
387
OnSetTextBkColor(WPARAM wParam,LPARAM lParam)388 LRESULT CListViewEx::OnSetTextBkColor(WPARAM wParam, LPARAM lParam)
389 {
390 m_clrTextBk = (COLORREF)lParam;
391 return(Default());
392 }
393
OnSetBkColor(WPARAM wParam,LPARAM lParam)394 LRESULT CListViewEx::OnSetBkColor(WPARAM wParam, LPARAM lParam)
395 {
396 m_clrBkgnd = (COLORREF)lParam;
397 return(Default());
398 }
399
OnSize(UINT nType,int cx,int cy)400 void CListViewEx::OnSize(UINT nType, int cx, int cy)
401 {
402 m_cxClient = cx;
403 CListView::OnSize(nType, cx, cy);
404 }
405
OnPaint()406 void CListViewEx::OnPaint()
407 {
408 // in full row select mode, we need to extend the clipping region
409 // so we can paint a selection all the way to the right
410 if (m_bClientWidthSel &&
411 (GetStyle() & LVS_TYPEMASK) == LVS_REPORT &&
412 GetFullRowSel())
413 {
414 CRect rcAllLabels;
415 GetListCtrl().GetItemRect(0, rcAllLabels, LVIR_BOUNDS);
416
417 if(rcAllLabels.right < m_cxClient)
418 {
419 // need to call BeginPaint (in CPaintDC c-tor)
420 // to get correct clipping rect
421 CPaintDC dc(this);
422
423 CRect rcClip;
424 dc.GetClipBox(rcClip);
425
426 rcClip.left = min(rcAllLabels.right-1, rcClip.left);
427 rcClip.right = m_cxClient;
428
429 InvalidateRect(rcClip, FALSE);
430 // EndPaint will be called in CPaintDC d-tor
431 }
432 }
433
434 CListView::OnPaint();
435 }
436
OnSetFocus(CWnd * pOldWnd)437 void CListViewEx::OnSetFocus(CWnd* pOldWnd)
438 {
439 CListView::OnSetFocus(pOldWnd);
440
441 // check if we are getting focus from label edit box
442 if(pOldWnd!=NULL && pOldWnd->GetParent()==this)
443 return;
444
445 // repaint items that should change appearance
446 if(m_bFullRowSel && (GetStyle() & LVS_TYPEMASK)==LVS_REPORT)
447 RepaintSelectedItems();
448 }
449
OnKillFocus(CWnd * pNewWnd)450 void CListViewEx::OnKillFocus(CWnd* pNewWnd)
451 {
452 CListView::OnKillFocus(pNewWnd);
453
454 // check if we are losing focus to label edit box
455 if(pNewWnd != NULL && pNewWnd->GetParent() == this)
456 return;
457
458 // repaint items that should change appearance
459 if(m_bFullRowSel && (GetStyle() & LVS_TYPEMASK) == LVS_REPORT)
460 RepaintSelectedItems();
461 }
462