• 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/pwl/cpwl_list_impl.h"
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "core/fpdfdoc/cpvt_word.h"
13 #include "core/fxcrt/fx_extension.h"
14 #include "fpdfsdk/pwl/cpwl_edit_impl.h"
15 #include "fpdfsdk/pwl/cpwl_list_box.h"
16 #include "third_party/base/stl_util.h"
17 
Item()18 CPWL_ListCtrl::Item::Item()
19     : m_pEdit(new CPWL_EditImpl),
20       m_bSelected(false),
21       m_rcListItem(0.0f, 0.0f, 0.0f, 0.0f) {
22   m_pEdit->SetAlignmentV(1, true);
23   m_pEdit->Initialize();
24 }
25 
~Item()26 CPWL_ListCtrl::Item::~Item() {}
27 
SetFontMap(IPVT_FontMap * pFontMap)28 void CPWL_ListCtrl::Item::SetFontMap(IPVT_FontMap* pFontMap) {
29   m_pEdit->SetFontMap(pFontMap);
30 }
31 
SetText(const WideString & text)32 void CPWL_ListCtrl::Item::SetText(const WideString& text) {
33   m_pEdit->SetText(text);
34 }
35 
SetFontSize(float fFontSize)36 void CPWL_ListCtrl::Item::SetFontSize(float fFontSize) {
37   m_pEdit->SetFontSize(fFontSize);
38 }
39 
GetItemHeight() const40 float CPWL_ListCtrl::Item::GetItemHeight() const {
41   return m_pEdit->GetContentRect().Height();
42 }
43 
GetFirstChar() const44 uint16_t CPWL_ListCtrl::Item::GetFirstChar() const {
45   CPVT_Word word;
46   CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator();
47   pIterator->SetAt(1);
48   pIterator->GetWord(word);
49   return word.Word;
50 }
51 
GetText() const52 WideString CPWL_ListCtrl::Item::GetText() const {
53   return m_pEdit->GetText();
54 }
55 
CPLST_Select()56 CPLST_Select::CPLST_Select() {}
57 
~CPLST_Select()58 CPLST_Select::~CPLST_Select() {}
59 
Add(int32_t nItemIndex)60 void CPLST_Select::Add(int32_t nItemIndex) {
61   m_Items[nItemIndex] = SELECTING;
62 }
63 
Add(int32_t nBeginIndex,int32_t nEndIndex)64 void CPLST_Select::Add(int32_t nBeginIndex, int32_t nEndIndex) {
65   if (nBeginIndex > nEndIndex)
66     std::swap(nBeginIndex, nEndIndex);
67 
68   for (int32_t i = nBeginIndex; i <= nEndIndex; ++i)
69     Add(i);
70 }
71 
Sub(int32_t nItemIndex)72 void CPLST_Select::Sub(int32_t nItemIndex) {
73   auto it = m_Items.find(nItemIndex);
74   if (it != m_Items.end())
75     it->second = DESELECTING;
76 }
77 
Sub(int32_t nBeginIndex,int32_t nEndIndex)78 void CPLST_Select::Sub(int32_t nBeginIndex, int32_t nEndIndex) {
79   if (nBeginIndex > nEndIndex)
80     std::swap(nBeginIndex, nEndIndex);
81 
82   for (int32_t i = nBeginIndex; i <= nEndIndex; ++i)
83     Sub(i);
84 }
85 
DeselectAll()86 void CPLST_Select::DeselectAll() {
87   for (auto& item : m_Items)
88     item.second = DESELECTING;
89 }
90 
Done()91 void CPLST_Select::Done() {
92   auto it = m_Items.begin();
93   while (it != m_Items.end()) {
94     if (it->second == DESELECTING)
95       it = m_Items.erase(it);
96     else
97       (it++)->second = NORMAL;
98   }
99 }
100 
CPWL_ListCtrl()101 CPWL_ListCtrl::CPWL_ListCtrl()
102     : m_pNotify(nullptr),
103       m_bNotifyFlag(false),
104       m_nSelItem(-1),
105       m_nFootIndex(-1),
106       m_bCtrlSel(false),
107       m_nCaretIndex(-1),
108       m_fFontSize(0.0f),
109       m_pFontMap(nullptr),
110       m_bMultiple(false) {}
111 
~CPWL_ListCtrl()112 CPWL_ListCtrl::~CPWL_ListCtrl() {
113   Empty();
114 }
115 
InToOut(const CFX_PointF & point) const116 CFX_PointF CPWL_ListCtrl::InToOut(const CFX_PointF& point) const {
117   CFX_FloatRect rcPlate = m_rcPlate;
118   return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
119                     point.y - (m_ptScrollPos.y - rcPlate.top));
120 }
121 
OutToIn(const CFX_PointF & point) const122 CFX_PointF CPWL_ListCtrl::OutToIn(const CFX_PointF& point) const {
123   CFX_FloatRect rcPlate = m_rcPlate;
124   return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left),
125                     point.y + (m_ptScrollPos.y - rcPlate.top));
126 }
127 
InToOut(const CFX_FloatRect & rect) const128 CFX_FloatRect CPWL_ListCtrl::InToOut(const CFX_FloatRect& rect) const {
129   CFX_PointF ptLeftBottom = InToOut(CFX_PointF(rect.left, rect.bottom));
130   CFX_PointF ptRightTop = InToOut(CFX_PointF(rect.right, rect.top));
131   return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
132                        ptRightTop.y);
133 }
134 
OutToIn(const CFX_FloatRect & rect) const135 CFX_FloatRect CPWL_ListCtrl::OutToIn(const CFX_FloatRect& rect) const {
136   CFX_PointF ptLeftBottom = OutToIn(CFX_PointF(rect.left, rect.bottom));
137   CFX_PointF ptRightTop = OutToIn(CFX_PointF(rect.right, rect.top));
138   return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
139                        ptRightTop.y);
140 }
141 
InnerToOuter(const CFX_PointF & point) const142 CFX_PointF CPWL_ListCtrl::InnerToOuter(const CFX_PointF& point) const {
143   return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y);
144 }
145 
OuterToInner(const CFX_PointF & point) const146 CFX_PointF CPWL_ListCtrl::OuterToInner(const CFX_PointF& point) const {
147   return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y);
148 }
149 
InnerToOuter(const CFX_FloatRect & rect) const150 CFX_FloatRect CPWL_ListCtrl::InnerToOuter(const CFX_FloatRect& rect) const {
151   CFX_PointF ptLeftTop = InnerToOuter(CFX_PointF(rect.left, rect.top));
152   CFX_PointF ptRightBottom = InnerToOuter(CFX_PointF(rect.right, rect.bottom));
153   return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
154                        ptLeftTop.y);
155 }
156 
OuterToInner(const CFX_FloatRect & rect) const157 CFX_FloatRect CPWL_ListCtrl::OuterToInner(const CFX_FloatRect& rect) const {
158   CFX_PointF ptLeftTop = OuterToInner(CFX_PointF(rect.left, rect.top));
159   CFX_PointF ptRightBottom = OuterToInner(CFX_PointF(rect.right, rect.bottom));
160   return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
161                        ptLeftTop.y);
162 }
163 
OnMouseDown(const CFX_PointF & point,bool bShift,bool bCtrl)164 void CPWL_ListCtrl::OnMouseDown(const CFX_PointF& point,
165                                 bool bShift,
166                                 bool bCtrl) {
167   int32_t nHitIndex = GetItemIndex(point);
168 
169   if (IsMultipleSel()) {
170     if (bCtrl) {
171       if (IsItemSelected(nHitIndex)) {
172         m_aSelItems.Sub(nHitIndex);
173         SelectItems();
174         m_bCtrlSel = false;
175       } else {
176         m_aSelItems.Add(nHitIndex);
177         SelectItems();
178         m_bCtrlSel = true;
179       }
180 
181       m_nFootIndex = nHitIndex;
182     } else if (bShift) {
183       m_aSelItems.DeselectAll();
184       m_aSelItems.Add(m_nFootIndex, nHitIndex);
185       SelectItems();
186     } else {
187       m_aSelItems.DeselectAll();
188       m_aSelItems.Add(nHitIndex);
189       SelectItems();
190 
191       m_nFootIndex = nHitIndex;
192     }
193 
194     SetCaret(nHitIndex);
195   } else {
196     SetSingleSelect(nHitIndex);
197   }
198 
199   if (!IsItemVisible(nHitIndex))
200     ScrollToListItem(nHitIndex);
201 }
202 
OnMouseMove(const CFX_PointF & point,bool bShift,bool bCtrl)203 void CPWL_ListCtrl::OnMouseMove(const CFX_PointF& point,
204                                 bool bShift,
205                                 bool bCtrl) {
206   int32_t nHitIndex = GetItemIndex(point);
207 
208   if (IsMultipleSel()) {
209     if (bCtrl) {
210       if (m_bCtrlSel)
211         m_aSelItems.Add(m_nFootIndex, nHitIndex);
212       else
213         m_aSelItems.Sub(m_nFootIndex, nHitIndex);
214 
215       SelectItems();
216     } else {
217       m_aSelItems.DeselectAll();
218       m_aSelItems.Add(m_nFootIndex, nHitIndex);
219       SelectItems();
220     }
221 
222     SetCaret(nHitIndex);
223   } else {
224     SetSingleSelect(nHitIndex);
225   }
226 
227   if (!IsItemVisible(nHitIndex))
228     ScrollToListItem(nHitIndex);
229 }
230 
OnVK(int32_t nItemIndex,bool bShift,bool bCtrl)231 void CPWL_ListCtrl::OnVK(int32_t nItemIndex, bool bShift, bool bCtrl) {
232   if (IsMultipleSel()) {
233     if (nItemIndex >= 0 && nItemIndex < GetCount()) {
234       if (bCtrl) {
235       } else if (bShift) {
236         m_aSelItems.DeselectAll();
237         m_aSelItems.Add(m_nFootIndex, nItemIndex);
238         SelectItems();
239       } else {
240         m_aSelItems.DeselectAll();
241         m_aSelItems.Add(nItemIndex);
242         SelectItems();
243         m_nFootIndex = nItemIndex;
244       }
245 
246       SetCaret(nItemIndex);
247     }
248   } else {
249     SetSingleSelect(nItemIndex);
250   }
251 
252   if (!IsItemVisible(nItemIndex))
253     ScrollToListItem(nItemIndex);
254 }
255 
OnVK_UP(bool bShift,bool bCtrl)256 void CPWL_ListCtrl::OnVK_UP(bool bShift, bool bCtrl) {
257   OnVK(IsMultipleSel() ? GetCaret() - 1 : GetSelect() - 1, bShift, bCtrl);
258 }
259 
OnVK_DOWN(bool bShift,bool bCtrl)260 void CPWL_ListCtrl::OnVK_DOWN(bool bShift, bool bCtrl) {
261   OnVK(IsMultipleSel() ? GetCaret() + 1 : GetSelect() + 1, bShift, bCtrl);
262 }
263 
OnVK_LEFT(bool bShift,bool bCtrl)264 void CPWL_ListCtrl::OnVK_LEFT(bool bShift, bool bCtrl) {
265   OnVK(0, bShift, bCtrl);
266 }
267 
OnVK_RIGHT(bool bShift,bool bCtrl)268 void CPWL_ListCtrl::OnVK_RIGHT(bool bShift, bool bCtrl) {
269   OnVK(GetCount() - 1, bShift, bCtrl);
270 }
271 
OnVK_HOME(bool bShift,bool bCtrl)272 void CPWL_ListCtrl::OnVK_HOME(bool bShift, bool bCtrl) {
273   OnVK(0, bShift, bCtrl);
274 }
275 
OnVK_END(bool bShift,bool bCtrl)276 void CPWL_ListCtrl::OnVK_END(bool bShift, bool bCtrl) {
277   OnVK(GetCount() - 1, bShift, bCtrl);
278 }
279 
OnChar(uint16_t nChar,bool bShift,bool bCtrl)280 bool CPWL_ListCtrl::OnChar(uint16_t nChar, bool bShift, bool bCtrl) {
281   int32_t nIndex = GetLastSelected();
282   int32_t nFindIndex = FindNext(nIndex, nChar);
283 
284   if (nFindIndex != nIndex) {
285     OnVK(nFindIndex, bShift, bCtrl);
286     return true;
287   }
288   return false;
289 }
290 
SetPlateRect(const CFX_FloatRect & rect)291 void CPWL_ListCtrl::SetPlateRect(const CFX_FloatRect& rect) {
292   m_rcPlate = rect;
293   m_ptScrollPos.x = rect.left;
294   SetScrollPos(CFX_PointF(rect.left, rect.top));
295   ReArrange(0);
296   InvalidateItem(-1);
297 }
298 
GetItemRect(int32_t nIndex) const299 CFX_FloatRect CPWL_ListCtrl::GetItemRect(int32_t nIndex) const {
300   return InToOut(GetItemRectInternal(nIndex));
301 }
302 
GetItemRectInternal(int32_t nIndex) const303 CFX_FloatRect CPWL_ListCtrl::GetItemRectInternal(int32_t nIndex) const {
304   if (!pdfium::IndexInBounds(m_ListItems, nIndex) || !m_ListItems[nIndex])
305     return CFX_FloatRect();
306 
307   CFX_FloatRect rcItem = m_ListItems[nIndex]->GetRect();
308   rcItem.left = 0.0f;
309   rcItem.right = m_rcPlate.Width();
310   return InnerToOuter(rcItem);
311 }
312 
AddString(const WideString & str)313 void CPWL_ListCtrl::AddString(const WideString& str) {
314   AddItem(str);
315   ReArrange(GetCount() - 1);
316 }
317 
SetMultipleSelect(int32_t nItemIndex,bool bSelected)318 void CPWL_ListCtrl::SetMultipleSelect(int32_t nItemIndex, bool bSelected) {
319   if (!IsValid(nItemIndex))
320     return;
321 
322   if (bSelected != IsItemSelected(nItemIndex)) {
323     if (bSelected) {
324       SetItemSelect(nItemIndex, true);
325       InvalidateItem(nItemIndex);
326     } else {
327       SetItemSelect(nItemIndex, false);
328       InvalidateItem(nItemIndex);
329     }
330   }
331 }
332 
SetSingleSelect(int32_t nItemIndex)333 void CPWL_ListCtrl::SetSingleSelect(int32_t nItemIndex) {
334   if (!IsValid(nItemIndex))
335     return;
336 
337   if (m_nSelItem != nItemIndex) {
338     if (m_nSelItem >= 0) {
339       SetItemSelect(m_nSelItem, false);
340       InvalidateItem(m_nSelItem);
341     }
342 
343     SetItemSelect(nItemIndex, true);
344     InvalidateItem(nItemIndex);
345     m_nSelItem = nItemIndex;
346   }
347 }
348 
SetCaret(int32_t nItemIndex)349 void CPWL_ListCtrl::SetCaret(int32_t nItemIndex) {
350   if (!IsValid(nItemIndex))
351     return;
352 
353   if (IsMultipleSel()) {
354     int32_t nOldIndex = m_nCaretIndex;
355 
356     if (nOldIndex != nItemIndex) {
357       m_nCaretIndex = nItemIndex;
358       InvalidateItem(nOldIndex);
359       InvalidateItem(nItemIndex);
360     }
361   }
362 }
363 
InvalidateItem(int32_t nItemIndex)364 void CPWL_ListCtrl::InvalidateItem(int32_t nItemIndex) {
365   if (m_pNotify) {
366     if (nItemIndex == -1) {
367       if (!m_bNotifyFlag) {
368         m_bNotifyFlag = true;
369         CFX_FloatRect rcRefresh = m_rcPlate;
370         m_pNotify->IOnInvalidateRect(&rcRefresh);
371         m_bNotifyFlag = false;
372       }
373     } else {
374       if (!m_bNotifyFlag) {
375         m_bNotifyFlag = true;
376         CFX_FloatRect rcRefresh = GetItemRect(nItemIndex);
377         rcRefresh.left -= 1.0f;
378         rcRefresh.right += 1.0f;
379         rcRefresh.bottom -= 1.0f;
380         rcRefresh.top += 1.0f;
381 
382         m_pNotify->IOnInvalidateRect(&rcRefresh);
383         m_bNotifyFlag = false;
384       }
385     }
386   }
387 }
388 
SelectItems()389 void CPWL_ListCtrl::SelectItems() {
390   for (const auto& item : m_aSelItems) {
391     if (item.second != CPLST_Select::NORMAL)
392       SetMultipleSelect(item.first, item.second == CPLST_Select::SELECTING);
393   }
394   m_aSelItems.Done();
395 }
396 
Select(int32_t nItemIndex)397 void CPWL_ListCtrl::Select(int32_t nItemIndex) {
398   if (!IsValid(nItemIndex))
399     return;
400 
401   if (IsMultipleSel()) {
402     m_aSelItems.Add(nItemIndex);
403     SelectItems();
404   } else {
405     SetSingleSelect(nItemIndex);
406   }
407 }
408 
IsItemVisible(int32_t nItemIndex) const409 bool CPWL_ListCtrl::IsItemVisible(int32_t nItemIndex) const {
410   CFX_FloatRect rcPlate = m_rcPlate;
411   CFX_FloatRect rcItem = GetItemRect(nItemIndex);
412 
413   return rcItem.bottom >= rcPlate.bottom && rcItem.top <= rcPlate.top;
414 }
415 
ScrollToListItem(int32_t nItemIndex)416 void CPWL_ListCtrl::ScrollToListItem(int32_t nItemIndex) {
417   if (!IsValid(nItemIndex))
418     return;
419 
420   CFX_FloatRect rcPlate = m_rcPlate;
421   CFX_FloatRect rcItem = GetItemRectInternal(nItemIndex);
422   CFX_FloatRect rcItemCtrl = GetItemRect(nItemIndex);
423 
424   if (IsFloatSmaller(rcItemCtrl.bottom, rcPlate.bottom)) {
425     if (IsFloatSmaller(rcItemCtrl.top, rcPlate.top)) {
426       SetScrollPosY(rcItem.bottom + rcPlate.Height());
427     }
428   } else if (IsFloatBigger(rcItemCtrl.top, rcPlate.top)) {
429     if (IsFloatBigger(rcItemCtrl.bottom, rcPlate.bottom)) {
430       SetScrollPosY(rcItem.top);
431     }
432   }
433 }
434 
SetScrollInfo()435 void CPWL_ListCtrl::SetScrollInfo() {
436   if (m_pNotify) {
437     CFX_FloatRect rcPlate = m_rcPlate;
438     CFX_FloatRect rcContent = GetContentRectInternal();
439 
440     if (!m_bNotifyFlag) {
441       m_bNotifyFlag = true;
442       m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top,
443                                    rcContent.bottom, rcContent.top,
444                                    GetFirstHeight(), rcPlate.Height());
445       m_bNotifyFlag = false;
446     }
447   }
448 }
449 
SetScrollPos(const CFX_PointF & point)450 void CPWL_ListCtrl::SetScrollPos(const CFX_PointF& point) {
451   SetScrollPosY(point.y);
452 }
453 
SetScrollPosY(float fy)454 void CPWL_ListCtrl::SetScrollPosY(float fy) {
455   if (!IsFloatEqual(m_ptScrollPos.y, fy)) {
456     CFX_FloatRect rcPlate = m_rcPlate;
457     CFX_FloatRect rcContent = GetContentRectInternal();
458 
459     if (rcPlate.Height() > rcContent.Height()) {
460       fy = rcPlate.top;
461     } else {
462       if (IsFloatSmaller(fy - rcPlate.Height(), rcContent.bottom)) {
463         fy = rcContent.bottom + rcPlate.Height();
464       } else if (IsFloatBigger(fy, rcContent.top)) {
465         fy = rcContent.top;
466       }
467     }
468 
469     m_ptScrollPos.y = fy;
470     InvalidateItem(-1);
471 
472     if (m_pNotify) {
473       if (!m_bNotifyFlag) {
474         m_bNotifyFlag = true;
475         m_pNotify->IOnSetScrollPosY(fy);
476         m_bNotifyFlag = false;
477       }
478     }
479   }
480 }
481 
GetContentRectInternal() const482 CFX_FloatRect CPWL_ListCtrl::GetContentRectInternal() const {
483   return InnerToOuter(m_rcContent);
484 }
485 
GetContentRect() const486 CFX_FloatRect CPWL_ListCtrl::GetContentRect() const {
487   return InToOut(GetContentRectInternal());
488 }
489 
ReArrange(int32_t nItemIndex)490 void CPWL_ListCtrl::ReArrange(int32_t nItemIndex) {
491   float fPosY = 0.0f;
492   if (pdfium::IndexInBounds(m_ListItems, nItemIndex - 1) &&
493       m_ListItems[nItemIndex - 1]) {
494     fPosY = m_ListItems[nItemIndex - 1]->GetRect().bottom;
495   }
496   for (const auto& pListItem : m_ListItems) {
497     if (pListItem) {
498       float fListItemHeight = pListItem->GetItemHeight();
499       pListItem->SetRect(
500           CFX_FloatRect(0.0f, fPosY + fListItemHeight, 0.0f, fPosY));
501       fPosY += fListItemHeight;
502     }
503   }
504   SetContentRect(CFX_FloatRect(0.0f, fPosY, 0.0f, 0.0f));
505   SetScrollInfo();
506 }
507 
SetTopItem(int32_t nIndex)508 void CPWL_ListCtrl::SetTopItem(int32_t nIndex) {
509   if (IsValid(nIndex)) {
510     CFX_FloatRect rcItem = GetItemRectInternal(nIndex);
511     SetScrollPosY(rcItem.top);
512   }
513 }
514 
GetTopItem() const515 int32_t CPWL_ListCtrl::GetTopItem() const {
516   int32_t nItemIndex = GetItemIndex(GetBTPoint());
517   if (!IsItemVisible(nItemIndex) && IsItemVisible(nItemIndex + 1))
518     nItemIndex += 1;
519 
520   return nItemIndex;
521 }
522 
Empty()523 void CPWL_ListCtrl::Empty() {
524   m_ListItems.clear();
525   InvalidateItem(-1);
526 }
527 
Cancel()528 void CPWL_ListCtrl::Cancel() {
529   m_aSelItems.DeselectAll();
530 }
531 
GetItemIndex(const CFX_PointF & point) const532 int32_t CPWL_ListCtrl::GetItemIndex(const CFX_PointF& point) const {
533   CFX_PointF pt = OuterToInner(OutToIn(point));
534   bool bFirst = true;
535   bool bLast = true;
536   for (const auto& pListItem : m_ListItems) {
537     if (!pListItem)
538       continue;
539     CFX_FloatRect rcListItem = pListItem->GetRect();
540     if (IsFloatBigger(pt.y, rcListItem.top))
541       bFirst = false;
542     if (IsFloatSmaller(pt.y, rcListItem.bottom))
543       bLast = false;
544     if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom)
545       return &pListItem - &m_ListItems.front();
546   }
547   if (bFirst)
548     return 0;
549   if (bLast)
550     return pdfium::CollectionSize<int32_t>(m_ListItems) - 1;
551   return -1;
552 }
553 
GetText() const554 WideString CPWL_ListCtrl::GetText() const {
555   if (IsMultipleSel())
556     return GetItemText(m_nCaretIndex);
557   return GetItemText(m_nSelItem);
558 }
559 
AddItem(const WideString & str)560 void CPWL_ListCtrl::AddItem(const WideString& str) {
561   auto pListItem = pdfium::MakeUnique<Item>();
562   pListItem->SetFontMap(m_pFontMap.Get());
563   pListItem->SetFontSize(m_fFontSize);
564   pListItem->SetText(str);
565   m_ListItems.push_back(std::move(pListItem));
566 }
567 
GetItemEdit(int32_t nIndex) const568 CPWL_EditImpl* CPWL_ListCtrl::GetItemEdit(int32_t nIndex) const {
569   if (!pdfium::IndexInBounds(m_ListItems, nIndex) || !m_ListItems[nIndex])
570     return nullptr;
571   return m_ListItems[nIndex]->GetEdit();
572 }
573 
GetCount() const574 int32_t CPWL_ListCtrl::GetCount() const {
575   return pdfium::CollectionSize<int32_t>(m_ListItems);
576 }
577 
GetFirstHeight() const578 float CPWL_ListCtrl::GetFirstHeight() const {
579   if (m_ListItems.empty() || !m_ListItems.front())
580     return 1.0f;
581   return m_ListItems.front()->GetItemHeight();
582 }
583 
GetFirstSelected() const584 int32_t CPWL_ListCtrl::GetFirstSelected() const {
585   int32_t i = 0;
586   for (const auto& pListItem : m_ListItems) {
587     if (pListItem && pListItem->IsSelected())
588       return i;
589     ++i;
590   }
591   return -1;
592 }
593 
GetLastSelected() const594 int32_t CPWL_ListCtrl::GetLastSelected() const {
595   for (auto iter = m_ListItems.rbegin(); iter != m_ListItems.rend(); ++iter) {
596     if (*iter && (*iter)->IsSelected())
597       return &*iter - &m_ListItems.front();
598   }
599   return -1;
600 }
601 
FindNext(int32_t nIndex,wchar_t nChar) const602 int32_t CPWL_ListCtrl::FindNext(int32_t nIndex, wchar_t nChar) const {
603   int32_t nCircleIndex = nIndex;
604   int32_t sz = pdfium::CollectionSize<int32_t>(m_ListItems);
605   for (int32_t i = 0; i < sz; i++) {
606     nCircleIndex++;
607     if (nCircleIndex >= sz)
608       nCircleIndex = 0;
609 
610     if (Item* pListItem = m_ListItems[nCircleIndex].get()) {
611       if (FXSYS_toupper(pListItem->GetFirstChar()) == FXSYS_toupper(nChar))
612         return nCircleIndex;
613     }
614   }
615 
616   return nCircleIndex;
617 }
618 
IsItemSelected(int32_t nIndex) const619 bool CPWL_ListCtrl::IsItemSelected(int32_t nIndex) const {
620   return pdfium::IndexInBounds(m_ListItems, nIndex) && m_ListItems[nIndex] &&
621          m_ListItems[nIndex]->IsSelected();
622 }
623 
SetItemSelect(int32_t nIndex,bool bSelected)624 void CPWL_ListCtrl::SetItemSelect(int32_t nIndex, bool bSelected) {
625   if (pdfium::IndexInBounds(m_ListItems, nIndex) && m_ListItems[nIndex])
626     m_ListItems[nIndex]->SetSelect(bSelected);
627 }
628 
IsValid(int32_t nItemIndex) const629 bool CPWL_ListCtrl::IsValid(int32_t nItemIndex) const {
630   return pdfium::IndexInBounds(m_ListItems, nItemIndex);
631 }
632 
GetItemText(int32_t nIndex) const633 WideString CPWL_ListCtrl::GetItemText(int32_t nIndex) const {
634   if (pdfium::IndexInBounds(m_ListItems, nIndex) && m_ListItems[nIndex])
635     return m_ListItems[nIndex]->GetText();
636   return L"";
637 }
638