soui 5.0.0.1
Soui5 Doc
 
Loading...
Searching...
No Matches
SListView.cpp
1#include "souistd.h"
2#include "control/SListView.h"
3#include "helper/SListViewItemLocator.h"
4
5SNSBEGIN
6
7class SListViewDataSetObserver : public TObjRefImpl<ILvDataSetObserver> {
8 public:
9 SListViewDataSetObserver(SListView *pView)
10 : m_pOwner(pView)
11 {
12 }
13 STDMETHOD_(void, onChanged)(THIS) OVERRIDE;
14
15 STDMETHOD_(void, onInvalidated)(THIS) OVERRIDE;
16
17 STDMETHOD_(void, OnItemChanged)(THIS_ int iItem) OVERRIDE;
18
19 protected:
20 SListView *m_pOwner;
21};
22
23//////////////////////////////////////////////////////////////////////////
24void SListViewDataSetObserver::onChanged()
25{
26 m_pOwner->onDataSetChanged();
27}
28
29void SListViewDataSetObserver::onInvalidated()
30{
31 m_pOwner->onDataSetInvalidated();
32}
33
34void SListViewDataSetObserver::OnItemChanged(int iItem)
35{
36 m_pOwner->onItemDataChanged(iItem);
37}
38
39//////////////////////////////////////////////////////////////////////////
40SListView::SListView()
41 : m_iSelItem(-1)
42 , m_iFirstVisible(-1)
43 , m_pHoverItem(NULL)
44 , m_itemCapture(NULL)
45 , m_pSkinDivider(NULL)
46 , m_bWantTab(FALSE)
47 , m_bDataSetInvalidated(FALSE)
48 , m_bPendingUpdate(false)
49 , m_iPendingUpdateItem(-2)
50 , m_iPendingViewItem(-1)
51 , m_bVertical(TRUE)
52 , SHostProxy(this)
53{
54 m_bFocusable = TRUE;
55 m_observer.Attach(new SListViewDataSetObserver(this));
56 m_dwUpdateInterval = 40;
57 m_evtSet.addEvent(EVENTID(EventLVSelChanging));
58 m_evtSet.addEvent(EVENTID(EventLVSelChanged));
59}
60
61SListView::~SListView()
62{
63 m_observer = NULL;
64 m_lvItemLocator = NULL;
65}
66
67BOOL SListView::SetAdapter(ILvAdapter *adapter)
68{
69 if (!m_lvItemLocator)
70 {
71 SASSERT_MSGA(FALSE, "error: A item locator is in need before setting adapter!!!");
72 return FALSE;
73 }
74 if (m_adapter == adapter)
75 {
76 SSLOGW() << "the new adapter is same to previous set adapter, same as notifyDatasetChanged";
77 if (m_adapter)
78 {
79 onDataSetChanged();
80 }
81 return TRUE;
82 }
83
84 if (m_adapter)
85 {
86 m_adapter->unregisterDataSetObserver(m_observer);
87 }
88 {
89 // free all itemPanels in recycle
90 for (size_t i = 0; i < m_itemRecycle.GetCount(); i++)
91 {
92 SList<SItemPanel *> *lstItemPanels = m_itemRecycle.GetAt(i);
93 SPOSITION pos = lstItemPanels->GetHeadPosition();
94 while (pos)
95 {
96 SItemPanel *pItemPanel = lstItemPanels->GetNext(pos);
97 pItemPanel->Destroy();
98 }
99 delete lstItemPanels;
100 }
101 m_itemRecycle.RemoveAll();
102
103 // free all visible itemPanels
104 SPOSITION pos = m_lstItems.GetHeadPosition();
105 while (pos)
106 {
107 ItemInfo ii = m_lstItems.GetNext(pos);
108 ii.pItem->Destroy();
109 }
110 m_lstItems.RemoveAll();
111 m_pHoverItem = NULL;
112 m_itemCapture = NULL;
113 m_iSelItem = -1;
114 m_iFirstVisible = -1;
115 }
116
117 m_adapter = adapter;
118 if (m_lvItemLocator)
119 m_lvItemLocator->SetAdapter(adapter);
120 if (m_adapter)
121 {
122 SXmlNode xmlNode = m_xmlTemplate.root().first_child();
123 m_adapter->InitByTemplate(&xmlNode);
124 m_adapter->registerDataSetObserver(m_observer);
125 for (int i = 0; i < m_adapter->getViewTypeCount(); i++)
126 {
127 m_itemRecycle.Add(new SList<SItemPanel *>());
128 }
129 onDataSetChanged();
130 }
131 return TRUE;
132}
133
134void SListView::UpdateScrollBar()
135{
136 CRect rcClient = SWindow::GetClientRect();
137 CSize size = rcClient.Size();
138 CSize szView;
139 if (m_bVertical)
140 {
141 szView.cx = rcClient.Width();
142 szView.cy = m_lvItemLocator ? m_lvItemLocator->GetTotalHeight() : 0;
143
144 // 关闭滚动条
145 m_wBarVisible = SSB_NULL;
146
147 if (size.cy < szView.cy)
148 {
149 // 需要纵向滚动条
150 m_wBarVisible |= SSB_VERT;
151 m_siVer.nMin = 0;
152 m_siVer.nMax = szView.cy - 1;
153 m_siVer.nPage = size.cy;
154 m_siVer.nPos = smin(m_siVer.nPos, m_siVer.nMax - (int)m_siVer.nPage);
155 }
156 else
157 {
158 // 不需要纵向滚动条
159 m_siVer.nPage = size.cy;
160 m_siVer.nMin = 0;
161 m_siVer.nMax = size.cy - 1;
162 m_siVer.nPos = 0;
163 }
164
165 SetScrollPos(TRUE, m_siVer.nPos, FALSE);
166 }
167 else
168 {
169 szView.cy = rcClient.Height();
170 szView.cx = m_lvItemLocator ? m_lvItemLocator->GetTotalHeight() : 0;
171
172 // 关闭滚动条
173 m_wBarVisible = SSB_NULL;
174
175 if (size.cx < szView.cx)
176 {
177 // 需要纵向滚动条
178 m_wBarVisible |= SSB_HORZ;
179 m_siHoz.nMin = 0;
180 m_siHoz.nMax = szView.cx - 1;
181 m_siHoz.nPage = size.cx;
182 m_siHoz.nPos = smin(m_siHoz.nPos, m_siHoz.nMax - (int)m_siHoz.nPage);
183 }
184 else
185 {
186 // 不需要纵向滚动条
187 m_siHoz.nPage = size.cx;
188 m_siHoz.nMin = 0;
189 m_siHoz.nMax = size.cx - 1;
190 m_siHoz.nPos = 0;
191 }
192
193 SetScrollPos(FALSE, m_siHoz.nPos, FALSE);
194 }
195
196 // 重新计算客户区及非客户区
197 SSendMessage(WM_NCCALCSIZE);
198
199 InvalidateRect(NULL);
200}
201
202void SListView::onDataSetChanged()
203{
204 if (!m_adapter)
205 return;
206 if (!IsVisible(TRUE))
207 {
208 m_bPendingUpdate = true;
209 m_iPendingUpdateItem = -1;
210 return;
211 }
212 if (m_lvItemLocator)
213 m_lvItemLocator->OnDataSetChanged();
214 if (m_iSelItem != -1 && m_iSelItem >= m_adapter->getCount())
215 m_iSelItem = -1;
216 UpdateScrollBar();
217 UpdateVisibleItems();
218}
219
220void SListView::onDataSetInvalidated()
221{
222 m_bDataSetInvalidated = TRUE;
223 Invalidate();
224}
225
226void SListView::onItemDataChanged(int iItem)
227{
228 if (!m_adapter)
229 return;
230 if (!IsVisible(TRUE))
231 {
232 m_bPendingUpdate = true;
233 m_iPendingUpdateItem = m_iPendingUpdateItem == -2 ? iItem : -1;
234 return;
235 }
236
237 if (iItem < m_iFirstVisible)
238 return;
239 if (iItem >= m_iFirstVisible + (int)m_lstItems.GetCount())
240 return;
241 if (m_lvItemLocator->IsFixHeight())
242 UpdateVisibleItem(iItem);
243 else
244 UpdateVisibleItems();
245}
246
247void SListView::OnPaint(IRenderTarget *pRT)
248{
249 if (m_bDataSetInvalidated)
250 {
251 UpdateVisibleItems();
252 m_bDataSetInvalidated = FALSE;
253 }
254
255 SPainter duiDC;
256 BeforePaint(pRT, duiDC);
257
258 int iFirst = m_iFirstVisible;
259 if (iFirst != -1)
260 {
261 CRect rcClient;
262 GetClientRect(&rcClient);
263 pRT->PushClipRect(&rcClient, RGN_AND);
264
265 CRect rcClip;
266 SAutoRefPtr<IRegionS> rgnClip;
267 pRT->GetClipRegion(&rgnClip);
268 pRT->GetClipBox(&rcClip);
269
270 float fMat[9];
271 pRT->GetTransform(fMat);
272 SMatrix mtx(fMat);
273
274 SCROLLINFO &si = m_bVertical ? m_siVer : m_siHoz;
275 int nOffset = m_lvItemLocator->Item2Position(iFirst) - si.nPos;
276
277 CRect rcItem(rcClient);
278 if (m_bVertical)
279 rcItem.bottom = rcItem.top + nOffset;
280 else
281 rcItem.right = rcItem.left + nOffset;
282
283 SPOSITION pos = m_lstItems.GetHeadPosition();
284 int i = 0;
285 for (; pos; i++)
286 {
287 ItemInfo ii = m_lstItems.GetNext(pos);
288 if (m_bVertical)
289 {
290 rcItem.top = rcItem.bottom;
291 rcItem.bottom = rcItem.top + m_lvItemLocator->GetItemHeight(iFirst + i);
292 }
293 else
294 {
295 rcItem.left = rcItem.right;
296 rcItem.right = rcItem.left + m_lvItemLocator->GetItemHeight(iFirst + i);
297 }
298 if (SItemPanel::IsItemInClip(mtx, rcClip, rgnClip, rcItem))
299 {
300 ii.pItem->Draw(pRT, rcItem);
301 }
302
303 if (m_bVertical)
304 {
305 rcItem.top = rcItem.bottom;
306 rcItem.bottom += m_lvItemLocator->GetDividerSize();
307 }
308 else
309 {
310 rcItem.left = rcItem.right;
311 rcItem.right += m_lvItemLocator->GetDividerSize();
312 }
313 if (m_pSkinDivider && !rcItem.IsRectEmpty() && rgnClip->RectInRegion(&rcItem))
314 { //绘制分隔线
315 m_pSkinDivider->DrawByIndex(pRT, rcItem, 0);
316 }
317 }
318
319 pRT->PopClip();
320 }
321 AfterPaint(pRT, duiDC);
322}
323
324BOOL SListView::OnScroll(BOOL bVertical, UINT uCode, int nPos)
325{
326 SCROLLINFO &si = bVertical ? m_siVer : m_siHoz;
327 int nOldPos = si.nPos;
328 SPanel::OnScroll(bVertical, uCode, nPos);
329 int nNewPos = si.nPos;
330 if (nOldPos != nNewPos)
331 {
332 UpdateVisibleItems();
333
334 //加速滚动时UI的刷新
335 if (uCode == SB_THUMBTRACK)
336 ScrollUpdate();
337
338 return TRUE;
339 }
340 return FALSE;
341}
342
343void SListView::UpdateVisibleItems()
344{
345 if (!m_adapter)
346 return;
347 SAutoEnableHostPrivUiDef enableUiDef(this);
348 int iOldFirstVisible = m_iFirstVisible;
349 int iOldLastVisible = m_iFirstVisible + (int)m_lstItems.GetCount();
350 int nOldTotalHeight = m_lvItemLocator->GetTotalHeight();
351
352 SCROLLINFO &si = m_bVertical ? m_siVer : m_siHoz;
353
354 int iNewFirstVisible = m_lvItemLocator->Position2Item(si.nPos);
355 int iNewLastVisible = iNewFirstVisible;
356 int pos = m_lvItemLocator->Item2Position(iNewFirstVisible);
357 int iHoverItem = m_pHoverItem ? (int)m_pHoverItem->GetItemIndex() : -1;
358 m_pHoverItem = NULL;
359
360 ItemInfo *pItemInfos = new ItemInfo[m_lstItems.GetCount()];
361 SPOSITION spos = m_lstItems.GetHeadPosition();
362 int i = 0;
363 while (spos)
364 {
365 pItemInfos[i++] = m_lstItems.GetNext(spos);
366 }
367
368 m_lstItems.RemoveAll();
369
370 if (iNewFirstVisible != -1)
371 {
372 while (pos < si.nPos + (int)si.nPage && iNewLastVisible < m_adapter->getCount())
373 {
374 DWORD dwState = WndState_Normal;
375 if (iHoverItem == iNewLastVisible)
376 dwState |= WndState_Hover;
377 if (m_iSelItem == iNewLastVisible)
378 dwState |= WndState_Check;
379
380 ItemInfo ii = { NULL, -1 };
381 ii.nType = m_adapter->getItemViewType(iNewLastVisible, dwState);
382 if (iNewLastVisible >= iOldFirstVisible && iNewLastVisible < iOldLastVisible)
383 { // use the old visible item
384 int iItem = iNewLastVisible - iOldFirstVisible; //(iNewLastVisible-iNewFirstVisible) +
385 //(iNewFirstVisible-iOldFirstVisible);
386 SASSERT(iItem >= 0 && iItem <= (iOldLastVisible - iOldFirstVisible));
387 if (ii.nType == pItemInfos[iItem].nType)
388 {
389 ii = pItemInfos[iItem];
390 pItemInfos[iItem].pItem = NULL; //标记该行已经被重用
391 }
392 }
393 BOOL bNewItem = FALSE;
394 if (!ii.pItem)
395 { // create new visible item
396 SList<SItemPanel *> *lstRecycle = m_itemRecycle.GetAt(ii.nType);
397 if (lstRecycle->IsEmpty())
398 { //创建一个新的列表项
399 bNewItem = TRUE;
400 ii.pItem = SItemPanel::Create(this, SXmlNode(), this);
401 ii.pItem->GetEventSet()->subscribeEvent(EventItemPanelClick::EventID, Subscriber(&SListView::OnItemClick, this));
402 }
403 else
404 {
405 ii.pItem = lstRecycle->RemoveHead();
406 }
407 ii.pItem->SetItemIndex(iNewLastVisible);
408 }
409 ii.pItem->SetVisible(TRUE);
410 CRect rcItem = GetClientRect();
411 rcItem.MoveToXY(0, 0);
412 if (m_lvItemLocator->IsFixHeight())
413 {
414 if (m_bVertical)
415 rcItem.bottom = m_lvItemLocator->GetItemHeight(iNewLastVisible);
416 else
417 rcItem.right = m_lvItemLocator->GetItemHeight(iNewLastVisible);
418 ii.pItem->Move(rcItem);
419 }
420
421 //设置状态,同时暂时禁止应用响应statechanged事件。
422 ii.pItem->GetEventSet()->setMutedState(true);
423 ii.pItem->ModifyItemState(dwState, 0);
424 ii.pItem->GetEventSet()->setMutedState(false);
425 if (dwState & WndState_Hover)
426 m_pHoverItem = ii.pItem;
427
428 SXmlNode xmlNode = m_xmlTemplate.root().first_child();
429 ii.pItem->LockUpdate();
430 m_adapter->getView(iNewLastVisible, ii.pItem, &xmlNode);
431 ii.pItem->UnlockUpdate();
432 if (bNewItem)
433 {
434 ii.pItem->SDispatchMessage(UM_SETSCALE, GetScale(), 0);
435 ii.pItem->SDispatchMessage(UM_SETLANGUAGE, 0, 0);
436 ii.pItem->DoColorize(GetColorizeColor());
437 }
438 if (!m_lvItemLocator->IsFixHeight())
439 {
440 if (m_bVertical)
441 {
442 rcItem.bottom = 0;
443 CSize szItem;
444 m_adapter->getViewDesiredSize(&szItem, iNewLastVisible, ii.pItem, rcItem.Width(), rcItem.Height());
445 rcItem.bottom = rcItem.top + szItem.cy;
446 ii.pItem->Move(rcItem);
447 m_lvItemLocator->SetItemHeight(iNewLastVisible, szItem.cy);
448 }
449 else
450 {
451 rcItem.right = 0;
452 CSize szItem;
453 m_adapter->getViewDesiredSize(&szItem, iNewLastVisible, ii.pItem, rcItem.Width(), rcItem.Height());
454 rcItem.right = rcItem.left + szItem.cx;
455 ii.pItem->Move(rcItem);
456 m_lvItemLocator->SetItemHeight(iNewLastVisible, szItem.cx);
457 }
458 }
459 ii.pItem->UpdateLayout();
460
461 m_lstItems.AddTail(ii);
462 pos += (m_bVertical ? rcItem.bottom : rcItem.right) + m_lvItemLocator->GetDividerSize();
463
464 iNewLastVisible++;
465 }
466 }
467
468 // move old visible items which were not reused to recycle
469 for (int i = 0; i < (iOldLastVisible - iOldFirstVisible); i++)
470 {
471 ItemInfo ii = pItemInfos[i];
472 if (!ii.pItem)
473 continue;
474 if (ii.pItem->GetState() & WndState_Hover)
475 {
476 ii.pItem->DoFrameEvent(WM_MOUSELEAVE, 0, 0);
477 }
478 ii.pItem->GetEventSet()->setMutedState(true);
479 if (ii.pItem->GetState() & WndState_Check)
480 {
481 ii.pItem->ModifyItemState(0, WndState_Check);
482 ii.pItem->GetFocusManager()->ClearFocus();
483 }
484 ii.pItem->SetVisible(FALSE);
485 ii.pItem->GetEventSet()->setMutedState(false);
486 m_itemRecycle[ii.nType]->AddTail(ii.pItem);
487 }
488 delete[] pItemInfos;
489
490 m_iFirstVisible = iNewFirstVisible;
491
492 if (!m_lvItemLocator->IsFixHeight() && m_lvItemLocator->GetTotalHeight() != nOldTotalHeight)
493 { // update scroll range
494 UpdateScrollBar();
495 UpdateVisibleItems(); //根据新的滚动条状态重新记录显示列表项
496 }
497 else
498 {
499 InvalidateRect(NULL);
500 }
501}
502
503void SListView::UpdateVisibleItem(int iItem)
504{
505 SAutoEnableHostPrivUiDef enableUiDef(this);
506 SASSERT(m_lvItemLocator->IsFixHeight());
507 SItemPanel *pItem = GetItemPanel(iItem);
508 SASSERT(pItem);
509 SXmlNode xmlNode = m_xmlTemplate.root().first_child();
510 m_adapter->getView(iItem, pItem, &xmlNode);
511 pItem->Invalidate();
512}
513
514void SListView::OnSize(UINT nType, CSize size)
515{
516 __baseCls::OnSize(nType, size);
517 UpdateScrollBar();
518
519 // update item window
520 CRect rcClient = GetClientRect();
521 SPOSITION pos = m_lstItems.GetHeadPosition();
522 while (pos)
523 {
524 ItemInfo ii = m_lstItems.GetNext(pos);
525 int idx = (int)ii.pItem->GetItemIndex();
526 int nHei = m_lvItemLocator->GetItemHeight(idx);
527 CRect rcItem;
528 if (m_bVertical)
529 rcItem.right = rcClient.Width(), rcItem.bottom = nHei;
530 else
531 rcItem.right = nHei, rcItem.bottom = rcClient.Height();
532 ii.pItem->Move(rcItem);
533 }
534
535 UpdateVisibleItems();
536}
537
538void SListView::OnDestroy()
539{
540 if (m_adapter)
541 {
542 m_adapter->unregisterDataSetObserver(m_observer);
543 }
544
545 // destroy all itempanel
546 SPOSITION pos = m_lstItems.GetHeadPosition();
547 while (pos)
548 {
549 ItemInfo ii = m_lstItems.GetNext(pos);
550 ii.pItem->Release();
551 }
552 m_lstItems.RemoveAll();
553
554 for (int i = 0; i < (int)m_itemRecycle.GetCount(); i++)
555 {
556 SList<SItemPanel *> *pLstTypeItems = m_itemRecycle[i];
557 SPOSITION pos = pLstTypeItems->GetHeadPosition();
558 while (pos)
559 {
560 SItemPanel *pItem = pLstTypeItems->GetNext(pos);
561 pItem->Release();
562 }
563 delete pLstTypeItems;
564 }
565 m_itemRecycle.RemoveAll();
566 __baseCls::OnDestroy();
567}
568
569//////////////////////////////////////////////////////////////////////////
570BOOL SListView::IsItemRedrawDelay() const
571{
572 return TRUE;
573}
574
575BOOL SListView::OnItemGetRect(const SOsrPanel *pItem, CRect &rcItem) const
576{
577 int iPosition = (int)pItem->GetItemIndex();
578 if (iPosition < 0 || iPosition >= m_adapter->getCount())
579 return FALSE;
580 if (m_bVertical)
581 {
582 int nOffset = m_lvItemLocator->Item2Position(iPosition) - m_siVer.nPos;
583 rcItem = GetClientRect();
584 rcItem.top += nOffset;
585 rcItem.bottom = rcItem.top + m_lvItemLocator->GetItemHeight(iPosition);
586 }
587 else
588 {
589 int nOffset = m_lvItemLocator->Item2Position(iPosition) - m_siHoz.nPos;
590 rcItem = GetClientRect();
591 rcItem.left += nOffset;
592 rcItem.right = rcItem.left + m_lvItemLocator->GetItemHeight(iPosition);
593 }
594 return TRUE;
595}
596
597void SListView::OnItemSetCapture(SOsrPanel *pItem, BOOL bCapture)
598{
599 if (bCapture)
600 {
602 m_itemCapture = pItem;
603 }
604 else
605 {
607 m_itemCapture = NULL;
608 }
609}
610
611void SListView::RedrawItem(SOsrPanel *pItem)
612{
613 pItem->InvalidateRect(NULL);
614}
615
616SItemPanel *SListView::HitTest(CPoint &pt) const
617{
618 SPOSITION pos = m_lstItems.GetHeadPosition();
619 while (pos)
620 {
621 ItemInfo ii = m_lstItems.GetNext(pos);
622 CRect rcItem = ii.pItem->GetItemRect();
623 if (rcItem.PtInRect(pt))
624 {
625 pt -= rcItem.TopLeft();
626 return ii.pItem;
627 }
628 }
629 return NULL;
630}
631
632LRESULT SListView::OnMouseEvent(UINT uMsg, WPARAM wParam, LPARAM lParam)
633{
634 SetMsgHandled(FALSE);
635 if (!m_adapter)
636 {
637 return 0;
638 }
639
640 LRESULT lRet = 0;
641 CPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
642
643 if (m_itemCapture)
644 {
645 CRect rcItem = m_itemCapture->GetItemRect();
646 pt -= rcItem.TopLeft();
647 lRet = m_itemCapture->DoFrameEvent(uMsg, wParam, MAKELPARAM(pt.x, pt.y));
648 }
649 else
650 {
651 if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN)
652 { //交给panel处理
653 __baseCls::ProcessSwndMessage(uMsg, wParam, lParam, lRet);
654 }
655
656 SItemPanel *pHover = HitTest(pt);
657 if (pHover != m_pHoverItem)
658 {
659 SOsrPanel *nOldHover = m_pHoverItem;
660 m_pHoverItem = pHover;
661 if (nOldHover)
662 {
663 nOldHover->DoFrameEvent(WM_MOUSELEAVE, 0, 0);
664 RedrawItem(nOldHover);
665 }
666 if (m_pHoverItem)
667 {
668 m_pHoverItem->DoFrameEvent(WM_MOUSEHOVER, wParam, MAKELPARAM(pt.x, pt.y));
669 RedrawItem(m_pHoverItem);
670 }
671 }
672 if (m_pHoverItem)
673 {
674 m_pHoverItem->DoFrameEvent(uMsg, wParam, MAKELPARAM(pt.x, pt.y));
675 }
676 }
677
678 if (uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP || uMsg == WM_MBUTTONUP)
679 { //交给panel处理
680 __baseCls::ProcessSwndMessage(uMsg, wParam, lParam, lRet);
681 }
682 SetMsgHandled(TRUE);
683 return 0;
684}
685
686LRESULT SListView::OnKeyEvent(UINT uMsg, WPARAM wParam, LPARAM lParam)
687{
688 LRESULT lRet = 0;
689 SItemPanel *pItem = GetItemPanel(m_iSelItem);
690 if (pItem)
691 {
692 lRet = pItem->DoFrameEvent(uMsg, wParam, lParam);
693 SetMsgHandled(pItem->IsMsgHandled());
694 }
695 else
696 {
697 SetMsgHandled(FALSE);
698 }
699 return lRet;
700}
701
702void SListView::OnMouseLeave()
703{
704 __baseCls::OnMouseLeave();
705 if (m_pHoverItem)
706 {
707 m_pHoverItem->DoFrameEvent(WM_MOUSELEAVE, 0, 0);
708 m_pHoverItem = NULL;
709 }
710}
711
712void SListView::OnKeyDown(TCHAR nChar, UINT nRepCnt, UINT nFlags)
713{
714 if (!m_adapter)
715 {
716 SetMsgHandled(FALSE);
717 return;
718 }
719
720 if (m_iSelItem != -1 && m_bWantTab)
721 {
722 SItemPanel *pItem = GetItemPanel(m_iSelItem);
723 if (pItem)
724 {
725 pItem->DoFrameEvent(WM_KEYDOWN, nChar, MAKELONG(nFlags, nRepCnt));
726 if (pItem->IsMsgHandled())
727 return;
728 }
729 }
730
731 int nNewSelItem = -1;
732 SWindow *pOwner = GetOwner();
733 if (pOwner && (nChar == VK_ESCAPE || nChar == VK_RETURN))
734 {
735 pOwner->SSendMessage(WM_KEYDOWN, nChar, MAKELONG(nFlags, nRepCnt));
736 return;
737 }
738
739 if (nChar == VK_DOWN && m_iSelItem < m_adapter->getCount() - 1)
740 nNewSelItem = m_iSelItem + 1;
741 else if (nChar == VK_UP && m_iSelItem > 0)
742 nNewSelItem = m_iSelItem - 1;
743 else
744 {
745 switch (nChar)
746 {
747 case VK_PRIOR:
748 OnScroll(TRUE, SB_PAGEUP, 0);
749 break;
750 case VK_NEXT:
751 OnScroll(TRUE, SB_PAGEDOWN, 0);
752 break;
753 case VK_HOME:
754 OnScroll(TRUE, SB_TOP, 0);
755 break;
756 case VK_END:
757 OnScroll(TRUE, SB_BOTTOM, 0);
758 break;
759 }
760 if (nChar == VK_PRIOR || nChar == VK_HOME)
761 {
762 if (!m_lstItems.IsEmpty())
763 {
764 nNewSelItem = (int)m_lstItems.GetHead().pItem->GetItemIndex();
765 }
766 }
767 else if (nChar == VK_NEXT || nChar == VK_END)
768 {
769 if (!m_lstItems.IsEmpty())
770 {
771 nNewSelItem = (int)m_lstItems.GetTail().pItem->GetItemIndex();
772 }
773 }
774 }
775
776 if (nNewSelItem != -1)
777 {
778 EnsureVisible(nNewSelItem);
779 SetSel(nNewSelItem, TRUE);
780 }
781 else
782 {
783 SetMsgHandled(FALSE);
784 }
785}
786
787void SListView::EnsureVisible(int iItem)
788{
789 if (iItem < 0 || iItem >= m_adapter->getCount())
790 return;
791 if (!IsVisible(TRUE))
792 {
793 m_iPendingViewItem = iItem;
794 return;
795 }
796
797 int iFirstVisible = m_iFirstVisible;
798 int iLastVisible = m_iFirstVisible + (int)m_lstItems.GetCount();
799 int nPageSize = m_bVertical ? m_siVer.nPage : m_siHoz.nPage;
800 if (iItem >= iFirstVisible && iItem < iLastVisible)
801 {
802 if (iItem == iFirstVisible)
803 {
804 int pos = m_lvItemLocator->Item2Position(iItem);
805 OnScroll(m_bVertical, SB_THUMBPOSITION, pos);
806 }
807 else if (iItem == iLastVisible - 1)
808 {
809 if (iItem == m_adapter->getCount() - 1)
810 OnScroll(m_bVertical, SB_BOTTOM, 0);
811 else
812 {
813 int pos = m_lvItemLocator->Item2Position(iItem + 1) - nPageSize;
814 OnScroll(m_bVertical, SB_THUMBPOSITION, pos);
815 }
816 }
817
818 return;
819 }
820
821 if (iItem < iFirstVisible)
822 { // scroll up
823 int pos = m_lvItemLocator->Item2Position(iItem);
824 OnScroll(m_bVertical, SB_THUMBPOSITION, pos);
825 }
826 else // if(iItem >= iLastVisible)
827 { // scroll down
828 if (iItem == m_adapter->getCount() - 1)
829 {
830 OnScroll(m_bVertical, SB_BOTTOM, 0);
831 }
832 else
833 {
834 int pos = m_lvItemLocator->Item2Position(iItem + 1) - nPageSize;
835 OnScroll(m_bVertical, SB_THUMBPOSITION, pos);
836 }
837 }
838 if (!m_lvItemLocator->IsFixHeight())
839 {
840 int pos = m_lvItemLocator->Item2Position(iItem);
841 OnScroll(m_bVertical, SB_THUMBPOSITION, pos);
842 }
843}
844
845BOOL SListView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
846{
847 SItemPanel *pSelItem = GetItemPanel(m_iSelItem);
848 if (pSelItem)
849 {
850 CRect rcItem = pSelItem->GetItemRect();
851 CPoint pt2 = pt - rcItem.TopLeft();
852 if (pSelItem->DoFrameEvent(WM_MOUSEWHEEL, MAKEWPARAM(nFlags, zDelta), MAKELPARAM(pt2.x, pt2.y)))
853 return TRUE;
854 }
855 return __baseCls::OnMouseWheel(nFlags, zDelta, pt);
856}
857
858int SListView::GetScrollLineSize(BOOL bVertical)
859{
860 return m_lvItemLocator->GetScrollLineSize();
861}
862
863SItemPanel *SListView::GetItemPanel(int iItem)
864{
865 if (!m_adapter || iItem < 0 || iItem >= m_adapter->getCount())
866 return NULL;
867 SPOSITION pos = m_lstItems.GetHeadPosition();
868 while (pos)
869 {
870 ItemInfo ii = m_lstItems.GetNext(pos);
871 if ((int)ii.pItem->GetItemIndex() == iItem)
872 return ii.pItem;
873 }
874 return NULL;
875}
876
877BOOL SListView::CreateChildren(SXmlNode xmlNode)
878{
879 SXmlNode xmlTemplate = xmlNode.child(L"template");
880 if (xmlTemplate)
881 {
882 m_xmlTemplate.root().append_copy(xmlTemplate);
883 LPCWSTR kItemSize = m_bVertical ? L"itemHeight" : L"itemWidth";
884 SLayoutSize nItemHei = GETLAYOUTSIZE(xmlTemplate.attribute(kItemSize).value());
885 if (nItemHei.fSize > 0.0f)
886 { //指定了itemHeight属性时创建一个固定行高的定位器
887 IListViewItemLocator *pItemLocator = new SListViewItemLocatorFix(nItemHei, m_nDividerSize);
888 SetItemLocator(pItemLocator);
889 pItemLocator->Release();
890 }
891 else
892 { //创建一个行高可变的行定位器,从defHeight/defWidth属性中获取默认行高
893 LPCWSTR kDefSize = m_bVertical ? L"defHeight" : L"defWidth";
894 IListViewItemLocator *pItemLocator = new SListViewItemLocatorFlex(GETLAYOUTSIZE(xmlTemplate.attribute(kDefSize).as_string(L"30dp")), m_nDividerSize);
895 SetItemLocator(pItemLocator);
896 pItemLocator->Release();
897 }
898 }
899 return TRUE;
900}
901
902void SListView::SetItemLocator(IListViewItemLocator *pItemLocator)
903{
904 m_lvItemLocator = pItemLocator;
905 if (m_lvItemLocator)
906 {
907 m_lvItemLocator->SetAdapter(GetAdapter());
908 m_lvItemLocator->SetScale(GetScale());
909 }
910 onDataSetChanged();
911}
912
913BOOL SListView::UpdateToolTip(CPoint pt, SwndToolTipInfo &tipInfo)
914{
915 if (!m_pHoverItem)
916 return __baseCls::UpdateToolTip(pt, tipInfo);
917 return m_pHoverItem->UpdateToolTip(pt, tipInfo);
918}
919
920void SListView::SetSel(int iItem, BOOL bNotify)
921{
922 if (!m_adapter)
923 return;
924
925 if (iItem >= m_adapter->getCount())
926 return;
927
928 if (iItem < 0)
929 iItem = -1;
930
931 int nOldSel = m_iSelItem;
932 int nNewSel = iItem;
933
934 m_iSelItem = nNewSel;
935 if (bNotify)
936 {
937 EventLVSelChanging evt(this);
938 evt.bCancel = FALSE;
939 evt.iOldSel = nOldSel;
940 evt.iNewSel = nNewSel;
941 FireEvent(evt);
942 if (evt.bCancel)
943 { // Cancel SetSel and restore selection state
944 m_iSelItem = nOldSel;
945 return;
946 }
947 }
948
949 if (nOldSel == nNewSel)
950 return;
951
952 m_iSelItem = nOldSel;
953 SItemPanel *pItem = GetItemPanel(nOldSel);
954 if (pItem)
955 {
956 pItem->GetFocusManager()->ClearFocus();
957 pItem->ModifyItemState(0, WndState_Check);
958 RedrawItem(pItem);
959 }
960 m_iSelItem = nNewSel;
961 pItem = GetItemPanel(nNewSel);
962 if (pItem)
963 {
964 pItem->ModifyItemState(WndState_Check, 0);
965 RedrawItem(pItem);
966 }
967
968 if (bNotify)
969 {
970 EventLVSelChanged evt(this);
971 evt.iOldSel = nOldSel;
972 evt.iNewSel = nNewSel;
973 FireEvent(evt);
974 }
975}
976
977UINT SListView::OnGetDlgCode() const
978{
979 if (m_bWantTab)
980 return SC_WANTALLKEYS;
981 else
982 return SC_WANTARROWS | SC_WANTSYSKEY;
983}
984
985void SListView::OnKillFocus(SWND wndFocus)
986{
987 __baseCls::OnKillFocus(wndFocus);
988
989 if (m_iSelItem == -1)
990 return;
991
992 SItemPanel *pSelPanel = GetItemPanel(m_iSelItem);
993 if (pSelPanel)
994 pSelPanel->GetFocusManager()->StoreFocusedView();
995}
996
997void SListView::OnSetFocus(SWND wndOld)
998{
999 __baseCls::OnSetFocus(wndOld);
1000 if (m_iSelItem == -1)
1001 return;
1002
1003 SItemPanel *pSelPanel = GetItemPanel(m_iSelItem);
1004 if (pSelPanel)
1005 pSelPanel->GetFocusManager()->RestoreFocusedView();
1006}
1007
1008BOOL SListView::OnSetCursor(const CPoint &pt)
1009{
1010 BOOL bRet = FALSE;
1011 if (m_itemCapture)
1012 {
1013 CRect rcItem = m_itemCapture->GetItemRect();
1014 bRet = m_itemCapture->DoFrameEvent(WM_SETCURSOR, 0, MAKELPARAM(pt.x - rcItem.left, pt.y - rcItem.top)) != 0;
1015 }
1016 else if (m_pHoverItem)
1017 {
1018 CRect rcItem = m_pHoverItem->GetItemRect();
1019 bRet = m_pHoverItem->DoFrameEvent(WM_SETCURSOR, 0, MAKELPARAM(pt.x - rcItem.left, pt.y - rcItem.top)) != 0;
1020 }
1021 if (!bRet)
1022 {
1023 bRet = __baseCls::OnSetCursor(pt);
1024 }
1025 return bRet;
1026}
1027
1028BOOL SListView::OnItemClick(IEvtArgs *pEvt)
1029{
1030 SItemPanel *pItemPanel = sobj_cast<SItemPanel>(pEvt->Sender());
1031 SASSERT(pItemPanel);
1032 int iItem = (int)pItemPanel->GetItemIndex();
1033 if (iItem != m_iSelItem)
1034 {
1035 SetSel(iItem, TRUE);
1036 }
1037 return TRUE;
1038}
1039
1040void SListView::OnColorize(COLORREF cr)
1041{
1042 __baseCls::OnColorize(cr);
1043 DispatchMessage2Items(UM_SETCOLORIZE, cr, 0);
1044}
1045
1046void SListView::OnScaleChanged(int nScale)
1047{
1048 __baseCls::OnScaleChanged(nScale);
1049 if (m_lvItemLocator)
1050 m_lvItemLocator->SetScale(nScale);
1051 DispatchMessage2Items(UM_SETSCALE, nScale, 0);
1052 UpdateVisibleItems();
1053}
1054
1055HRESULT SListView::OnLanguageChanged()
1056{
1057 HRESULT hret = __baseCls::OnLanguageChanged();
1058 DispatchMessage2Items(UM_SETLANGUAGE, 0, 0);
1059 return hret;
1060}
1061
1062void SListView::DispatchMessage2Items(UINT uMsg, WPARAM wParam, LPARAM lParam)
1063{
1064 SPOSITION pos = m_lstItems.GetHeadPosition();
1065 while (pos)
1066 {
1067 ItemInfo ii = m_lstItems.GetNext(pos);
1068 ii.pItem->SDispatchMessage(uMsg, wParam, lParam);
1069 }
1070 for (UINT i = 0; i < m_itemRecycle.GetCount(); i++)
1071 {
1072 SList<SItemPanel *> *pLstTypeItems = m_itemRecycle[i];
1073 SPOSITION pos = pLstTypeItems->GetHeadPosition();
1074 while (pos)
1075 {
1076 SItemPanel *pItem = pLstTypeItems->GetNext(pos);
1077 pItem->SDispatchMessage(uMsg, wParam, lParam);
1078 }
1079 }
1080}
1081
1082void SListView::OnShowWindow(BOOL bShow, UINT nStatus)
1083{
1084 __baseCls::OnShowWindow(bShow, nStatus);
1085 if (IsVisible(TRUE))
1086 {
1087 if (m_bPendingUpdate)
1088 {
1089 if (m_iPendingUpdateItem == -1)
1090 onDataSetChanged();
1091 else
1092 onItemDataChanged(m_iPendingUpdateItem);
1093 m_bPendingUpdate = false;
1094 m_iPendingUpdateItem = -2;
1095 }
1096 if (m_iPendingViewItem != -1)
1097 {
1098 EnsureVisible(m_iPendingViewItem);
1099 m_iPendingViewItem = -1;
1100 }
1101 }
1102}
1103
1104void SListView::OnRebuildFont()
1105{
1106 __baseCls::OnRebuildFont();
1107 DispatchMessage2Items(UM_UPDATEFONT, 0, 0);
1108}
1109
1110ILvAdapter *SListView::GetAdapter() const
1111{
1112 return m_adapter;
1113}
1114
1115IListViewItemLocator *SListView::GetItemLocator() const
1116{
1117 return m_lvItemLocator;
1118}
1119
1120int SListView::GetSel() const
1121{
1122 return m_iSelItem;
1123}
1124
1125IItemPanel *SListView::HitTest(const POINT *pt) const
1126{
1127 SASSERT(pt);
1128 if (!pt)
1129 return NULL;
1130 CPoint pt2(*pt);
1131 return HitTest(pt2);
1132}
1133
1134void SListView::GetDesiredSize(THIS_ SIZE *psz, int nParentWid, int nParentHei)
1135{
1136 __baseCls::GetDesiredSize(psz, nParentWid, nParentHei);
1137 ILayoutParam *pLayoutParam = GetLayoutParam();
1138 if (pLayoutParam->IsWrapContent(Vert) && m_lvItemLocator && m_lvItemLocator->IsFixHeight())
1139 {
1140 CRect rcPadding = GetStyle().GetPadding();
1141 psz->cy = m_lvItemLocator->GetTotalHeight() + rcPadding.top + rcPadding.bottom;
1142 if (nParentHei > 0 && psz->cy > nParentHei)
1143 psz->cy = nParentHei;
1144 }
1145}
1146
1147SNSEND
@ WndState_Hover
Definition SWnd.h:76
@ WndState_Check
Definition SWnd.h:78
@ WndState_Normal
Definition SWnd.h:75
void RestoreFocusedView()
Restores the focused view.
void ClearFocus()
Clears the focused window.
void StoreFocusedView()
Stores the focused view.
virtual CRect GetClientRect() const
Gets the client rectangle.
Definition SPanel.cpp:368
virtual BOOL OnScroll(BOOL bVertical, UINT uCode, int nPos)
Handles scroll events.
Definition SPanel.cpp:517
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
SWindow * GetOwner() const
Retrieves the current owner of the window.
Definition Swnd.cpp:706
BOOL Destroy() OVERRIDE
Destroys the window.
Definition Swnd.cpp:504
void SDispatchMessage(UINT uMsg, WPARAM wParam=0, LPARAM lParam=0) OVERRIDE
Dispatches a message to the window.
Definition Swnd.cpp:388
int GetScale() SCONST OVERRIDE
Retrieves the scale factor of the window.
Definition Swnd.cpp:3266
BOOL IsMsgHandled() const
Checks if the message is handled.
Definition Swnd.cpp:207
COLORREF GetColorizeColor() SCONST OVERRIDE
Retrieves the colorization color of the window.
Definition Swnd.cpp:3166
BOOL IsVisible(BOOL bCheckParent=FALSE) SCONST OVERRIDE
Checks if the window is visible.
Definition Swnd.cpp:646
ISwndContainer * GetContainer() OVERRIDE
Retrieves the container associated with this window.
Definition Swnd.cpp:679
virtual CRect GetClientRect() const
Retrieves the client rectangle of the window.
Definition Swnd.cpp:243
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
SWindow()
Constructor.
Definition Swnd.cpp:104
virtual void AfterPaint(IRenderTarget *pRT, SPainter &painter)
Restore rendering environment.
Definition Swnd.cpp:1776
ILayoutParam * GetLayoutParam() SCONST OVERRIDE
Retrieves the layout parameter object associated with the window.
Definition SWnd.h:405
void Invalidate() OVERRIDE
Invalidates the entire window.
Definition Swnd.cpp:1437
void SetMsgHandled(BOOL bHandled)
Sets the message handled flag.
Definition Swnd.cpp:212
const SwndStyle & GetStyle() const
Retrieves the style of the window.
Definition Swnd.cpp:716
SWND m_swnd
Member variables representing various properties of the window.
Definition SWnd.h:2577
const wchar_t * as_string(const wchar_t *def=L"") const
Gets the attribute value as a string.
Definition SXml.cpp:95
const wchar_t * value() const
Gets the attribute value.
Definition SXml.cpp:90
Class representing an XML node.
Definition SXml.h:352
SXmlNode first_child() const
Gets the first child node of the node.
Definition SXml.cpp:383
SXmlAttr attribute(const wchar_t *name, bool bCaseSensitive=false) const
Gets the attribute with the specified name.
Definition SXml.cpp:428
SXmlNode root() const
Gets the root node of the DOM tree this node belongs to.
Definition SXml.cpp:418
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
SFocusManager * GetFocusManager()
Retrieves the focus manager.
CRect GetPadding() const
Retrieves the padding rectangle.
Template class implementing the IObjRef interface.
Interface for rendering target objects.
Definition SRender-i.h:1440
HRESULT GetTransform(float matrix[9]) SCONST PURE
Retrieves the current coordinate transformation matrix.
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 GetClipBox(LPRECT prc) PURE
Get the bounding box of the current clip region.
HRESULT GetClipRegion(IRegionS **ppRegion) PURE
Get the current clip region.
BOOL OnReleaseSwndCapture() PURE
Releases the mouse capture from the Swnd object.
SWND OnSetSwndCapture(SWND swnd) PURE
Sets the Swnd object to capture the mouse.
Information for window tooltips.
Definition SWnd.h:208