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_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 "fpdfsdk/pwl/cpwl_edit_impl.h"
15 #include "fpdfsdk/pwl/cpwl_list_box.h"
16 #include "third_party/base/stl_util.h"
17
18 CPWL_ListCtrl::NotifyIface::~NotifyIface() = default;
19
Item()20 CPWL_ListCtrl::Item::Item() : m_pEdit(std::make_unique<CPWL_EditImpl>()) {
21 m_pEdit->SetAlignmentV(1, true);
22 m_pEdit->Initialize();
23 }
24
25 CPWL_ListCtrl::Item::~Item() = default;
26
SetFontMap(IPVT_FontMap * pFontMap)27 void CPWL_ListCtrl::Item::SetFontMap(IPVT_FontMap* pFontMap) {
28 m_pEdit->SetFontMap(pFontMap);
29 }
30
SetText(const WideString & text)31 void CPWL_ListCtrl::Item::SetText(const WideString& text) {
32 m_pEdit->SetText(text);
33 }
34
SetFontSize(float fFontSize)35 void CPWL_ListCtrl::Item::SetFontSize(float fFontSize) {
36 m_pEdit->SetFontSize(fFontSize);
37 }
38
GetItemHeight() const39 float CPWL_ListCtrl::Item::GetItemHeight() const {
40 return m_pEdit->GetContentRect().Height();
41 }
42
GetFirstChar() const43 uint16_t CPWL_ListCtrl::Item::GetFirstChar() const {
44 CPVT_Word word;
45 CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator();
46 pIterator->SetAt(1);
47 pIterator->GetWord(word);
48 return word.Word;
49 }
50
GetText() const51 WideString CPWL_ListCtrl::Item::GetText() const {
52 return m_pEdit->GetText();
53 }
54
55 CPWL_ListCtrl::SelectState::SelectState() = default;
56
57 CPWL_ListCtrl::SelectState::~SelectState() = default;
58
Add(int32_t nItemIndex)59 void CPWL_ListCtrl::SelectState::Add(int32_t nItemIndex) {
60 m_Items[nItemIndex] = SELECTING;
61 }
62
Add(int32_t nBeginIndex,int32_t nEndIndex)63 void CPWL_ListCtrl::SelectState::Add(int32_t nBeginIndex, int32_t nEndIndex) {
64 if (nBeginIndex > nEndIndex)
65 std::swap(nBeginIndex, nEndIndex);
66
67 for (int32_t i = nBeginIndex; i <= nEndIndex; ++i)
68 Add(i);
69 }
70
Sub(int32_t nItemIndex)71 void CPWL_ListCtrl::SelectState::Sub(int32_t nItemIndex) {
72 auto it = m_Items.find(nItemIndex);
73 if (it != m_Items.end())
74 it->second = DESELECTING;
75 }
76
Sub(int32_t nBeginIndex,int32_t nEndIndex)77 void CPWL_ListCtrl::SelectState::Sub(int32_t nBeginIndex, int32_t nEndIndex) {
78 if (nBeginIndex > nEndIndex)
79 std::swap(nBeginIndex, nEndIndex);
80
81 for (int32_t i = nBeginIndex; i <= nEndIndex; ++i)
82 Sub(i);
83 }
84
DeselectAll()85 void CPWL_ListCtrl::SelectState::DeselectAll() {
86 for (auto& item : m_Items)
87 item.second = DESELECTING;
88 }
89
Done()90 void CPWL_ListCtrl::SelectState::Done() {
91 auto it = m_Items.begin();
92 while (it != m_Items.end()) {
93 if (it->second == DESELECTING)
94 it = m_Items.erase(it);
95 else
96 (it++)->second = NORMAL;
97 }
98 }
99
100 CPWL_ListCtrl::CPWL_ListCtrl() = default;
101
~CPWL_ListCtrl()102 CPWL_ListCtrl::~CPWL_ListCtrl() {
103 Clear();
104 }
105
InToOut(const CFX_PointF & point) const106 CFX_PointF CPWL_ListCtrl::InToOut(const CFX_PointF& point) const {
107 CFX_FloatRect rcPlate = m_rcPlate;
108 return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
109 point.y - (m_ptScrollPos.y - rcPlate.top));
110 }
111
OutToIn(const CFX_PointF & point) const112 CFX_PointF CPWL_ListCtrl::OutToIn(const CFX_PointF& point) const {
113 CFX_FloatRect rcPlate = m_rcPlate;
114 return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left),
115 point.y + (m_ptScrollPos.y - rcPlate.top));
116 }
117
InToOut(const CFX_FloatRect & rect) const118 CFX_FloatRect CPWL_ListCtrl::InToOut(const CFX_FloatRect& rect) const {
119 CFX_PointF ptLeftBottom = InToOut(CFX_PointF(rect.left, rect.bottom));
120 CFX_PointF ptRightTop = InToOut(CFX_PointF(rect.right, rect.top));
121 return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
122 ptRightTop.y);
123 }
124
OutToIn(const CFX_FloatRect & rect) const125 CFX_FloatRect CPWL_ListCtrl::OutToIn(const CFX_FloatRect& rect) const {
126 CFX_PointF ptLeftBottom = OutToIn(CFX_PointF(rect.left, rect.bottom));
127 CFX_PointF ptRightTop = OutToIn(CFX_PointF(rect.right, rect.top));
128 return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
129 ptRightTop.y);
130 }
131
InnerToOuter(const CFX_PointF & point) const132 CFX_PointF CPWL_ListCtrl::InnerToOuter(const CFX_PointF& point) const {
133 return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y);
134 }
135
OuterToInner(const CFX_PointF & point) const136 CFX_PointF CPWL_ListCtrl::OuterToInner(const CFX_PointF& point) const {
137 return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y);
138 }
139
InnerToOuter(const CFX_FloatRect & rect) const140 CFX_FloatRect CPWL_ListCtrl::InnerToOuter(const CFX_FloatRect& rect) const {
141 CFX_PointF ptLeftTop = InnerToOuter(CFX_PointF(rect.left, rect.top));
142 CFX_PointF ptRightBottom = InnerToOuter(CFX_PointF(rect.right, rect.bottom));
143 return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
144 ptLeftTop.y);
145 }
146
OuterToInner(const CFX_FloatRect & rect) const147 CFX_FloatRect CPWL_ListCtrl::OuterToInner(const CFX_FloatRect& rect) const {
148 CFX_PointF ptLeftTop = OuterToInner(CFX_PointF(rect.left, rect.top));
149 CFX_PointF ptRightBottom = OuterToInner(CFX_PointF(rect.right, rect.bottom));
150 return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
151 ptLeftTop.y);
152 }
153
OnMouseDown(const CFX_PointF & point,bool bShift,bool bCtrl)154 void CPWL_ListCtrl::OnMouseDown(const CFX_PointF& point,
155 bool bShift,
156 bool bCtrl) {
157 int32_t nHitIndex = GetItemIndex(point);
158
159 if (IsMultipleSel()) {
160 if (bCtrl) {
161 if (IsItemSelected(nHitIndex)) {
162 m_SelectState.Sub(nHitIndex);
163 SelectItems();
164 m_bCtrlSel = false;
165 } else {
166 m_SelectState.Add(nHitIndex);
167 SelectItems();
168 m_bCtrlSel = true;
169 }
170
171 m_nFootIndex = nHitIndex;
172 } else if (bShift) {
173 m_SelectState.DeselectAll();
174 m_SelectState.Add(m_nFootIndex, nHitIndex);
175 SelectItems();
176 } else {
177 m_SelectState.DeselectAll();
178 m_SelectState.Add(nHitIndex);
179 SelectItems();
180
181 m_nFootIndex = nHitIndex;
182 }
183
184 SetCaret(nHitIndex);
185 } else {
186 SetSingleSelect(nHitIndex);
187 }
188
189 if (!IsItemVisible(nHitIndex))
190 ScrollToListItem(nHitIndex);
191 }
192
OnMouseMove(const CFX_PointF & point,bool bShift,bool bCtrl)193 void CPWL_ListCtrl::OnMouseMove(const CFX_PointF& point,
194 bool bShift,
195 bool bCtrl) {
196 int32_t nHitIndex = GetItemIndex(point);
197
198 if (IsMultipleSel()) {
199 if (bCtrl) {
200 if (m_bCtrlSel)
201 m_SelectState.Add(m_nFootIndex, nHitIndex);
202 else
203 m_SelectState.Sub(m_nFootIndex, nHitIndex);
204
205 SelectItems();
206 } else {
207 m_SelectState.DeselectAll();
208 m_SelectState.Add(m_nFootIndex, nHitIndex);
209 SelectItems();
210 }
211
212 SetCaret(nHitIndex);
213 } else {
214 SetSingleSelect(nHitIndex);
215 }
216
217 if (!IsItemVisible(nHitIndex))
218 ScrollToListItem(nHitIndex);
219 }
220
OnVK(int32_t nItemIndex,bool bShift,bool bCtrl)221 void CPWL_ListCtrl::OnVK(int32_t nItemIndex, bool bShift, bool bCtrl) {
222 if (IsMultipleSel()) {
223 if (nItemIndex >= 0 && nItemIndex < GetCount()) {
224 if (bCtrl) {
225 } else if (bShift) {
226 m_SelectState.DeselectAll();
227 m_SelectState.Add(m_nFootIndex, nItemIndex);
228 SelectItems();
229 } else {
230 m_SelectState.DeselectAll();
231 m_SelectState.Add(nItemIndex);
232 SelectItems();
233 m_nFootIndex = nItemIndex;
234 }
235
236 SetCaret(nItemIndex);
237 }
238 } else {
239 SetSingleSelect(nItemIndex);
240 }
241
242 if (!IsItemVisible(nItemIndex))
243 ScrollToListItem(nItemIndex);
244 }
245
OnVK_UP(bool bShift,bool bCtrl)246 void CPWL_ListCtrl::OnVK_UP(bool bShift, bool bCtrl) {
247 OnVK(IsMultipleSel() ? GetCaret() - 1 : GetSelect() - 1, bShift, bCtrl);
248 }
249
OnVK_DOWN(bool bShift,bool bCtrl)250 void CPWL_ListCtrl::OnVK_DOWN(bool bShift, bool bCtrl) {
251 OnVK(IsMultipleSel() ? GetCaret() + 1 : GetSelect() + 1, bShift, bCtrl);
252 }
253
OnVK_LEFT(bool bShift,bool bCtrl)254 void CPWL_ListCtrl::OnVK_LEFT(bool bShift, bool bCtrl) {
255 OnVK(0, bShift, bCtrl);
256 }
257
OnVK_RIGHT(bool bShift,bool bCtrl)258 void CPWL_ListCtrl::OnVK_RIGHT(bool bShift, bool bCtrl) {
259 OnVK(GetCount() - 1, bShift, bCtrl);
260 }
261
OnVK_HOME(bool bShift,bool bCtrl)262 void CPWL_ListCtrl::OnVK_HOME(bool bShift, bool bCtrl) {
263 OnVK(0, bShift, bCtrl);
264 }
265
OnVK_END(bool bShift,bool bCtrl)266 void CPWL_ListCtrl::OnVK_END(bool bShift, bool bCtrl) {
267 OnVK(GetCount() - 1, bShift, bCtrl);
268 }
269
OnChar(uint16_t nChar,bool bShift,bool bCtrl)270 bool CPWL_ListCtrl::OnChar(uint16_t nChar, bool bShift, bool bCtrl) {
271 int32_t nIndex = GetLastSelected();
272 int32_t nFindIndex = FindNext(nIndex, nChar);
273
274 if (nFindIndex != nIndex) {
275 OnVK(nFindIndex, bShift, bCtrl);
276 return true;
277 }
278 return false;
279 }
280
SetPlateRect(const CFX_FloatRect & rect)281 void CPWL_ListCtrl::SetPlateRect(const CFX_FloatRect& rect) {
282 m_rcPlate = rect;
283 m_ptScrollPos.x = rect.left;
284 SetScrollPos(CFX_PointF(rect.left, rect.top));
285 ReArrange(0);
286 InvalidateItem(-1);
287 }
288
GetItemRect(int32_t nIndex) const289 CFX_FloatRect CPWL_ListCtrl::GetItemRect(int32_t nIndex) const {
290 return InToOut(GetItemRectInternal(nIndex));
291 }
292
GetItemRectInternal(int32_t nIndex) const293 CFX_FloatRect CPWL_ListCtrl::GetItemRectInternal(int32_t nIndex) const {
294 if (!IsValid(nIndex))
295 return CFX_FloatRect();
296
297 CFX_FloatRect rcItem = m_ListItems[nIndex]->GetRect();
298 rcItem.left = 0.0f;
299 rcItem.right = m_rcPlate.Width();
300 return InnerToOuter(rcItem);
301 }
302
AddString(const WideString & str)303 void CPWL_ListCtrl::AddString(const WideString& str) {
304 AddItem(str);
305 ReArrange(GetCount() - 1);
306 }
307
SetMultipleSelect(int32_t nItemIndex,bool bSelected)308 void CPWL_ListCtrl::SetMultipleSelect(int32_t nItemIndex, bool bSelected) {
309 if (!IsValid(nItemIndex))
310 return;
311
312 if (bSelected != IsItemSelected(nItemIndex)) {
313 if (bSelected) {
314 SetItemSelect(nItemIndex, true);
315 InvalidateItem(nItemIndex);
316 } else {
317 SetItemSelect(nItemIndex, false);
318 InvalidateItem(nItemIndex);
319 }
320 }
321 }
322
SetSingleSelect(int32_t nItemIndex)323 void CPWL_ListCtrl::SetSingleSelect(int32_t nItemIndex) {
324 if (!IsValid(nItemIndex))
325 return;
326
327 if (m_nSelItem != nItemIndex) {
328 if (m_nSelItem >= 0) {
329 SetItemSelect(m_nSelItem, false);
330 InvalidateItem(m_nSelItem);
331 }
332
333 SetItemSelect(nItemIndex, true);
334 InvalidateItem(nItemIndex);
335 m_nSelItem = nItemIndex;
336 }
337 }
338
SetCaret(int32_t nItemIndex)339 void CPWL_ListCtrl::SetCaret(int32_t nItemIndex) {
340 if (!IsValid(nItemIndex))
341 return;
342
343 if (IsMultipleSel()) {
344 int32_t nOldIndex = m_nCaretIndex;
345
346 if (nOldIndex != nItemIndex) {
347 m_nCaretIndex = nItemIndex;
348 InvalidateItem(nOldIndex);
349 InvalidateItem(nItemIndex);
350 }
351 }
352 }
353
InvalidateItem(int32_t nItemIndex)354 void CPWL_ListCtrl::InvalidateItem(int32_t nItemIndex) {
355 if (m_pNotify) {
356 if (nItemIndex == -1) {
357 if (!m_bNotifyFlag) {
358 m_bNotifyFlag = true;
359 CFX_FloatRect rcRefresh = m_rcPlate;
360 m_pNotify->OnInvalidateRect(rcRefresh);
361 m_bNotifyFlag = false;
362 }
363 } else {
364 if (!m_bNotifyFlag) {
365 m_bNotifyFlag = true;
366 CFX_FloatRect rcRefresh = GetItemRect(nItemIndex);
367 rcRefresh.left -= 1.0f;
368 rcRefresh.right += 1.0f;
369 rcRefresh.bottom -= 1.0f;
370 rcRefresh.top += 1.0f;
371
372 m_pNotify->OnInvalidateRect(rcRefresh);
373 m_bNotifyFlag = false;
374 }
375 }
376 }
377 }
378
SelectItems()379 void CPWL_ListCtrl::SelectItems() {
380 for (const auto& item : m_SelectState) {
381 if (item.second != SelectState::NORMAL)
382 SetMultipleSelect(item.first, item.second == SelectState::SELECTING);
383 }
384 m_SelectState.Done();
385 }
386
Select(int32_t nItemIndex)387 void CPWL_ListCtrl::Select(int32_t nItemIndex) {
388 if (!IsValid(nItemIndex))
389 return;
390
391 if (IsMultipleSel()) {
392 m_SelectState.Add(nItemIndex);
393 SelectItems();
394 } else {
395 SetSingleSelect(nItemIndex);
396 }
397 }
398
Deselect(int32_t nItemIndex)399 void CPWL_ListCtrl::Deselect(int32_t nItemIndex) {
400 if (!IsItemSelected(nItemIndex))
401 return;
402
403 SetMultipleSelect(nItemIndex, false);
404
405 if (!IsMultipleSel())
406 m_nSelItem = -1;
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->OnSetScrollInfoY(rcPlate.bottom, rcPlate.top, rcContent.bottom,
443 rcContent.top, GetFirstHeight(),
444 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->OnSetScrollPosY(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 (IsValid(nItemIndex - 1))
493 fPosY = m_ListItems[nItemIndex - 1]->GetRect().bottom;
494
495 for (const auto& pListItem : m_ListItems) {
496 float fListItemHeight = pListItem->GetItemHeight();
497 pListItem->SetRect(
498 CFX_FloatRect(0.0f, fPosY + fListItemHeight, 0.0f, fPosY));
499 fPosY += fListItemHeight;
500 }
501 SetContentRect(CFX_FloatRect(0.0f, fPosY, 0.0f, 0.0f));
502 SetScrollInfo();
503 }
504
SetTopItem(int32_t nIndex)505 void CPWL_ListCtrl::SetTopItem(int32_t nIndex) {
506 if (IsValid(nIndex)) {
507 CFX_FloatRect rcItem = GetItemRectInternal(nIndex);
508 SetScrollPosY(rcItem.top);
509 }
510 }
511
GetTopItem() const512 int32_t CPWL_ListCtrl::GetTopItem() const {
513 int32_t nItemIndex = GetItemIndex(GetBTPoint());
514 if (!IsItemVisible(nItemIndex) && IsItemVisible(nItemIndex + 1))
515 nItemIndex += 1;
516
517 return nItemIndex;
518 }
519
Clear()520 void CPWL_ListCtrl::Clear() {
521 m_ListItems.clear();
522 InvalidateItem(-1);
523 }
524
Cancel()525 void CPWL_ListCtrl::Cancel() {
526 m_SelectState.DeselectAll();
527 }
528
GetItemIndex(const CFX_PointF & point) const529 int32_t CPWL_ListCtrl::GetItemIndex(const CFX_PointF& point) const {
530 CFX_PointF pt = OuterToInner(OutToIn(point));
531 bool bFirst = true;
532 bool bLast = true;
533 for (const auto& pListItem : m_ListItems) {
534 CFX_FloatRect rcListItem = pListItem->GetRect();
535 if (IsFloatBigger(pt.y, rcListItem.top))
536 bFirst = false;
537 if (IsFloatSmaller(pt.y, rcListItem.bottom))
538 bLast = false;
539 if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom)
540 return &pListItem - &m_ListItems.front();
541 }
542 if (bFirst)
543 return 0;
544 if (bLast)
545 return GetCount() - 1;
546 return -1;
547 }
548
GetText() const549 WideString CPWL_ListCtrl::GetText() const {
550 if (IsMultipleSel())
551 return GetItemText(m_nCaretIndex);
552 return GetItemText(m_nSelItem);
553 }
554
AddItem(const WideString & str)555 void CPWL_ListCtrl::AddItem(const WideString& str) {
556 auto pListItem = std::make_unique<Item>();
557 pListItem->SetFontMap(m_pFontMap.Get());
558 pListItem->SetFontSize(m_fFontSize);
559 pListItem->SetText(str);
560 m_ListItems.push_back(std::move(pListItem));
561 }
562
GetItemEdit(int32_t nIndex) const563 CPWL_EditImpl* CPWL_ListCtrl::GetItemEdit(int32_t nIndex) const {
564 if (!IsValid(nIndex))
565 return nullptr;
566 return m_ListItems[nIndex]->GetEdit();
567 }
568
GetCount() const569 int32_t CPWL_ListCtrl::GetCount() const {
570 return pdfium::CollectionSize<int32_t>(m_ListItems);
571 }
572
GetFirstHeight() const573 float CPWL_ListCtrl::GetFirstHeight() const {
574 if (m_ListItems.empty())
575 return 1.0f;
576 return m_ListItems.front()->GetItemHeight();
577 }
578
GetFirstSelected() const579 int32_t CPWL_ListCtrl::GetFirstSelected() const {
580 int32_t i = 0;
581 for (const auto& pListItem : m_ListItems) {
582 if (pListItem->IsSelected())
583 return i;
584 ++i;
585 }
586 return -1;
587 }
588
GetLastSelected() const589 int32_t CPWL_ListCtrl::GetLastSelected() const {
590 for (auto iter = m_ListItems.rbegin(); iter != m_ListItems.rend(); ++iter) {
591 if ((*iter)->IsSelected())
592 return &*iter - &m_ListItems.front();
593 }
594 return -1;
595 }
596
FindNext(int32_t nIndex,wchar_t nChar) const597 int32_t CPWL_ListCtrl::FindNext(int32_t nIndex, wchar_t nChar) const {
598 int32_t nCircleIndex = nIndex;
599 int32_t sz = GetCount();
600 for (int32_t i = 0; i < sz; i++) {
601 nCircleIndex++;
602 if (nCircleIndex >= sz)
603 nCircleIndex = 0;
604
605 if (Item* pListItem = m_ListItems[nCircleIndex].get()) {
606 if (FXSYS_towupper(pListItem->GetFirstChar()) == FXSYS_towupper(nChar))
607 return nCircleIndex;
608 }
609 }
610
611 return nCircleIndex;
612 }
613
IsItemSelected(int32_t nIndex) const614 bool CPWL_ListCtrl::IsItemSelected(int32_t nIndex) const {
615 return IsValid(nIndex) && m_ListItems[nIndex]->IsSelected();
616 }
617
SetItemSelect(int32_t nIndex,bool bSelected)618 void CPWL_ListCtrl::SetItemSelect(int32_t nIndex, bool bSelected) {
619 if (IsValid(nIndex))
620 m_ListItems[nIndex]->SetSelect(bSelected);
621 }
622
IsValid(int32_t nItemIndex) const623 bool CPWL_ListCtrl::IsValid(int32_t nItemIndex) const {
624 return pdfium::IndexInBounds(m_ListItems, nItemIndex);
625 }
626
GetItemText(int32_t nIndex) const627 WideString CPWL_ListCtrl::GetItemText(int32_t nIndex) const {
628 if (IsValid(nIndex))
629 return m_ListItems[nIndex]->GetText();
630 return WideString();
631 }
632