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