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