• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "fpdfsdk/fxedit/fxet_list.h"
8 
9 #include "core/fpdfdoc/cpvt_word.h"
10 #include "fpdfsdk/fxedit/fxet_edit.h"
11 #include "fpdfsdk/pdfwindow/PWL_ListBox.h"
12 
CFX_ListItem()13 CFX_ListItem::CFX_ListItem()
14     : m_pEdit(new CFX_Edit),
15       m_bSelected(false),
16       m_rcListItem(0.0f, 0.0f, 0.0f, 0.0f) {
17   m_pEdit->SetAlignmentV(1, true);
18   m_pEdit->Initialize();
19 }
20 
~CFX_ListItem()21 CFX_ListItem::~CFX_ListItem() {
22 }
23 
SetFontMap(IPVT_FontMap * pFontMap)24 void CFX_ListItem::SetFontMap(IPVT_FontMap* pFontMap) {
25   m_pEdit->SetFontMap(pFontMap);
26 }
27 
GetEdit() const28 CFX_Edit* CFX_ListItem::GetEdit() const {
29   return m_pEdit.get();
30 }
31 
GetIterator() const32 CFX_Edit_Iterator* CFX_ListItem::GetIterator() const {
33   return m_pEdit->GetIterator();
34 }
35 
SetRect(const CLST_Rect & rect)36 void CFX_ListItem::SetRect(const CLST_Rect& rect) {
37   m_rcListItem = rect;
38 }
39 
GetRect() const40 CLST_Rect CFX_ListItem::GetRect() const {
41   return m_rcListItem;
42 }
43 
IsSelected() const44 bool CFX_ListItem::IsSelected() const {
45   return m_bSelected;
46 }
47 
SetSelect(bool bSelected)48 void CFX_ListItem::SetSelect(bool bSelected) {
49   m_bSelected = bSelected;
50 }
51 
SetText(const CFX_WideString & text)52 void CFX_ListItem::SetText(const CFX_WideString& text) {
53   m_pEdit->SetText(text);
54 }
55 
SetFontSize(FX_FLOAT fFontSize)56 void CFX_ListItem::SetFontSize(FX_FLOAT fFontSize) {
57   m_pEdit->SetFontSize(fFontSize);
58 }
59 
GetItemHeight() const60 FX_FLOAT CFX_ListItem::GetItemHeight() const {
61   return m_pEdit->GetContentRect().Height();
62 }
63 
GetFirstChar() const64 uint16_t CFX_ListItem::GetFirstChar() const {
65   CPVT_Word word;
66   CFX_Edit_Iterator* pIterator = GetIterator();
67   pIterator->SetAt(1);
68   pIterator->GetWord(word);
69   return word.Word;
70 }
71 
GetText() const72 CFX_WideString CFX_ListItem::GetText() const {
73   return m_pEdit->GetText();
74 }
75 
CFX_ListContainer()76 CFX_ListContainer::CFX_ListContainer() {}
77 
~CFX_ListContainer()78 CFX_ListContainer::~CFX_ListContainer() {}
79 
SetPlateRect(const CFX_FloatRect & rect)80 void CFX_ListContainer::SetPlateRect(const CFX_FloatRect& rect) {
81   m_rcPlate = rect;
82 }
83 
CPLST_Select()84 CPLST_Select::CPLST_Select() {}
85 
~CPLST_Select()86 CPLST_Select::~CPLST_Select() {
87   for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++)
88     delete m_aItems.GetAt(i);
89 
90   m_aItems.RemoveAll();
91 }
92 
Add(int32_t nItemIndex)93 void CPLST_Select::Add(int32_t nItemIndex) {
94   int32_t nIndex = Find(nItemIndex);
95 
96   if (nIndex < 0) {
97     m_aItems.Add(new CPLST_Select_Item(nItemIndex, 1));
98   } else {
99     if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex)) {
100       pItem->nState = 1;
101     }
102   }
103 }
104 
Add(int32_t nBeginIndex,int32_t nEndIndex)105 void CPLST_Select::Add(int32_t nBeginIndex, int32_t nEndIndex) {
106   if (nBeginIndex > nEndIndex) {
107     int32_t nTemp = nEndIndex;
108     nEndIndex = nBeginIndex;
109     nBeginIndex = nTemp;
110   }
111 
112   for (int32_t i = nBeginIndex; i <= nEndIndex; i++)
113     Add(i);
114 }
115 
Sub(int32_t nItemIndex)116 void CPLST_Select::Sub(int32_t nItemIndex) {
117   for (int32_t i = m_aItems.GetSize() - 1; i >= 0; i--) {
118     if (CPLST_Select_Item* pItem = m_aItems.GetAt(i))
119       if (pItem->nItemIndex == nItemIndex)
120         pItem->nState = -1;
121   }
122 }
123 
Sub(int32_t nBeginIndex,int32_t nEndIndex)124 void CPLST_Select::Sub(int32_t nBeginIndex, int32_t nEndIndex) {
125   if (nBeginIndex > nEndIndex) {
126     int32_t nTemp = nEndIndex;
127     nEndIndex = nBeginIndex;
128     nBeginIndex = nTemp;
129   }
130 
131   for (int32_t i = nBeginIndex; i <= nEndIndex; i++)
132     Sub(i);
133 }
134 
Find(int32_t nItemIndex) const135 int32_t CPLST_Select::Find(int32_t nItemIndex) const {
136   for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++) {
137     if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
138       if (pItem->nItemIndex == nItemIndex)
139         return i;
140     }
141   }
142 
143   return -1;
144 }
145 
IsExist(int32_t nItemIndex) const146 bool CPLST_Select::IsExist(int32_t nItemIndex) const {
147   return Find(nItemIndex) >= 0;
148 }
149 
GetCount() const150 int32_t CPLST_Select::GetCount() const {
151   return m_aItems.GetSize();
152 }
153 
GetItemIndex(int32_t nIndex) const154 int32_t CPLST_Select::GetItemIndex(int32_t nIndex) const {
155   if (nIndex >= 0 && nIndex < m_aItems.GetSize())
156     if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex))
157       return pItem->nItemIndex;
158 
159   return -1;
160 }
161 
GetState(int32_t nIndex) const162 int32_t CPLST_Select::GetState(int32_t nIndex) const {
163   if (nIndex >= 0 && nIndex < m_aItems.GetSize())
164     if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex))
165       return pItem->nState;
166 
167   return 0;
168 }
169 
DeselectAll()170 void CPLST_Select::DeselectAll() {
171   for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++) {
172     if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
173       pItem->nState = -1;
174     }
175   }
176 }
177 
Done()178 void CPLST_Select::Done() {
179   for (int32_t i = m_aItems.GetSize() - 1; i >= 0; i--) {
180     if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
181       if (pItem->nState == -1) {
182         delete pItem;
183         m_aItems.RemoveAt(i);
184       } else {
185         pItem->nState = 0;
186       }
187     }
188   }
189 }
190 
CFX_ListCtrl()191 CFX_ListCtrl::CFX_ListCtrl()
192     : m_pNotify(nullptr),
193       m_bNotifyFlag(false),
194       m_nSelItem(-1),
195       m_nFootIndex(-1),
196       m_bCtrlSel(false),
197       m_nCaretIndex(-1),
198       m_fFontSize(0.0f),
199       m_pFontMap(nullptr),
200       m_bMultiple(false) {}
201 
~CFX_ListCtrl()202 CFX_ListCtrl::~CFX_ListCtrl() {
203   Empty();
204 }
205 
SetNotify(CPWL_List_Notify * pNotify)206 void CFX_ListCtrl::SetNotify(CPWL_List_Notify* pNotify) {
207   m_pNotify = pNotify;
208 }
209 
InToOut(const CFX_PointF & point) const210 CFX_PointF CFX_ListCtrl::InToOut(const CFX_PointF& point) const {
211   CFX_FloatRect rcPlate = GetPlateRect();
212   return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
213                     point.y - (m_ptScrollPos.y - rcPlate.top));
214 }
215 
OutToIn(const CFX_PointF & point) const216 CFX_PointF CFX_ListCtrl::OutToIn(const CFX_PointF& point) const {
217   CFX_FloatRect rcPlate = GetPlateRect();
218   return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left),
219                     point.y + (m_ptScrollPos.y - rcPlate.top));
220 }
221 
InToOut(const CFX_FloatRect & rect) const222 CFX_FloatRect CFX_ListCtrl::InToOut(const CFX_FloatRect& rect) const {
223   CFX_PointF ptLeftBottom = InToOut(CFX_PointF(rect.left, rect.bottom));
224   CFX_PointF ptRightTop = InToOut(CFX_PointF(rect.right, rect.top));
225   return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
226                        ptRightTop.y);
227 }
228 
OutToIn(const CFX_FloatRect & rect) const229 CFX_FloatRect CFX_ListCtrl::OutToIn(const CFX_FloatRect& rect) const {
230   CFX_PointF ptLeftBottom = OutToIn(CFX_PointF(rect.left, rect.bottom));
231   CFX_PointF ptRightTop = OutToIn(CFX_PointF(rect.right, rect.top));
232   return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
233                        ptRightTop.y);
234 }
235 
OnMouseDown(const CFX_PointF & point,bool bShift,bool bCtrl)236 void CFX_ListCtrl::OnMouseDown(const CFX_PointF& point,
237                                bool bShift,
238                                bool bCtrl) {
239   int32_t nHitIndex = GetItemIndex(point);
240 
241   if (IsMultipleSel()) {
242     if (bCtrl) {
243       if (IsItemSelected(nHitIndex)) {
244         m_aSelItems.Sub(nHitIndex);
245         SelectItems();
246         m_bCtrlSel = false;
247       } else {
248         m_aSelItems.Add(nHitIndex);
249         SelectItems();
250         m_bCtrlSel = true;
251       }
252 
253       m_nFootIndex = nHitIndex;
254     } else if (bShift) {
255       m_aSelItems.DeselectAll();
256       m_aSelItems.Add(m_nFootIndex, nHitIndex);
257       SelectItems();
258     } else {
259       m_aSelItems.DeselectAll();
260       m_aSelItems.Add(nHitIndex);
261       SelectItems();
262 
263       m_nFootIndex = nHitIndex;
264     }
265 
266     SetCaret(nHitIndex);
267   } else {
268     SetSingleSelect(nHitIndex);
269   }
270 
271   if (!IsItemVisible(nHitIndex))
272     ScrollToListItem(nHitIndex);
273 }
274 
OnMouseMove(const CFX_PointF & point,bool bShift,bool bCtrl)275 void CFX_ListCtrl::OnMouseMove(const CFX_PointF& point,
276                                bool bShift,
277                                bool bCtrl) {
278   int32_t nHitIndex = GetItemIndex(point);
279 
280   if (IsMultipleSel()) {
281     if (bCtrl) {
282       if (m_bCtrlSel)
283         m_aSelItems.Add(m_nFootIndex, nHitIndex);
284       else
285         m_aSelItems.Sub(m_nFootIndex, nHitIndex);
286 
287       SelectItems();
288     } else {
289       m_aSelItems.DeselectAll();
290       m_aSelItems.Add(m_nFootIndex, nHitIndex);
291       SelectItems();
292     }
293 
294     SetCaret(nHitIndex);
295   } else {
296     SetSingleSelect(nHitIndex);
297   }
298 
299   if (!IsItemVisible(nHitIndex))
300     ScrollToListItem(nHitIndex);
301 }
302 
OnVK(int32_t nItemIndex,bool bShift,bool bCtrl)303 void CFX_ListCtrl::OnVK(int32_t nItemIndex, bool bShift, bool bCtrl) {
304   if (IsMultipleSel()) {
305     if (nItemIndex >= 0 && nItemIndex < GetCount()) {
306       if (bCtrl) {
307       } else if (bShift) {
308         m_aSelItems.DeselectAll();
309         m_aSelItems.Add(m_nFootIndex, nItemIndex);
310         SelectItems();
311       } else {
312         m_aSelItems.DeselectAll();
313         m_aSelItems.Add(nItemIndex);
314         SelectItems();
315         m_nFootIndex = nItemIndex;
316       }
317 
318       SetCaret(nItemIndex);
319     }
320   } else {
321     SetSingleSelect(nItemIndex);
322   }
323 
324   if (!IsItemVisible(nItemIndex))
325     ScrollToListItem(nItemIndex);
326 }
327 
OnVK_UP(bool bShift,bool bCtrl)328 void CFX_ListCtrl::OnVK_UP(bool bShift, bool bCtrl) {
329   OnVK(IsMultipleSel() ? GetCaret() - 1 : GetSelect() - 1, bShift, bCtrl);
330 }
331 
OnVK_DOWN(bool bShift,bool bCtrl)332 void CFX_ListCtrl::OnVK_DOWN(bool bShift, bool bCtrl) {
333   OnVK(IsMultipleSel() ? GetCaret() + 1 : GetSelect() + 1, bShift, bCtrl);
334 }
335 
OnVK_LEFT(bool bShift,bool bCtrl)336 void CFX_ListCtrl::OnVK_LEFT(bool bShift, bool bCtrl) {
337   OnVK(0, bShift, bCtrl);
338 }
339 
OnVK_RIGHT(bool bShift,bool bCtrl)340 void CFX_ListCtrl::OnVK_RIGHT(bool bShift, bool bCtrl) {
341   OnVK(GetCount() - 1, bShift, bCtrl);
342 }
343 
OnVK_HOME(bool bShift,bool bCtrl)344 void CFX_ListCtrl::OnVK_HOME(bool bShift, bool bCtrl) {
345   OnVK(0, bShift, bCtrl);
346 }
347 
OnVK_END(bool bShift,bool bCtrl)348 void CFX_ListCtrl::OnVK_END(bool bShift, bool bCtrl) {
349   OnVK(GetCount() - 1, bShift, bCtrl);
350 }
351 
OnChar(uint16_t nChar,bool bShift,bool bCtrl)352 bool CFX_ListCtrl::OnChar(uint16_t nChar, bool bShift, bool bCtrl) {
353   int32_t nIndex = GetLastSelected();
354   int32_t nFindIndex = FindNext(nIndex, nChar);
355 
356   if (nFindIndex != nIndex) {
357     OnVK(nFindIndex, bShift, bCtrl);
358     return true;
359   }
360   return false;
361 }
362 
SetPlateRect(const CFX_FloatRect & rect)363 void CFX_ListCtrl::SetPlateRect(const CFX_FloatRect& rect) {
364   CFX_ListContainer::SetPlateRect(rect);
365   m_ptScrollPos.x = rect.left;
366   SetScrollPos(CFX_PointF(rect.left, rect.top));
367   ReArrange(0);
368   InvalidateItem(-1);
369 }
370 
GetItemRect(int32_t nIndex) const371 CFX_FloatRect CFX_ListCtrl::GetItemRect(int32_t nIndex) const {
372   return InToOut(GetItemRectInternal(nIndex));
373 }
374 
GetItemRectInternal(int32_t nIndex) const375 CFX_FloatRect CFX_ListCtrl::GetItemRectInternal(int32_t nIndex) const {
376   if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
377     CFX_FloatRect rcItem = pListItem->GetRect();
378     rcItem.left = 0.0f;
379     rcItem.right = GetPlateRect().Width();
380     return InnerToOuter(CLST_Rect(rcItem));
381   }
382 
383   return CFX_FloatRect();
384 }
385 
GetCaret() const386 int32_t CFX_ListCtrl::GetCaret() const {
387   return m_nCaretIndex;
388 }
389 
GetSelect() const390 int32_t CFX_ListCtrl::GetSelect() const {
391   return m_nSelItem;
392 }
393 
AddString(const CFX_WideString & str)394 void CFX_ListCtrl::AddString(const CFX_WideString& str) {
395   AddItem(str);
396   ReArrange(GetCount() - 1);
397 }
398 
SetMultipleSelect(int32_t nItemIndex,bool bSelected)399 void CFX_ListCtrl::SetMultipleSelect(int32_t nItemIndex, bool bSelected) {
400   if (!IsValid(nItemIndex))
401     return;
402 
403   if (bSelected != IsItemSelected(nItemIndex)) {
404     if (bSelected) {
405       SetItemSelect(nItemIndex, true);
406       InvalidateItem(nItemIndex);
407     } else {
408       SetItemSelect(nItemIndex, false);
409       InvalidateItem(nItemIndex);
410     }
411   }
412 }
413 
SetSingleSelect(int32_t nItemIndex)414 void CFX_ListCtrl::SetSingleSelect(int32_t nItemIndex) {
415   if (!IsValid(nItemIndex))
416     return;
417 
418   if (m_nSelItem != nItemIndex) {
419     if (m_nSelItem >= 0) {
420       SetItemSelect(m_nSelItem, false);
421       InvalidateItem(m_nSelItem);
422     }
423 
424     SetItemSelect(nItemIndex, true);
425     InvalidateItem(nItemIndex);
426     m_nSelItem = nItemIndex;
427   }
428 }
429 
SetCaret(int32_t nItemIndex)430 void CFX_ListCtrl::SetCaret(int32_t nItemIndex) {
431   if (!IsValid(nItemIndex))
432     return;
433 
434   if (IsMultipleSel()) {
435     int32_t nOldIndex = m_nCaretIndex;
436 
437     if (nOldIndex != nItemIndex) {
438       m_nCaretIndex = nItemIndex;
439       InvalidateItem(nOldIndex);
440       InvalidateItem(nItemIndex);
441     }
442   }
443 }
444 
InvalidateItem(int32_t nItemIndex)445 void CFX_ListCtrl::InvalidateItem(int32_t nItemIndex) {
446   if (m_pNotify) {
447     if (nItemIndex == -1) {
448       if (!m_bNotifyFlag) {
449         m_bNotifyFlag = true;
450         CFX_FloatRect rcRefresh = GetPlateRect();
451         m_pNotify->IOnInvalidateRect(&rcRefresh);
452         m_bNotifyFlag = false;
453       }
454     } else {
455       if (!m_bNotifyFlag) {
456         m_bNotifyFlag = true;
457         CFX_FloatRect rcRefresh = GetItemRect(nItemIndex);
458         rcRefresh.left -= 1.0f;
459         rcRefresh.right += 1.0f;
460         rcRefresh.bottom -= 1.0f;
461         rcRefresh.top += 1.0f;
462 
463         m_pNotify->IOnInvalidateRect(&rcRefresh);
464         m_bNotifyFlag = false;
465       }
466     }
467   }
468 }
469 
SelectItems()470 void CFX_ListCtrl::SelectItems() {
471   for (int32_t i = 0, sz = m_aSelItems.GetCount(); i < sz; i++) {
472     int32_t nItemIndex = m_aSelItems.GetItemIndex(i);
473     int32_t nState = m_aSelItems.GetState(i);
474 
475     switch (nState) {
476       case 1:
477         SetMultipleSelect(nItemIndex, true);
478         break;
479       case -1:
480         SetMultipleSelect(nItemIndex, false);
481         break;
482     }
483   }
484 
485   m_aSelItems.Done();
486 }
487 
Select(int32_t nItemIndex)488 void CFX_ListCtrl::Select(int32_t nItemIndex) {
489   if (!IsValid(nItemIndex))
490     return;
491 
492   if (IsMultipleSel()) {
493     m_aSelItems.Add(nItemIndex);
494     SelectItems();
495   } else {
496     SetSingleSelect(nItemIndex);
497   }
498 }
499 
IsItemVisible(int32_t nItemIndex) const500 bool CFX_ListCtrl::IsItemVisible(int32_t nItemIndex) const {
501   CFX_FloatRect rcPlate = GetPlateRect();
502   CFX_FloatRect rcItem = GetItemRect(nItemIndex);
503 
504   return rcItem.bottom >= rcPlate.bottom && rcItem.top <= rcPlate.top;
505 }
506 
ScrollToListItem(int32_t nItemIndex)507 void CFX_ListCtrl::ScrollToListItem(int32_t nItemIndex) {
508   if (!IsValid(nItemIndex))
509     return;
510 
511   CFX_FloatRect rcPlate = GetPlateRect();
512   CFX_FloatRect rcItem = GetItemRectInternal(nItemIndex);
513   CFX_FloatRect rcItemCtrl = GetItemRect(nItemIndex);
514 
515   if (IsFloatSmaller(rcItemCtrl.bottom, rcPlate.bottom)) {
516     if (IsFloatSmaller(rcItemCtrl.top, rcPlate.top)) {
517       SetScrollPosY(rcItem.bottom + rcPlate.Height());
518     }
519   } else if (IsFloatBigger(rcItemCtrl.top, rcPlate.top)) {
520     if (IsFloatBigger(rcItemCtrl.bottom, rcPlate.bottom)) {
521       SetScrollPosY(rcItem.top);
522     }
523   }
524 }
525 
SetScrollInfo()526 void CFX_ListCtrl::SetScrollInfo() {
527   if (m_pNotify) {
528     CFX_FloatRect rcPlate = GetPlateRect();
529     CFX_FloatRect rcContent = GetContentRectInternal();
530 
531     if (!m_bNotifyFlag) {
532       m_bNotifyFlag = true;
533       m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top,
534                                    rcContent.bottom, rcContent.top,
535                                    GetFirstHeight(), rcPlate.Height());
536       m_bNotifyFlag = false;
537     }
538   }
539 }
540 
SetScrollPos(const CFX_PointF & point)541 void CFX_ListCtrl::SetScrollPos(const CFX_PointF& point) {
542   SetScrollPosY(point.y);
543 }
544 
SetScrollPosY(FX_FLOAT fy)545 void CFX_ListCtrl::SetScrollPosY(FX_FLOAT fy) {
546   if (!IsFloatEqual(m_ptScrollPos.y, fy)) {
547     CFX_FloatRect rcPlate = GetPlateRect();
548     CFX_FloatRect rcContent = GetContentRectInternal();
549 
550     if (rcPlate.Height() > rcContent.Height()) {
551       fy = rcPlate.top;
552     } else {
553       if (IsFloatSmaller(fy - rcPlate.Height(), rcContent.bottom)) {
554         fy = rcContent.bottom + rcPlate.Height();
555       } else if (IsFloatBigger(fy, rcContent.top)) {
556         fy = rcContent.top;
557       }
558     }
559 
560     m_ptScrollPos.y = fy;
561     InvalidateItem(-1);
562 
563     if (m_pNotify) {
564       if (!m_bNotifyFlag) {
565         m_bNotifyFlag = true;
566         m_pNotify->IOnSetScrollPosY(fy);
567         m_bNotifyFlag = false;
568       }
569     }
570   }
571 }
572 
GetContentRectInternal() const573 CFX_FloatRect CFX_ListCtrl::GetContentRectInternal() const {
574   return InnerToOuter(CFX_ListContainer::GetContentRect());
575 }
576 
GetContentRect() const577 CFX_FloatRect CFX_ListCtrl::GetContentRect() const {
578   return InToOut(GetContentRectInternal());
579 }
580 
ReArrange(int32_t nItemIndex)581 void CFX_ListCtrl::ReArrange(int32_t nItemIndex) {
582   FX_FLOAT fPosY = 0.0f;
583 
584   if (CFX_ListItem* pPrevItem = m_aListItems.GetAt(nItemIndex - 1))
585     fPosY = pPrevItem->GetRect().bottom;
586 
587   for (int32_t i = nItemIndex, sz = m_aListItems.GetSize(); i < sz; i++) {
588     if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
589       FX_FLOAT fListItemHeight = pListItem->GetItemHeight();
590       pListItem->SetRect(CLST_Rect(0.0f, fPosY, 0.0f, fPosY + fListItemHeight));
591       fPosY += fListItemHeight;
592     }
593   }
594 
595   SetContentRect(CLST_Rect(0.0f, 0.0f, 0.0f, fPosY));
596   SetScrollInfo();
597 }
598 
SetTopItem(int32_t nIndex)599 void CFX_ListCtrl::SetTopItem(int32_t nIndex) {
600   if (IsValid(nIndex)) {
601     GetPlateRect();
602     CFX_FloatRect rcItem = GetItemRectInternal(nIndex);
603     SetScrollPosY(rcItem.top);
604   }
605 }
606 
GetTopItem() const607 int32_t CFX_ListCtrl::GetTopItem() const {
608   int32_t nItemIndex = GetItemIndex(GetBTPoint());
609 
610   if (!IsItemVisible(nItemIndex) && IsItemVisible(nItemIndex + 1))
611     nItemIndex += 1;
612 
613   return nItemIndex;
614 }
615 
Empty()616 void CFX_ListCtrl::Empty() {
617   for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++)
618     delete m_aListItems.GetAt(i);
619 
620   m_aListItems.RemoveAll();
621 
622   InvalidateItem(-1);
623 }
624 
Cancel()625 void CFX_ListCtrl::Cancel() {
626   m_aSelItems.DeselectAll();
627 }
628 
GetItemIndex(const CFX_PointF & point) const629 int32_t CFX_ListCtrl::GetItemIndex(const CFX_PointF& point) const {
630   CFX_PointF pt = OuterToInner(OutToIn(point));
631 
632   bool bFirst = true;
633   bool bLast = true;
634 
635   for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
636     if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
637       CLST_Rect rcListItem = pListItem->GetRect();
638 
639       if (IsFloatBigger(pt.y, rcListItem.top)) {
640         bFirst = false;
641       }
642 
643       if (IsFloatSmaller(pt.y, rcListItem.bottom)) {
644         bLast = false;
645       }
646 
647       if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom) {
648         return i;
649       }
650     }
651   }
652 
653   if (bFirst)
654     return 0;
655   if (bLast)
656     return m_aListItems.GetSize() - 1;
657 
658   return -1;
659 }
660 
GetText() const661 CFX_WideString CFX_ListCtrl::GetText() const {
662   if (IsMultipleSel())
663     return GetItemText(m_nCaretIndex);
664   return GetItemText(m_nSelItem);
665 }
666 
SetFontMap(IPVT_FontMap * pFontMap)667 void CFX_ListCtrl::SetFontMap(IPVT_FontMap* pFontMap) {
668   m_pFontMap = pFontMap;
669 }
670 
SetFontSize(FX_FLOAT fFontSize)671 void CFX_ListCtrl::SetFontSize(FX_FLOAT fFontSize) {
672   m_fFontSize = fFontSize;
673 }
674 
AddItem(const CFX_WideString & str)675 void CFX_ListCtrl::AddItem(const CFX_WideString& str) {
676   CFX_ListItem* pListItem = new CFX_ListItem();
677   pListItem->SetFontMap(m_pFontMap);
678   pListItem->SetFontSize(m_fFontSize);
679   pListItem->SetText(str);
680   m_aListItems.Add(pListItem);
681 }
682 
GetItemEdit(int32_t nIndex) const683 CFX_Edit* CFX_ListCtrl::GetItemEdit(int32_t nIndex) const {
684   if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
685     return pListItem->GetEdit();
686   }
687 
688   return nullptr;
689 }
690 
GetCount() const691 int32_t CFX_ListCtrl::GetCount() const {
692   return m_aListItems.GetSize();
693 }
694 
GetPlateRect() const695 CFX_FloatRect CFX_ListCtrl::GetPlateRect() const {
696   return CFX_ListContainer::GetPlateRect();
697 }
698 
GetFontSize() const699 FX_FLOAT CFX_ListCtrl::GetFontSize() const {
700   return m_fFontSize;
701 }
702 
GetFirstHeight() const703 FX_FLOAT CFX_ListCtrl::GetFirstHeight() const {
704   if (CFX_ListItem* pListItem = m_aListItems.GetAt(0)) {
705     return pListItem->GetItemHeight();
706   }
707 
708   return 1.0f;
709 }
710 
GetFirstSelected() const711 int32_t CFX_ListCtrl::GetFirstSelected() const {
712   for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
713     if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
714       if (pListItem->IsSelected())
715         return i;
716     }
717   }
718   return -1;
719 }
720 
GetLastSelected() const721 int32_t CFX_ListCtrl::GetLastSelected() const {
722   for (int32_t i = m_aListItems.GetSize() - 1; i >= 0; i--) {
723     if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
724       if (pListItem->IsSelected())
725         return i;
726     }
727   }
728   return -1;
729 }
730 
Toupper(FX_WCHAR c) const731 FX_WCHAR CFX_ListCtrl::Toupper(FX_WCHAR c) const {
732   if ((c >= 'a') && (c <= 'z'))
733     c = c - ('a' - 'A');
734   return c;
735 }
736 
FindNext(int32_t nIndex,FX_WCHAR nChar) const737 int32_t CFX_ListCtrl::FindNext(int32_t nIndex, FX_WCHAR nChar) const {
738   int32_t nCircleIndex = nIndex;
739 
740   for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
741     nCircleIndex++;
742     if (nCircleIndex >= sz)
743       nCircleIndex = 0;
744 
745     if (CFX_ListItem* pListItem = m_aListItems.GetAt(nCircleIndex)) {
746       if (Toupper(pListItem->GetFirstChar()) == Toupper(nChar))
747         return nCircleIndex;
748     }
749   }
750 
751   return nCircleIndex;
752 }
753 
IsItemSelected(int32_t nIndex) const754 bool CFX_ListCtrl::IsItemSelected(int32_t nIndex) const {
755   if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex))
756     return pListItem->IsSelected();
757   return false;
758 }
759 
SetItemSelect(int32_t nItemIndex,bool bSelected)760 void CFX_ListCtrl::SetItemSelect(int32_t nItemIndex, bool bSelected) {
761   if (CFX_ListItem* pListItem = m_aListItems.GetAt(nItemIndex)) {
762     pListItem->SetSelect(bSelected);
763   }
764 }
765 
SetMultipleSel(bool bMultiple)766 void CFX_ListCtrl::SetMultipleSel(bool bMultiple) {
767   m_bMultiple = bMultiple;
768 }
769 
IsMultipleSel() const770 bool CFX_ListCtrl::IsMultipleSel() const {
771   return m_bMultiple;
772 }
773 
IsValid(int32_t nItemIndex) const774 bool CFX_ListCtrl::IsValid(int32_t nItemIndex) const {
775   return nItemIndex >= 0 && nItemIndex < m_aListItems.GetSize();
776 }
777 
GetItemText(int32_t nIndex) const778 CFX_WideString CFX_ListCtrl::GetItemText(int32_t nIndex) const {
779   if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
780     return pListItem->GetText();
781   }
782 
783   return L"";
784 }
785