1 // Copyright 2014 The PDFium Authors
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_ctrl.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 "core/fxcrt/stl_util.h"
15 #include "fpdfsdk/pwl/cpwl_edit_impl.h"
16 #include "fpdfsdk/pwl/cpwl_list_box.h"
17 #include "third_party/base/numerics/safe_conversions.h"
18
19 CPWL_ListCtrl::NotifyIface::~NotifyIface() = default;
20
Item()21 CPWL_ListCtrl::Item::Item() : m_pEdit(std::make_unique<CPWL_EditImpl>()) {
22 m_pEdit->SetAlignmentV(1);
23 m_pEdit->Initialize();
24 }
25
26 CPWL_ListCtrl::Item::~Item() = default;
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 m_pEdit->Paint();
35 }
36
SetFontSize(float fFontSize)37 void CPWL_ListCtrl::Item::SetFontSize(float fFontSize) {
38 m_pEdit->SetFontSize(fFontSize);
39 m_pEdit->Paint();
40 }
41
GetItemHeight() const42 float CPWL_ListCtrl::Item::GetItemHeight() const {
43 return m_pEdit->GetContentRect().Height();
44 }
45
GetFirstChar() const46 uint16_t CPWL_ListCtrl::Item::GetFirstChar() const {
47 CPVT_Word word;
48 CPWL_EditImpl::Iterator* pIterator = m_pEdit->GetIterator();
49 pIterator->SetAt(1);
50 pIterator->GetWord(word);
51 return word.Word;
52 }
53
GetText() const54 WideString CPWL_ListCtrl::Item::GetText() const {
55 return m_pEdit->GetText();
56 }
57
58 CPWL_ListCtrl::SelectState::SelectState() = default;
59
60 CPWL_ListCtrl::SelectState::~SelectState() = default;
61
Add(int32_t nItemIndex)62 void CPWL_ListCtrl::SelectState::Add(int32_t nItemIndex) {
63 m_Items[nItemIndex] = SELECTING;
64 }
65
Add(int32_t nBeginIndex,int32_t nEndIndex)66 void CPWL_ListCtrl::SelectState::Add(int32_t nBeginIndex, int32_t nEndIndex) {
67 if (nBeginIndex > nEndIndex)
68 std::swap(nBeginIndex, nEndIndex);
69
70 for (int32_t i = nBeginIndex; i <= nEndIndex; ++i)
71 Add(i);
72 }
73
Sub(int32_t nItemIndex)74 void CPWL_ListCtrl::SelectState::Sub(int32_t nItemIndex) {
75 auto it = m_Items.find(nItemIndex);
76 if (it != m_Items.end())
77 it->second = DESELECTING;
78 }
79
Sub(int32_t nBeginIndex,int32_t nEndIndex)80 void CPWL_ListCtrl::SelectState::Sub(int32_t nBeginIndex, int32_t nEndIndex) {
81 if (nBeginIndex > nEndIndex)
82 std::swap(nBeginIndex, nEndIndex);
83
84 for (int32_t i = nBeginIndex; i <= nEndIndex; ++i)
85 Sub(i);
86 }
87
DeselectAll()88 void CPWL_ListCtrl::SelectState::DeselectAll() {
89 for (auto& item : m_Items)
90 item.second = DESELECTING;
91 }
92
Done()93 void CPWL_ListCtrl::SelectState::Done() {
94 auto it = m_Items.begin();
95 while (it != m_Items.end()) {
96 if (it->second == DESELECTING)
97 it = m_Items.erase(it);
98 else
99 (it++)->second = NORMAL;
100 }
101 }
102
103 CPWL_ListCtrl::CPWL_ListCtrl() = default;
104
~CPWL_ListCtrl()105 CPWL_ListCtrl::~CPWL_ListCtrl() {
106 m_ListItems.clear();
107 InvalidateItem(-1);
108 }
109
InToOut(const CFX_PointF & point) const110 CFX_PointF CPWL_ListCtrl::InToOut(const CFX_PointF& point) const {
111 CFX_FloatRect rcPlate = m_rcPlate;
112 return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
113 point.y - (m_ptScrollPos.y - rcPlate.top));
114 }
115
OutToIn(const CFX_PointF & point) const116 CFX_PointF CPWL_ListCtrl::OutToIn(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
InToOut(const CFX_FloatRect & rect) const122 CFX_FloatRect CPWL_ListCtrl::InToOut(const CFX_FloatRect& rect) const {
123 CFX_PointF ptLeftBottom = InToOut(CFX_PointF(rect.left, rect.bottom));
124 CFX_PointF ptRightTop = InToOut(CFX_PointF(rect.right, rect.top));
125 return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
126 ptRightTop.y);
127 }
128
OutToIn(const CFX_FloatRect & rect) const129 CFX_FloatRect CPWL_ListCtrl::OutToIn(const CFX_FloatRect& rect) const {
130 CFX_PointF ptLeftBottom = OutToIn(CFX_PointF(rect.left, rect.bottom));
131 CFX_PointF ptRightTop = OutToIn(CFX_PointF(rect.right, rect.top));
132 return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
133 ptRightTop.y);
134 }
135
InnerToOuter(const CFX_PointF & point) const136 CFX_PointF CPWL_ListCtrl::InnerToOuter(const CFX_PointF& point) const {
137 return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y);
138 }
139
OuterToInner(const CFX_PointF & point) const140 CFX_PointF CPWL_ListCtrl::OuterToInner(const CFX_PointF& point) const {
141 return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y);
142 }
143
InnerToOuter(const CFX_FloatRect & rect) const144 CFX_FloatRect CPWL_ListCtrl::InnerToOuter(const CFX_FloatRect& rect) const {
145 CFX_PointF ptLeftTop = InnerToOuter(CFX_PointF(rect.left, rect.top));
146 CFX_PointF ptRightBottom = InnerToOuter(CFX_PointF(rect.right, rect.bottom));
147 return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
148 ptLeftTop.y);
149 }
150
OuterToInner(const CFX_FloatRect & rect) const151 CFX_FloatRect CPWL_ListCtrl::OuterToInner(const CFX_FloatRect& rect) const {
152 CFX_PointF ptLeftTop = OuterToInner(CFX_PointF(rect.left, rect.top));
153 CFX_PointF ptRightBottom = OuterToInner(CFX_PointF(rect.right, rect.bottom));
154 return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
155 ptLeftTop.y);
156 }
157
OnMouseDown(const CFX_PointF & point,bool bShift,bool bCtrl)158 void CPWL_ListCtrl::OnMouseDown(const CFX_PointF& point,
159 bool bShift,
160 bool bCtrl) {
161 int32_t nHitIndex = GetItemIndex(point);
162
163 if (IsMultipleSel()) {
164 if (bCtrl) {
165 if (IsItemSelected(nHitIndex)) {
166 m_SelectState.Sub(nHitIndex);
167 SelectItems();
168 m_bCtrlSel = false;
169 } else {
170 m_SelectState.Add(nHitIndex);
171 SelectItems();
172 m_bCtrlSel = true;
173 }
174
175 m_nFootIndex = nHitIndex;
176 } else if (bShift) {
177 m_SelectState.DeselectAll();
178 m_SelectState.Add(m_nFootIndex, nHitIndex);
179 SelectItems();
180 } else {
181 m_SelectState.DeselectAll();
182 m_SelectState.Add(nHitIndex);
183 SelectItems();
184
185 m_nFootIndex = nHitIndex;
186 }
187
188 SetCaret(nHitIndex);
189 } else {
190 SetSingleSelect(nHitIndex);
191 }
192
193 if (!IsItemVisible(nHitIndex))
194 ScrollToListItem(nHitIndex);
195 }
196
OnMouseMove(const CFX_PointF & point,bool bShift,bool bCtrl)197 void CPWL_ListCtrl::OnMouseMove(const CFX_PointF& point,
198 bool bShift,
199 bool bCtrl) {
200 int32_t nHitIndex = GetItemIndex(point);
201
202 if (IsMultipleSel()) {
203 if (bCtrl) {
204 if (m_bCtrlSel)
205 m_SelectState.Add(m_nFootIndex, nHitIndex);
206 else
207 m_SelectState.Sub(m_nFootIndex, nHitIndex);
208
209 SelectItems();
210 } else {
211 m_SelectState.DeselectAll();
212 m_SelectState.Add(m_nFootIndex, nHitIndex);
213 SelectItems();
214 }
215
216 SetCaret(nHitIndex);
217 } else {
218 SetSingleSelect(nHitIndex);
219 }
220
221 if (!IsItemVisible(nHitIndex))
222 ScrollToListItem(nHitIndex);
223 }
224
OnVK(int32_t nItemIndex,bool bShift,bool bCtrl)225 void CPWL_ListCtrl::OnVK(int32_t nItemIndex, bool bShift, bool bCtrl) {
226 if (IsMultipleSel()) {
227 if (nItemIndex >= 0 && nItemIndex < GetCount()) {
228 if (bCtrl) {
229 } else if (bShift) {
230 m_SelectState.DeselectAll();
231 m_SelectState.Add(m_nFootIndex, nItemIndex);
232 SelectItems();
233 } else {
234 m_SelectState.DeselectAll();
235 m_SelectState.Add(nItemIndex);
236 SelectItems();
237 m_nFootIndex = nItemIndex;
238 }
239
240 SetCaret(nItemIndex);
241 }
242 } else {
243 SetSingleSelect(nItemIndex);
244 }
245
246 if (!IsItemVisible(nItemIndex))
247 ScrollToListItem(nItemIndex);
248 }
249
OnVK_UP(bool bShift,bool bCtrl)250 void CPWL_ListCtrl::OnVK_UP(bool bShift, bool bCtrl) {
251 OnVK(IsMultipleSel() ? GetCaret() - 1 : GetSelect() - 1, bShift, bCtrl);
252 }
253
OnVK_DOWN(bool bShift,bool bCtrl)254 void CPWL_ListCtrl::OnVK_DOWN(bool bShift, bool bCtrl) {
255 OnVK(IsMultipleSel() ? GetCaret() + 1 : GetSelect() + 1, bShift, bCtrl);
256 }
257
OnVK_LEFT(bool bShift,bool bCtrl)258 void CPWL_ListCtrl::OnVK_LEFT(bool bShift, bool bCtrl) {
259 OnVK(0, bShift, bCtrl);
260 }
261
OnVK_RIGHT(bool bShift,bool bCtrl)262 void CPWL_ListCtrl::OnVK_RIGHT(bool bShift, bool bCtrl) {
263 OnVK(GetCount() - 1, bShift, bCtrl);
264 }
265
OnVK_HOME(bool bShift,bool bCtrl)266 void CPWL_ListCtrl::OnVK_HOME(bool bShift, bool bCtrl) {
267 OnVK(0, bShift, bCtrl);
268 }
269
OnVK_END(bool bShift,bool bCtrl)270 void CPWL_ListCtrl::OnVK_END(bool bShift, bool bCtrl) {
271 OnVK(GetCount() - 1, bShift, bCtrl);
272 }
273
OnChar(uint16_t nChar,bool bShift,bool bCtrl)274 bool CPWL_ListCtrl::OnChar(uint16_t nChar, bool bShift, bool bCtrl) {
275 int32_t nIndex = GetLastSelected();
276 int32_t nFindIndex = FindNext(nIndex, nChar);
277
278 if (nFindIndex != nIndex) {
279 OnVK(nFindIndex, bShift, bCtrl);
280 return true;
281 }
282 return false;
283 }
284
SetPlateRect(const CFX_FloatRect & rect)285 void CPWL_ListCtrl::SetPlateRect(const CFX_FloatRect& rect) {
286 m_rcPlate = rect;
287 m_ptScrollPos.x = rect.left;
288 SetScrollPos(CFX_PointF(rect.left, rect.top));
289 ReArrange(0);
290 InvalidateItem(-1);
291 }
292
GetItemRect(int32_t nIndex) const293 CFX_FloatRect CPWL_ListCtrl::GetItemRect(int32_t nIndex) const {
294 return InToOut(GetItemRectInternal(nIndex));
295 }
296
GetItemRectInternal(int32_t nIndex) const297 CFX_FloatRect CPWL_ListCtrl::GetItemRectInternal(int32_t nIndex) const {
298 if (!IsValid(nIndex))
299 return CFX_FloatRect();
300
301 CFX_FloatRect rcItem = m_ListItems[nIndex]->GetRect();
302 rcItem.left = 0.0f;
303 rcItem.right = m_rcPlate.Width();
304 return InnerToOuter(rcItem);
305 }
306
AddString(const WideString & str)307 void CPWL_ListCtrl::AddString(const WideString& str) {
308 AddItem(str);
309 ReArrange(GetCount() - 1);
310 }
311
SetMultipleSelect(int32_t nItemIndex,bool bSelected)312 void CPWL_ListCtrl::SetMultipleSelect(int32_t nItemIndex, bool bSelected) {
313 if (!IsValid(nItemIndex))
314 return;
315
316 if (bSelected != IsItemSelected(nItemIndex)) {
317 if (bSelected) {
318 SetItemSelect(nItemIndex, true);
319 InvalidateItem(nItemIndex);
320 } else {
321 SetItemSelect(nItemIndex, false);
322 InvalidateItem(nItemIndex);
323 }
324 }
325 }
326
SetSingleSelect(int32_t nItemIndex)327 void CPWL_ListCtrl::SetSingleSelect(int32_t nItemIndex) {
328 if (!IsValid(nItemIndex))
329 return;
330
331 if (m_nSelItem != nItemIndex) {
332 if (m_nSelItem >= 0) {
333 SetItemSelect(m_nSelItem, false);
334 InvalidateItem(m_nSelItem);
335 }
336
337 SetItemSelect(nItemIndex, true);
338 InvalidateItem(nItemIndex);
339 m_nSelItem = nItemIndex;
340 }
341 }
342
SetCaret(int32_t nItemIndex)343 void CPWL_ListCtrl::SetCaret(int32_t nItemIndex) {
344 if (!IsValid(nItemIndex))
345 return;
346
347 if (IsMultipleSel()) {
348 int32_t nOldIndex = m_nCaretIndex;
349
350 if (nOldIndex != nItemIndex) {
351 m_nCaretIndex = nItemIndex;
352 InvalidateItem(nOldIndex);
353 InvalidateItem(nItemIndex);
354 }
355 }
356 }
357
InvalidateItem(int32_t nItemIndex)358 void CPWL_ListCtrl::InvalidateItem(int32_t nItemIndex) {
359 if (!m_pNotify) {
360 return;
361 }
362 if (nItemIndex == -1) {
363 if (!m_bNotifyFlag) {
364 m_bNotifyFlag = true;
365 CFX_FloatRect rcRefresh = m_rcPlate;
366 if (!m_pNotify->OnInvalidateRect(rcRefresh)) {
367 m_pNotify = nullptr; // Gone, dangling even.
368 }
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 if (!m_pNotify->OnInvalidateRect(rcRefresh)) {
380 m_pNotify = nullptr; // Gone, dangling even.
381 }
382 m_bNotifyFlag = false;
383 }
384 }
385 }
386
SelectItems()387 void CPWL_ListCtrl::SelectItems() {
388 for (const auto& item : m_SelectState) {
389 if (item.second != SelectState::NORMAL)
390 SetMultipleSelect(item.first, item.second == SelectState::SELECTING);
391 }
392 m_SelectState.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_SelectState.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 (FXSYS_IsFloatSmaller(rcItemCtrl.bottom, rcPlate.bottom)) {
433 if (FXSYS_IsFloatSmaller(rcItemCtrl.top, rcPlate.top)) {
434 SetScrollPosY(rcItem.bottom + rcPlate.Height());
435 }
436 } else if (FXSYS_IsFloatBigger(rcItemCtrl.top, rcPlate.top)) {
437 if (FXSYS_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->OnSetScrollInfoY(rcPlate.bottom, rcPlate.top, rcContent.bottom,
451 rcContent.top, GetFirstHeight(),
452 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 (!FXSYS_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 (FXSYS_IsFloatSmaller(fy - rcPlate.Height(), rcContent.bottom)) {
471 fy = rcContent.bottom + rcPlate.Height();
472 } else if (FXSYS_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->OnSetScrollPosY(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 m_rcContent = 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
GetItemIndex(const CFX_PointF & point) const528 int32_t CPWL_ListCtrl::GetItemIndex(const CFX_PointF& point) const {
529 CFX_PointF pt = OuterToInner(OutToIn(point));
530 bool bFirst = true;
531 bool bLast = true;
532 for (const auto& pListItem : m_ListItems) {
533 CFX_FloatRect rcListItem = pListItem->GetRect();
534 if (FXSYS_IsFloatBigger(pt.y, rcListItem.top))
535 bFirst = false;
536 if (FXSYS_IsFloatSmaller(pt.y, rcListItem.bottom))
537 bLast = false;
538 if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom) {
539 return pdfium::base::checked_cast<int32_t>(&pListItem -
540 &m_ListItems.front());
541 }
542 }
543 if (bFirst)
544 return 0;
545 if (bLast)
546 return GetCount() - 1;
547 return -1;
548 }
549
GetText() const550 WideString CPWL_ListCtrl::GetText() const {
551 if (IsMultipleSel())
552 return GetItemText(m_nCaretIndex);
553 return GetItemText(m_nSelItem);
554 }
555
AddItem(const WideString & str)556 void CPWL_ListCtrl::AddItem(const WideString& str) {
557 auto pListItem = std::make_unique<Item>();
558 pListItem->SetFontMap(m_pFontMap);
559 pListItem->SetFontSize(m_fFontSize);
560 pListItem->SetText(str);
561 m_ListItems.push_back(std::move(pListItem));
562 }
563
GetItemEdit(int32_t nIndex) const564 CPWL_EditImpl* CPWL_ListCtrl::GetItemEdit(int32_t nIndex) const {
565 if (!IsValid(nIndex))
566 return nullptr;
567 return m_ListItems[nIndex]->GetEdit();
568 }
569
GetCount() const570 int32_t CPWL_ListCtrl::GetCount() const {
571 return fxcrt::CollectionSize<int32_t>(m_ListItems);
572 }
573
GetFirstHeight() const574 float CPWL_ListCtrl::GetFirstHeight() const {
575 if (m_ListItems.empty())
576 return 1.0f;
577 return m_ListItems.front()->GetItemHeight();
578 }
579
GetFirstSelected() const580 int32_t CPWL_ListCtrl::GetFirstSelected() const {
581 int32_t i = 0;
582 for (const auto& pListItem : m_ListItems) {
583 if (pListItem->IsSelected())
584 return i;
585 ++i;
586 }
587 return -1;
588 }
589
GetLastSelected() const590 int32_t CPWL_ListCtrl::GetLastSelected() const {
591 for (auto iter = m_ListItems.rbegin(); iter != m_ListItems.rend(); ++iter) {
592 if ((*iter)->IsSelected())
593 return pdfium::base::checked_cast<int32_t>(&*iter - &m_ListItems.front());
594 }
595 return -1;
596 }
597
FindNext(int32_t nIndex,wchar_t nChar) const598 int32_t CPWL_ListCtrl::FindNext(int32_t nIndex, wchar_t nChar) const {
599 int32_t nCircleIndex = nIndex;
600 int32_t sz = GetCount();
601 for (int32_t i = 0; i < sz; i++) {
602 nCircleIndex++;
603 if (nCircleIndex >= sz)
604 nCircleIndex = 0;
605
606 if (Item* pListItem = m_ListItems[nCircleIndex].get()) {
607 if (FXSYS_towupper(pListItem->GetFirstChar()) == FXSYS_towupper(nChar))
608 return nCircleIndex;
609 }
610 }
611
612 return nCircleIndex;
613 }
614
IsItemSelected(int32_t nIndex) const615 bool CPWL_ListCtrl::IsItemSelected(int32_t nIndex) const {
616 return IsValid(nIndex) && m_ListItems[nIndex]->IsSelected();
617 }
618
SetItemSelect(int32_t nIndex,bool bSelected)619 void CPWL_ListCtrl::SetItemSelect(int32_t nIndex, bool bSelected) {
620 if (IsValid(nIndex))
621 m_ListItems[nIndex]->SetSelect(bSelected);
622 }
623
IsValid(int32_t nItemIndex) const624 bool CPWL_ListCtrl::IsValid(int32_t nItemIndex) const {
625 return fxcrt::IndexInBounds(m_ListItems, nItemIndex);
626 }
627
GetItemText(int32_t nIndex) const628 WideString CPWL_ListCtrl::GetItemText(int32_t nIndex) const {
629 if (IsValid(nIndex))
630 return m_ListItems[nIndex]->GetText();
631 return WideString();
632 }
633