soui 5.0.0.1
Soui5 Doc
 
Loading...
Searching...
No Matches
SListCtrl.cpp
1#include "souistd.h"
2
3#include "control/SListCtrl.h"
4
5#pragma warning(disable : 4267 4018)
6
7#define ITEM_MARGIN 4
8SNSBEGIN
9//////////////////////////////////////////////////////////////////////////
10// SListCtrl
12 : m_nHeaderHeight(20)
13 , m_nItemHeight(20)
14 , m_pHeader(NULL)
15 , m_nSelectItem(-1)
16 , m_crItemBg(RGBA(255, 255, 255, 255))
17 , m_crItemBg2(RGBA(226, 226, 226, 255))
18 , m_crItemSelBg(RGBA(57, 145, 209, 255))
19 , m_crItemHotBg(RGBA(57, 145, 209, 128))
20 , m_crText(RGBA(0, 0, 0, 255))
21 , m_crSelText(RGBA(255, 255, 0, 255))
22 , m_pItemSkin(NULL)
23 , m_pIconSkin(NULL)
24 , m_pCheckSkin(GETBUILTINSKIN(SKIN_SYS_CHECKBOX))
25 , m_ptIcon(-1, -1)
26 , m_ptText(-1, -1)
27 , m_bHotTrack(FALSE)
28 , m_bCheckBox(FALSE)
29 , m_bMultiSelection(FALSE)
30{
31 m_bClipClient = TRUE;
32 m_bFocusable = TRUE;
33 m_evtSet.addEvent(EVENTID(EventLCSelChanging));
34 m_evtSet.addEvent(EVENTID(EventLCSelChanged));
35 m_evtSet.addEvent(EVENTID(EventLCDbClick));
36 m_evtSet.addEvent(EVENTID(EventLCItemDeleted));
37}
38
42
43int SListCtrl::InsertColumn(int nIndex, LPCTSTR pszText, int nWidth, UINT fmt, LPARAM lParam)
44{
45 SASSERT(m_pHeader);
46
47 int nRet = m_pHeader->InsertItem(nIndex, pszText, nWidth, fmt, lParam);
48 for (int i = 0; i < GetItemCount(); i++)
49 {
50 m_arrItems[i].arSubItems->SetCount(GetColumnCount());
51 }
53 return nRet;
54}
55
57{
58 SXmlNode xmlHeader = xmlNode.child(L"headerStyle");
59 m_pHeader = sobj_cast<SHeaderCtrl>(CreateChildByName(xmlHeader.attribute(L"wndclass").as_string(SHeaderCtrl::GetClassName())));
60 if (!m_pHeader)
61 return FALSE;
63 m_pHeader->InitFromXml(&xmlHeader);
64 xmlHeader.set_userdata(1);
65
66 if (!__baseCls::CreateChildren(xmlNode))
67 return FALSE;
68
69 m_pHeader->GetEventSet()->subscribeEvent(EventHeaderItemChanging::EventID, Subscriber(&SListCtrl::OnHeaderSizeChanging, this));
70 m_pHeader->GetEventSet()->subscribeEvent(EventHeaderItemSwap::EventID, Subscriber(&SListCtrl::OnHeaderSwap, this));
71
72 return TRUE;
73}
74
75int SListCtrl::InsertItem(int nItem, LPCTSTR pszText, int nImage)
76{
77 if (GetColumnCount() == 0)
78 return -1;
79 if (nItem < 0 || nItem > GetItemCount())
80 nItem = GetItemCount();
81
82 DXLVITEM lvi;
83 lvi.dwData = 0;
84 lvi.arSubItems = new ArrSubItem();
85 lvi.arSubItems->SetCount(GetColumnCount());
86
87 DXLVSUBITEM &subItem = lvi.arSubItems->GetAt(0);
88 subItem.strText = _tcsdup(pszText);
89 subItem.cchTextMax = _tcslen(pszText);
90 subItem.nImage = nImage;
91
92 m_arrItems.InsertAt(nItem, lvi);
93
95
96 return nItem;
97}
98
99BOOL SListCtrl::SetItemData(int nItem, LPARAM dwData)
100{
101 if (nItem >= GetItemCount() || nItem < 0)
102 return FALSE;
103
104 m_arrItems[nItem].dwData = dwData;
105
106 return TRUE;
107}
108
109LPARAM SListCtrl::GetItemData(int nItem)
110{
111 if (nItem >= GetItemCount() || nItem < 0)
112 return 0;
113
114 DXLVITEM &lvi = m_arrItems[nItem];
115
116 return lvi.dwData;
117}
118
119BOOL SListCtrl::SetSubItem(int nItem, int nSubItem, const DXLVSUBITEM *plv)
120{
121 if (nItem >= GetItemCount() || nSubItem >= GetColumnCount() || nItem < 0)
122 return FALSE;
123 DXLVSUBITEM &lvsi_dst = m_arrItems[nItem].arSubItems->GetAt(nSubItem);
124 if (plv->mask & S_LVIF_TEXT)
125 {
126 if (lvsi_dst.strText)
127 free(lvsi_dst.strText);
128 lvsi_dst.strText = _tcsdup(plv->strText);
129 lvsi_dst.cchTextMax = _tcslen(plv->strText);
130 }
131 if (plv->mask & S_LVIF_IMAGE)
132 lvsi_dst.nImage = plv->nImage;
133 if (plv->mask & S_LVIF_INDENT)
134 lvsi_dst.nIndent = plv->nIndent;
135 RedrawItem(nItem);
136 return TRUE;
137}
138
139BOOL SListCtrl::GetSubItem(int nItem, int nSubItem, DXLVSUBITEM *plv) const
140{
141 if (nItem >= GetItemCount() || nSubItem >= GetColumnCount() || nItem < 0)
142 return FALSE;
143
144 const DXLVSUBITEM &lvsi_src = m_arrItems[nItem].arSubItems->GetAt(nSubItem);
145 if (plv->mask & S_LVIF_TEXT)
146 {
147 _tcscpy_s(plv->strText, plv->cchTextMax, lvsi_src.strText);
148 }
149 if (plv->mask & S_LVIF_IMAGE)
150 plv->nImage = lvsi_src.nImage;
151 if (plv->mask & S_LVIF_INDENT)
152 plv->nIndent = lvsi_src.nIndent;
153 return TRUE;
154}
155
156BOOL SListCtrl::SetSubItemText(int nItem, int nSubItem, LPCTSTR pszText)
157{
158 if (nItem < 0 || nItem >= GetItemCount())
159 return FALSE;
160
161 if (nSubItem < 0 || nSubItem >= GetColumnCount())
162 return FALSE;
163
164 DXLVSUBITEM &lvi = m_arrItems[nItem].arSubItems->GetAt(nSubItem);
165 if (lvi.strText)
166 {
167 free(lvi.strText);
168 }
169 lvi.strText = _tcsdup(pszText);
170 lvi.cchTextMax = _tcslen(pszText);
171
172 CRect rcItem = GetItemRect(nItem, nSubItem);
173 InvalidateRect(rcItem);
174 return TRUE;
175}
176
177SStringT SListCtrl::GetSubItemText(int nItem, int nSubItem) const
178{
179 if (nItem >= GetItemCount() || nSubItem >= GetColumnCount() || nItem < 0)
180 return _T("");
181
182 const DXLVSUBITEM &lvsi_src = m_arrItems[nItem].arSubItems->GetAt(nSubItem);
183 return lvsi_src.strText;
184}
185
187{
188 return m_nSelectItem;
189}
190
192{
193 if (nItem != m_nSelectItem)
194 {
196 }
197}
198
200{
201 if (GetColumnCount() <= 0)
202 return 0;
203
204 return m_arrItems.GetCount();
205}
206
207BOOL SListCtrl::SetItemCount(int nItems, int nGrowBy)
208{
209 int nOldCount = GetItemCount();
210 if (nItems < nOldCount)
211 return FALSE;
212
213 BOOL bRet = m_arrItems.SetCount(nItems, nGrowBy);
214 if (bRet)
215 {
216 for (int i = nOldCount; i < nItems; i++)
217 {
218 DXLVITEM &lvi = m_arrItems[i];
219 lvi.arSubItems = new ArrSubItem;
220 lvi.arSubItems->SetCount(GetColumnCount());
221 }
222 }
224
225 return bRet;
226}
227
229{
230 CRect rcList;
231
232 GetClientRect(&rcList);
233 rcList.top += m_nHeaderHeight;
234
235 return rcList;
236}
237
238//////////////////////////////////////////////////////////////////////////
239// 更新滚动条
241{
242 CSize szView;
243 szView.cx = m_pHeader->GetTotalWidth(false);
244 int nMinWid = m_pHeader->GetTotalWidth(true);
245 szView.cy = GetItemCount() * m_nItemHeight;
246
247 CRect rcClient;
248 SWindow::GetClientRect(&rcClient); //不计算滚动条大小
249 rcClient.top += m_nHeaderHeight;
250 if (rcClient.bottom < rcClient.top)
251 rcClient.bottom = rcClient.top;
252 CSize size = rcClient.Size();
253 // 关闭滚动条
254 m_wBarVisible = SSB_NULL;
255
256 if (size.cy < szView.cy || (size.cy < szView.cy + GetSbWidth() && size.cx < szView.cx))
257 {
258 // 需要纵向滚动条
259 m_wBarVisible |= SSB_VERT;
260 m_siVer.nMin = 0;
261 m_siVer.nMax = szView.cy - 1;
262 m_siVer.nPage = rcClient.Height();
263
264 int horzSize = size.cx - GetSbWidth();
265 if (horzSize < nMinWid)
266 {
267 // 小于表头的最小宽度, 需要横向滚动条
268 m_wBarVisible |= SSB_HORZ;
269 m_siVer.nPage = size.cy - GetSbWidth() > 0 ? size.cy - GetSbWidth() : 0; //注意同时调整纵向滚动条page信息
270
271 m_siHoz.nMin = 0;
272 m_siHoz.nMax = szView.cx - 1;
273 m_siHoz.nPage = (size.cx - GetSbWidth()) > 0 ? (size.cx - GetSbWidth()) : 0;
274 }
275 else
276 {
277 if (horzSize < szView.cx || m_pHeader->IsAutoResize())
278 { //大于最小宽度,小于现在宽度,则调整表头的宽度。
279 CRect rcHead = m_pHeader->GetWindowRect();
280 rcHead.right = rcHead.left + horzSize;
281 m_pHeader->Move(rcHead);
282 szView.cx = horzSize;
283 }
284 // 不需要横向滚动条
285 m_siHoz.nPage = szView.cx;
286 m_siHoz.nMin = 0;
287 m_siHoz.nMax = m_siHoz.nPage - 1;
288 m_siHoz.nPos = 0;
289 }
290 }
291 else
292 {
293 // 不需要纵向滚动条
294 m_siVer.nPage = size.cy;
295 m_siVer.nMin = 0;
296 m_siVer.nMax = size.cy - 1;
297 m_siVer.nPos = 0;
298
299 if (size.cx < nMinWid)
300 {
301 //小于表头的最小宽度, 需要横向滚动条
302 m_wBarVisible |= SSB_HORZ;
303 m_siHoz.nMin = 0;
304 m_siHoz.nMax = szView.cx - 1;
305 m_siHoz.nPage = size.cx;
306 }
307 else
308 {
309 if (size.cx < szView.cx || m_pHeader->IsAutoResize())
310 { //大于最小宽度,小于现在宽度,则调整表头的宽度。
311 CRect rcHead = m_pHeader->GetWindowRect();
312 rcHead.right = rcHead.left + size.cx;
313 m_pHeader->Move(rcHead);
314 szView.cx = size.cx;
315 }
316 // 不需要横向滚动条
317 m_siHoz.nPage = szView.cx;
318 m_siHoz.nMin = 0;
319 m_siHoz.nMax = m_siHoz.nPage - 1;
320 m_siHoz.nPos = 0;
321 }
322 }
323
324 // 根据需要调整原点位置
325 if (HasScrollBar(FALSE) && m_siHoz.nPos + m_siHoz.nPage > szView.cx)
326 {
327 m_siHoz.nPos = szView.cx - m_siHoz.nPage;
328 }
329
330 if (HasScrollBar(TRUE) && m_siVer.nPos + m_siVer.nPage > szView.cy)
331 {
332 m_siVer.nPos = szView.cy - m_siVer.nPage;
333 }
334
335 SetScrollPos(TRUE, m_siVer.nPos, TRUE);
336 SetScrollPos(FALSE, m_siHoz.nPos, TRUE);
337
338 // 重新计算客户区及非客户区
339 SSendMessage(WM_NCCALCSIZE);
340
341 Invalidate();
342}
343
344//更新表头位置
346{
347 CRect rcClient;
348 GetClientRect(&rcClient);
349 CRect rcHeader(rcClient);
350 rcHeader.bottom = rcHeader.top + m_nHeaderHeight;
351 rcHeader.left -= m_ptOrigin.x;
352 if (m_pHeader)
353 m_pHeader->Move(rcHeader);
354}
355
357{
358 if (nItem >= 0 && nItem < GetItemCount())
359 {
360 DXLVITEM &lvi = m_arrItems[nItem];
361
362 EventLCItemDeleted evt2(this);
363 evt2.nItem = nItem;
364 evt2.dwData = lvi.dwData;
365 FireEvent(evt2);
366
367 for (int i = 0; i < GetColumnCount(); i++)
368 {
369 DXLVSUBITEM &lvsi = lvi.arSubItems->GetAt(i);
370 if (lvsi.strText)
371 free(lvsi.strText);
372 }
373 delete lvi.arSubItems;
374 m_arrItems.RemoveAt(nItem);
375
377 }
378}
379
381{
382 if (m_pHeader->DeleteItem(iCol))
383 {
384 int nColumnCount = m_pHeader->GetItemCount();
385
386 for (int i = 0; i < GetItemCount(); i++)
387 {
388 DXLVITEM &lvi = m_arrItems[i];
389
390 if (0 == nColumnCount)
391 {
392 EventLCItemDeleted evt2(this);
393 evt2.nItem = i;
394 evt2.dwData = lvi.dwData;
395 FireEvent(evt2);
396 }
397
398 DXLVSUBITEM &lvsi = lvi.arSubItems->GetAt(iCol);
399 if (lvsi.strText)
400 free(lvsi.strText);
401 m_arrItems[i].arSubItems->RemoveAt(iCol);
402 }
404 }
405}
406
408{
409 m_nSelectItem = -1;
410 for (int i = 0; i < GetItemCount(); i++)
411 {
412 DXLVITEM &lvi = m_arrItems[i];
413
414 EventLCItemDeleted evt2(this);
415 evt2.nItem = i;
416 evt2.dwData = lvi.dwData;
417 FireEvent(evt2);
418
419 for (int j = 0; j < GetColumnCount(); j++)
420 {
421 DXLVSUBITEM &lvsi = lvi.arSubItems->GetAt(j);
422 if (lvsi.strText)
423 free(lvsi.strText);
424 }
425 delete lvi.arSubItems;
426 }
427 m_arrItems.RemoveAll();
428
430}
431
432CRect SListCtrl::GetItemRect(int nItem, int nSubItem)
433{
434 if (!(nItem >= 0 && nItem < GetItemCount() && nSubItem >= 0 && nSubItem < GetColumnCount()))
435 return CRect();
436
437 CRect rcItem;
438 rcItem.top = m_nItemHeight * nItem;
439 rcItem.bottom = rcItem.top + m_nItemHeight;
440 rcItem.left = 0;
441 rcItem.right = 0;
442
443 for (int nCol = 0; nCol < GetColumnCount(); nCol++)
444 {
445 SHDITEM hdi = { SHDI_WIDTH | SHDI_ORDER, 0 };
446
447 m_pHeader->GetItem(nCol, &hdi);
448 rcItem.left = rcItem.right;
449 rcItem.right = rcItem.left + hdi.cx;
450 if (hdi.iOrder == nSubItem)
451 break;
452 }
453
454 CRect rcList = GetListRect();
455 // 变换到窗口坐标
456 rcItem.OffsetRect(rcList.TopLeft());
457 // 根据原点坐标修正
458 rcItem.OffsetRect(-m_ptOrigin);
459
460 return rcItem;
461}
462
463//////////////////////////////////////////////////////////////////////////
464// 自动修改pt的位置为相对当前项的偏移量
465int SListCtrl::HitTest(const CPoint &pt)
466{
467 CRect rcList = GetListRect();
468
469 CPoint pt2 = pt;
470 pt2.y -= rcList.top - m_ptOrigin.y;
471
472 int nRet = pt2.y / m_nItemHeight;
473 if (nRet >= GetItemCount())
474 {
475 nRet = -1;
476 }
477
478 return nRet;
479}
480
482{
483 if (!IsVisible(TRUE))
484 return;
485
486 CRect rcList = GetListRect();
487
488 int nTopItem = GetTopIndex();
489 int nPageItems = (rcList.Height() + m_nItemHeight - 1) / m_nItemHeight;
490
491 if (nItem >= nTopItem && nItem < GetItemCount() && nItem <= nTopItem + nPageItems)
492 {
493 CRect rcItem(0, 0, rcList.Width(), m_nItemHeight);
494 rcItem.OffsetRect(0, m_nItemHeight * nItem - m_ptOrigin.y);
495 rcItem.OffsetRect(rcList.TopLeft());
496 CRect rcDC;
497 rcDC.IntersectRect(rcItem, rcList);
499 SSendMessage(WM_ERASEBKGND, (WPARAM)pRT);
500
501 DrawItem(pRT, rcItem, nItem);
502
504 }
505}
506
508{
509 CRect rcClient = GetListRect();
510
511 // calculate number of items per control height (include partial item)
512 div_t divHeight = div(rcClient.Height(), m_nItemHeight);
513
514 // round up to nearest item count
515 return smax((int)(bPartial && divHeight.rem > 0 ? divHeight.quot + 1 : divHeight.quot), 1);
516}
517BOOL SListCtrl::SortItems(PFNLVCOMPAREEX pfnCompare, void *pContext)
518{
519 qsort_s(m_arrItems.GetData(), m_arrItems.GetCount(), sizeof(DXLVITEM), pfnCompare, pContext);
520 m_nSelectItem = -1;
521 m_nHoverItem = -1;
523 return TRUE;
524}
525
527{
528 SPainter painter;
529 BeforePaint(pRT, painter);
530 CRect rcList = GetListRect();
531 int nTopItem = GetTopIndex();
532 pRT->PushClipRect(&rcList, RGN_AND);
533 CRect rcItem(rcList);
534
535 rcItem.bottom = rcItem.top;
536 rcItem.OffsetRect(0, -(m_ptOrigin.y % m_nItemHeight));
537 for (int nItem = nTopItem; nItem <= (nTopItem + GetCountPerPage(TRUE)) && nItem < GetItemCount(); rcItem.top = rcItem.bottom, nItem++)
538 {
539 rcItem.bottom = rcItem.top + m_nItemHeight;
540
541 DrawItem(pRT, rcItem, nItem);
542 }
543 pRT->PopClip();
544 AfterPaint(pRT, painter);
545}
546
547BOOL SListCtrl::HitCheckBox(const CPoint &pt)
548{
549 if (!m_bCheckBox)
550 return FALSE;
551
552 CRect rect = GetListRect();
553 rect.left += ITEM_MARGIN;
554 rect.OffsetRect(-m_ptOrigin.x, 0);
555
556 CSize sizeSkin = m_pCheckSkin->GetSkinSize();
557 int nOffsetX = 3;
558 CRect rcCheck;
559 rcCheck.SetRect(0, 0, sizeSkin.cx, sizeSkin.cy);
560 rcCheck.OffsetRect(rect.left + nOffsetX, 0);
561
562 if (pt.x >= rcCheck.left && pt.x <= rcCheck.right)
563 return TRUE;
564 return FALSE;
565}
566
567void SListCtrl::DrawItem(IRenderTarget *pRT, CRect rcItem, int nItem)
568{
569 BOOL bTextColorChanged = FALSE;
570 int nBgImg = 0;
571 COLORREF crOldText = RGBA(0xFF, 0xFF, 0xFF, 0xFF);
572 COLORREF crItemBg = m_crItemBg;
573 COLORREF crText = m_crText;
574 DXLVITEM lvItem = m_arrItems[nItem];
575 CRect rcIcon, rcText;
576
577 if (nItem % 2)
578 {
579 // if (m_pItemSkin != NULL)
580 // nBgImg = 1;
581 // else if (CR_INVALID != m_crItemBg2)
582 // crItemBg = m_crItemBg2;
583 //上面的代码不要了,因为skin间隔效果没必要,只留下颜色间隔就好了
584 if (CR_INVALID != m_crItemBg2)
585 crItemBg = m_crItemBg2;
586 }
587
588 if (lvItem.checked)
589 { //和下面那个if的条件分开,才会有sel和hot的区别
590 if (m_pItemSkin != NULL)
591 nBgImg = 2;
592 else if (CR_INVALID != m_crItemSelBg)
593 crItemBg = m_crItemSelBg;
594
595 if (CR_INVALID != m_crSelText)
596 crText = m_crSelText;
597 }
598 else if (m_bHotTrack && nItem == m_nHoverItem)
599 {
600 if (m_pItemSkin != NULL)
601 nBgImg = 1;
602 else if (CR_INVALID != m_crItemHotBg)
603 crItemBg = m_crItemHotBg;
604
605 if (CR_INVALID != m_crSelText)
606 crText = m_crSelText;
607 }
608
609 //绘制背景
610 // if (m_pItemSkin != NULL)
611 // m_pItemSkin->Draw(pRT, rc, nBgImg);
612 // else if (CR_INVALID != crItemBg)
613 // pRT->FillSolidRect( rc, crItemBg);
614 //上面的代码在某些时候,【指定skin的时候,会导致背景异常】,所以颠倒一下顺序
615 if (CR_INVALID != crItemBg) //先画背景
616 pRT->FillSolidRect(rcItem, crItemBg);
617
618 if (m_pItemSkin != NULL) //有skin,则覆盖背景
619 m_pItemSkin->DrawByIndex(pRT, rcItem, nBgImg);
620
621 // 左边加上空白
622 rcItem.left += ITEM_MARGIN;
623
624 if (CR_INVALID != crText)
625 {
626 bTextColorChanged = TRUE;
627 crOldText = pRT->SetTextColor(crText);
628 }
629
630 CRect rcCol(rcItem);
631 rcCol.right = rcCol.left;
632 rcCol.OffsetRect(-m_ptOrigin.x, 0);
633
634 for (int nCol = 0; nCol < GetColumnCount(); nCol++)
635 {
636 CRect rcVisiblePart;
637
638 SHDITEM hdi = { SHDI_WIDTH | SHDI_ORDER, 0 };
639 m_pHeader->GetItem(nCol, &hdi);
640 rcCol.left = rcCol.right;
641 rcCol.right = rcCol.left + hdi.cx;
642
643 rcVisiblePart.IntersectRect(rcItem, rcCol);
644
645 if (rcVisiblePart.IsRectEmpty())
646 continue;
647
648 // 绘制 checkbox
649 if (nCol == 0 && m_bCheckBox && m_pCheckSkin)
650 {
651 CSize sizeSkin = m_pCheckSkin->GetSkinSize();
652 int nOffsetX = 3;
653 int nOffsetY = (m_nItemHeight - sizeSkin.cy) / 2;
654 CRect rcCheck;
655 rcCheck.SetRect(0, 0, sizeSkin.cx, sizeSkin.cy);
656 rcCheck.OffsetRect(rcCol.left + nOffsetX, rcCol.top + nOffsetY);
657 m_pCheckSkin->DrawByIndex(pRT, rcCheck, lvItem.checked ? 4 : 0);
658
659 rcCol.left = sizeSkin.cx + 6 + rcCol.left;
660 }
661
662 DXLVSUBITEM &subItem = lvItem.arSubItems->GetAt(hdi.iOrder);
663
664 if (subItem.nImage != -1 && m_pIconSkin)
665 {
666 int nOffsetX = m_ptIcon.x;
667 int nOffsetY = m_ptIcon.y;
668 CSize sizeSkin = m_pIconSkin->GetSkinSize();
669 rcIcon.SetRect(0, 0, sizeSkin.cx, sizeSkin.cy);
670
671 if (m_ptIcon.x == -1)
672 nOffsetX = m_nItemHeight / 6;
673
674 if (m_ptIcon.y == -1)
675 nOffsetY = (m_nItemHeight - sizeSkin.cy) / 2;
676
677 rcIcon.OffsetRect(rcCol.left + nOffsetX, rcCol.top + nOffsetY);
678 m_pIconSkin->DrawByIndex(pRT, rcIcon, subItem.nImage);
679 }
680
681 UINT align = DT_SINGLELINE;
682 rcText = rcCol;
683
684 if (m_ptText.x == -1)
685 rcText.left = rcIcon.Width() > 0 ? rcIcon.right + m_nItemHeight / 6 : rcCol.left;
686 else
687 rcText.left = rcCol.left + m_ptText.x;
688
689 if (m_ptText.y == -1)
690 align |= DT_VCENTER;
691 else
692 rcText.top = rcCol.top + m_ptText.y;
693
694 pRT->DrawText(subItem.strText, subItem.cchTextMax, rcText, align);
695 }
696
697 if (bTextColorChanged)
698 pRT->SetTextColor(crOldText);
699}
700
702{
704
705 __baseCls::OnDestroy();
706}
707
709{
710 if (!m_pHeader)
711 return 0;
712
713 return m_pHeader->GetItemCount();
714}
715
717{
718 return m_ptOrigin.y / m_nItemHeight;
719}
720
721void SListCtrl::NotifySelChange(int nOldSel, int nNewSel, BOOL checkBox)
722{
723 EventLCSelChanging evt1(this);
724 evt1.bCancel = FALSE;
725 evt1.nOldSel = nOldSel;
726 evt1.nNewSel = nNewSel;
727
728 FireEvent(evt1);
729 if (evt1.bCancel)
730 return;
731
732 if (checkBox)
733 {
734 if (nNewSel != -1)
735 {
736 DXLVITEM &newItem = m_arrItems[nNewSel];
737 newItem.checked = newItem.checked ? FALSE : TRUE;
738 m_nSelectItem = nNewSel;
739 RedrawItem(nNewSel);
740 }
741 }
742 else
743 {
744 if ((m_bMultiSelection || m_bCheckBox) && GetKeyState(VK_CONTROL) < 0)
745 {
746 if (nNewSel != -1)
747 {
748 DXLVITEM &newItem = m_arrItems[nNewSel];
749 newItem.checked = newItem.checked ? FALSE : TRUE;
750 m_nSelectItem = nNewSel;
751 RedrawItem(nNewSel);
752 }
753 }
754 else if ((m_bMultiSelection || m_bCheckBox) && GetKeyState(VK_SHIFT) < 0)
755 {
756 if (nNewSel != -1)
757 {
758 if (nOldSel == -1)
759 nOldSel = 0;
760
761 int imax = (nOldSel > nNewSel) ? nOldSel : nNewSel;
762 int imin = (imax == nOldSel) ? nNewSel : nOldSel;
763 for (int i = 0; i < GetItemCount(); i++)
764 {
765 DXLVITEM &lvItem = m_arrItems[i];
766 BOOL last = lvItem.checked;
767 if (i >= imin && i <= imax)
768 {
769 lvItem.checked = TRUE;
770 }
771 else
772 {
773 lvItem.checked = FALSE;
774 }
775 if (last != lvItem.checked)
776 RedrawItem(i);
777 }
778 }
779 }
780 else
781 {
782 m_nSelectItem = -1;
783 for (int i = 0; i < GetItemCount(); i++)
784 {
785 DXLVITEM &lvItem = m_arrItems[i];
786 if (i != nNewSel && lvItem.checked)
787 {
788 BOOL last = lvItem.checked;
789 lvItem.checked = FALSE;
790 if (last != lvItem.checked)
791 RedrawItem(i);
792 }
793 }
794 if (nNewSel != -1)
795 {
796 DXLVITEM &newItem = m_arrItems[nNewSel];
797 newItem.checked = TRUE;
798 m_nSelectItem = nNewSel;
799 RedrawItem(nNewSel);
800 }
801 }
802 }
803
804 EventLCSelChanged evt2(this);
805 evt2.nOldSel = nOldSel;
806 evt2.nNewSel = nNewSel;
807 FireEvent(evt2);
808}
809
810BOOL SListCtrl::OnScroll(BOOL bVertical, UINT uCode, int nPos)
811{
812 BOOL bRet = __baseCls::OnScroll(bVertical, uCode, nPos);
813
814 if (bVertical)
815 {
816 m_ptOrigin.y = m_siVer.nPos;
817 }
818 else
819 {
820 m_ptOrigin.x = m_siHoz.nPos;
821 // 处理列头滚动
823 }
824
825 Invalidate();
826 if (uCode == SB_THUMBTRACK)
827 ScrollUpdate();
828
829 return bRet;
830}
831
832void SListCtrl::OnLButtonDown(UINT nFlags, CPoint pt)
833{
834 __baseCls::OnLButtonDown(nFlags, pt);
835 m_nHoverItem = HitTest(pt);
836 BOOL hitCheckBox = HitCheckBox(pt);
837
838 if (hitCheckBox)
840 else if (m_nHoverItem != m_nSelectItem && !m_bHotTrack)
842 else if (m_nHoverItem != -1 || m_nSelectItem != -1)
844}
845
846void SListCtrl::OnLButtonDbClick(UINT nFlags, CPoint pt)
847{
848 m_nHoverItem = HitTest(pt);
851
852 EventLCDbClick evt2(this);
853 evt2.nCurSel = m_nHoverItem;
854 FireEvent(evt2);
855}
856
857void SListCtrl::OnLButtonUp(UINT nFlags, CPoint pt)
858{
859 __baseCls::OnLButtonUp(nFlags, pt);
860}
861
863{
864 __baseCls::UpdateChildrenPosition();
866}
867
868void SListCtrl::OnSize(UINT nType, CSize size)
869{
870 __baseCls::OnSize(nType, size);
873}
874
875BOOL SListCtrl::OnHeaderClick(IEvtArgs *pEvt)
876{
877 return true;
878}
879
881{
884
885 return true;
886}
887
888BOOL SListCtrl::OnHeaderSwap(IEvtArgs *pEvt)
889{
891
892 return true;
893}
894
895void SListCtrl::OnMouseMove(UINT nFlags, CPoint pt)
896{
897 int nHoverItem = HitTest(pt);
898 if (m_bHotTrack && nHoverItem != m_nHoverItem)
899 {
900 m_nHoverItem = nHoverItem;
901 Invalidate();
902 }
903}
904
906{
907 if (m_bHotTrack)
908 {
909 m_nHoverItem = -1;
910 Invalidate();
911 }
912 __baseCls::OnMouseLeave();
913}
914
916{
917 if (nItem >= GetItemCount())
918 return FALSE;
919
920 const DXLVITEM lvItem = m_arrItems[nItem];
921 return lvItem.checked;
922}
923
924BOOL SListCtrl::SetCheckState(int nItem, BOOL bCheck)
925{
926 if (!m_bCheckBox)
927 return FALSE;
928
929 if (nItem >= GetItemCount())
930 return FALSE;
931
932 DXLVITEM &lvItem = m_arrItems[nItem];
933 lvItem.checked = bCheck;
934
935 return TRUE;
936}
937
939{
940 int ret = 0;
941
942 for (int i = 0; i < GetItemCount(); i++)
943 {
944 const DXLVITEM lvItem = m_arrItems[i];
945 if (lvItem.checked)
946 ret++;
947 }
948
949 return ret;
950}
951
953{
954 int ret = -1;
955 for (int i = 0; i < GetItemCount(); i++)
956 {
957 const DXLVITEM lvItem = m_arrItems[i];
958 if (lvItem.checked)
959 {
960 ret = i;
961 break;
962 }
963 }
964
965 return ret;
966}
967
969{
970 int ret = -1;
971 for (int i = GetItemCount() - 1; i >= 0; i--)
972 {
973 const DXLVITEM lvItem = m_arrItems[i];
974 if (lvItem.checked)
975 {
976 ret = i;
977 break;
978 }
979 }
980
981 return ret;
982}
983
985{
986 return m_pHeader;
987}
988
989SNSEND
@ GRT_PAINTBKGND
Header Control.
Definition SHeaderCtrl.h:18
virtual BOOL CreateChildren(SXmlNode xmlNode)
Create child items from XML configuration.
Definition SListCtrl.cpp:56
void OnLButtonUp(UINT nFlags, CPoint pt)
Handle left mouse button up event.
void SetSelectedItem(int nItem)
Set the selected item.
BOOL SetSubItemText(int nItem, int nSubItem, LPCTSTR pszText)
Set the text of a subitem.
int GetLastCheckedItem()
Get the last checked item.
BOOL SetSubItem(int nItem, int nSubItem, const DXLVSUBITEM *plv)
Set a subitem.
int GetSelectedItem()
Get the selected item.
int m_nSelectItem
Definition SListCtrl.h:461
void OnLButtonDown(UINT nFlags, CPoint pt)
Handle left mouse button down event.
BOOL SetItemCount(int nItems, int nGrowBy)
Set the total number of items.
int GetTopIndex() const
Get the index of the top visible item.
void UpdateChildrenPosition() OVERRIDE
Update the position of child items.
SListCtrl()
Constructor.
Definition SListCtrl.cpp:11
int m_nHoverItem
Definition SListCtrl.h:462
SStringT GetSubItemText(int nItem, int nSubItem) const
Get the text of a subitem.
void NotifySelChange(int nOldSel, int nNewSel, BOOL checkBox=FALSE)
Notify of selection change.
int InsertItem(int nItem, LPCTSTR pszText, int nImage=-1)
Insert an item.
Definition SListCtrl.cpp:75
COLORREF m_crItemHotBg
Definition SListCtrl.h:471
CPoint m_ptIcon
Definition SListCtrl.h:465
BOOL SortItems(PFNLVCOMPAREEX pfnCompare, void *pContext)
Sort items using a comparison function.
ArrLvItem m_arrItems
Definition SListCtrl.h:485
void OnMouseLeave()
Handle mouse leave event.
int GetFirstCheckedItem()
Get the first checked item.
virtual ~SListCtrl()
Destructor.
Definition SListCtrl.cpp:39
virtual BOOL OnScroll(BOOL bVertical, UINT uCode, int nPos)
Handle scroll event.
SAutoRefPtr< ISkinObj > m_pItemSkin
Definition SListCtrl.h:475
CPoint m_ptOrigin
Definition SListCtrl.h:486
int InsertColumn(int nIndex, LPCTSTR pszText, int nWidth, UINT fmt, LPARAM lParam=0)
Insert a column.
Definition SListCtrl.cpp:43
void UpdateHeaderCtrl()
Update the header control.
void OnMouseMove(UINT nFlags, CPoint pt)
Handle mouse move event.
BOOL GetCheckState(int nItem)
Get the check state of an item.
void OnPaint(IRenderTarget *pRT)
Paint the control.
CRect GetItemRect(int nItem, int nSubItem=0)
Get the rectangle of an item.
BOOL OnHeaderSizeChanging(IEvtArgs *pEvt)
Handle header size changing event.
COLORREF m_crItemSelBg
Definition SListCtrl.h:470
BOOL HitCheckBox(const CPoint &pt)
Hit test to determine if the point is on a checkbox.
void DeleteAllItems()
Delete all items.
LPARAM GetItemData(int nItem)
Get the data associated with an item.
void OnSize(UINT nType, CSize size)
Handle size change event.
void RedrawItem(int nItem)
Redraw a specific item.
void OnDestroy()
Handle destroy event.
COLORREF m_crText
Definition SListCtrl.h:472
SHeaderCtrl * GetHeaderCtrl() const
Get the header control.
virtual void DrawItem(IRenderTarget *pRT, CRect rcItem, int nItem)
Draw an item.
BOOL OnHeaderSwap(IEvtArgs *pEvt)
Handle header swap event.
SAutoRefPtr< ISkinObj > m_pCheckSkin
Definition SListCtrl.h:477
CPoint m_ptText
Definition SListCtrl.h:466
int m_nHeaderHeight
Definition SListCtrl.h:458
SAutoRefPtr< ISkinObj > m_pIconSkin
Definition SListCtrl.h:476
COLORREF m_crItemBg
Definition SListCtrl.h:468
int GetItemCount() const
Get the total number of items.
BOOL m_bCheckBox
Definition SListCtrl.h:478
int HitTest(const CPoint &pt)
Hit test to determine the item under the mouse.
SHeaderCtrl * m_pHeader
Definition SListCtrl.h:484
COLORREF m_crSelText
Definition SListCtrl.h:473
BOOL m_bHotTrack
Definition SListCtrl.h:463
void DeleteItem(int nItem)
Delete a specific item.
COLORREF m_crItemBg2
Definition SListCtrl.h:469
void UpdateScrollBar()
Update the scroll bar.
BOOL SetCheckState(int nItem, BOOL bCheck)
Set the check state of an item.
BOOL m_bMultiSelection
Definition SListCtrl.h:479
int m_nItemHeight
Definition SListCtrl.h:459
void OnLButtonDbClick(UINT nFlags, CPoint pt)
Handle left mouse button double-click event.
int GetColumnCount() const
Get the total number of columns.
BOOL GetSubItem(int nItem, int nSubItem, DXLVSUBITEM *plv) const
Get a subitem.
int GetCheckedItemCount()
Get the number of checked items.
BOOL OnHeaderClick(IEvtArgs *pEvt)
Handle header click event.
BOOL SetItemData(int nItem, LPARAM dwData)
Set the data associated with an item.
Definition SListCtrl.cpp:99
void DeleteColumn(int iCol)
Delete a specific column.
int GetCountPerPage(BOOL bPartial)
Get the number of items per page.
CRect GetListRect()
Get the rectangle of the list.
static LPCWSTR GetClassName()
Definition Sobject.hpp:41
Helper class for painting.
Definition SWnd.h:178
virtual CRect GetClientRect() const
Gets the client rectangle.
Definition SPanel.cpp:368
int GetSbWidth() const
Gets the width of the scrollbar.
Definition SPanel.cpp:650
BOOL HasScrollBar(BOOL bVertical) SCONST OVERRIDE
Checks if a scrollbar is present.
Definition SPanel.cpp:313
BOOL SetScrollPos(BOOL bVertical, int nNewPos, BOOL bRedraw) OVERRIDE
Sets the scroll position for a scrollbar.
Definition SPanel.cpp:251
void ScrollUpdate()
Updates the scrollbar.
Definition SPanel.cpp:579
BOOL FireEvent(IEvtArgs *evt) OVERRIDE
Fires an event.
Definition Swnd.cpp:1540
void ReleaseRenderTarget(IRenderTarget *pRT)
Releases the RenderTarget obtained via GetRenderTarget.
Definition Swnd.cpp:2372
BOOL IsVisible(BOOL bCheckParent=FALSE) SCONST OVERRIDE
Checks if the window is visible.
Definition Swnd.cpp:646
virtual CRect GetClientRect() const
Retrieves the client rectangle of the window.
Definition Swnd.cpp:243
void InsertChild(SWindow *pNewChild, SWindow *pInsertAfter=NULL)
Inserts a child window into the window tree.
Definition Swnd.cpp:538
LRESULT SSendMessage(UINT uMsg, WPARAM wParam=0, LPARAM lParam=0, BOOL *pbMsgHandled=NULL) OVERRIDE
Sends a message to the window.
Definition Swnd.cpp:364
virtual void BeforePaint(IRenderTarget *pRT, SPainter &painter)
Prepare rendering environment.
Definition Swnd.cpp:1755
void InvalidateRect(LPCRECT lprect) OVERRIDE
Invalidates a specific rectangle area of the window.
Definition Swnd.cpp:1444
BOOL m_bFocusable
Definition SWnd.h:2609
virtual SWindow * CreateChildByName(LPCWSTR pszName)
Create child window by name.
Definition Swnd.cpp:935
virtual void AfterPaint(IRenderTarget *pRT, SPainter &painter)
Restore rendering environment.
Definition Swnd.cpp:1776
void Invalidate() OVERRIDE
Invalidates the entire window.
Definition Swnd.cpp:1437
SEventSet m_evtSet
Definition SWnd.h:2581
BOOL m_bClipClient
Definition SWnd.h:2607
IRenderTarget * GetRenderTarget(LPCRECT pRc=NULL, GrtFlag gdcFlags=GRT_NODRAW, BOOL bClientRT=TRUE)
Retrieves a memory DC compatible with the SWND window.
Definition Swnd.cpp:2320
const wchar_t * as_string(const wchar_t *def=L"") const
Gets the attribute value as a string.
Definition SXml.cpp:95
Class representing an XML node.
Definition SXml.h:352
SXmlAttr attribute(const wchar_t *name, bool bCaseSensitive=false) const
Gets the attribute with the specified name.
Definition SXml.cpp:428
SXmlNode child(const wchar_t *name, bool bCaseSensitive=false) const
Gets the child node, attribute, or next/previous sibling with the specified name.
Definition SXml.cpp:423
BOOL set_userdata(int data) OVERRIDE
Sets user data for the node.
Definition SXml.cpp:270
Item structure.
Definition SListCtrl.h:62
ArrSubItem * arSubItems
Definition SListCtrl.h:73
LPARAM dwData
Definition SListCtrl.h:74
BOOL checked
Definition SListCtrl.h:75
Subitem structure.
Definition SListCtrl.h:34
UINT nImage
Definition SListCtrl.h:50
int cchTextMax
Definition SListCtrl.h:49
LPTSTR strText
Definition SListCtrl.h:48
Interface for rendering target objects.
Definition SRender-i.h:1440
HRESULT DrawText(LPCTSTR pszText, int cchLen, LPRECT pRc, UINT uFormat) PURE
Draw text within a rectangle.
HRESULT PushClipRect(LPCRECT pRect, UINT mode=RGN_AND) PURE
Push a rectangular clip region.
HRESULT PopClip() PURE
Pop the last clip region from the stack.
HRESULT FillSolidRect(LPCRECT pRect, COLORREF cr) PURE
Fill a rectangle with a solid color.
COLORREF SetTextColor(COLORREF color) PURE
Sets the current text color.