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/fxedit/fxet_list.h"
8
9 #include "core/fpdfdoc/cpvt_word.h"
10 #include "fpdfsdk/fxedit/fxet_edit.h"
11 #include "fpdfsdk/pdfwindow/PWL_ListBox.h"
12
CFX_ListItem()13 CFX_ListItem::CFX_ListItem()
14 : m_pEdit(new CFX_Edit),
15 m_bSelected(false),
16 m_rcListItem(0.0f, 0.0f, 0.0f, 0.0f) {
17 m_pEdit->SetAlignmentV(1, true);
18 m_pEdit->Initialize();
19 }
20
~CFX_ListItem()21 CFX_ListItem::~CFX_ListItem() {
22 }
23
SetFontMap(IPVT_FontMap * pFontMap)24 void CFX_ListItem::SetFontMap(IPVT_FontMap* pFontMap) {
25 m_pEdit->SetFontMap(pFontMap);
26 }
27
GetEdit() const28 CFX_Edit* CFX_ListItem::GetEdit() const {
29 return m_pEdit.get();
30 }
31
GetIterator() const32 CFX_Edit_Iterator* CFX_ListItem::GetIterator() const {
33 return m_pEdit->GetIterator();
34 }
35
SetRect(const CLST_Rect & rect)36 void CFX_ListItem::SetRect(const CLST_Rect& rect) {
37 m_rcListItem = rect;
38 }
39
GetRect() const40 CLST_Rect CFX_ListItem::GetRect() const {
41 return m_rcListItem;
42 }
43
IsSelected() const44 bool CFX_ListItem::IsSelected() const {
45 return m_bSelected;
46 }
47
SetSelect(bool bSelected)48 void CFX_ListItem::SetSelect(bool bSelected) {
49 m_bSelected = bSelected;
50 }
51
SetText(const CFX_WideString & text)52 void CFX_ListItem::SetText(const CFX_WideString& text) {
53 m_pEdit->SetText(text);
54 }
55
SetFontSize(FX_FLOAT fFontSize)56 void CFX_ListItem::SetFontSize(FX_FLOAT fFontSize) {
57 m_pEdit->SetFontSize(fFontSize);
58 }
59
GetItemHeight() const60 FX_FLOAT CFX_ListItem::GetItemHeight() const {
61 return m_pEdit->GetContentRect().Height();
62 }
63
GetFirstChar() const64 uint16_t CFX_ListItem::GetFirstChar() const {
65 CPVT_Word word;
66 CFX_Edit_Iterator* pIterator = GetIterator();
67 pIterator->SetAt(1);
68 pIterator->GetWord(word);
69 return word.Word;
70 }
71
GetText() const72 CFX_WideString CFX_ListItem::GetText() const {
73 return m_pEdit->GetText();
74 }
75
CFX_ListContainer()76 CFX_ListContainer::CFX_ListContainer() {}
77
~CFX_ListContainer()78 CFX_ListContainer::~CFX_ListContainer() {}
79
SetPlateRect(const CFX_FloatRect & rect)80 void CFX_ListContainer::SetPlateRect(const CFX_FloatRect& rect) {
81 m_rcPlate = rect;
82 }
83
CPLST_Select()84 CPLST_Select::CPLST_Select() {}
85
~CPLST_Select()86 CPLST_Select::~CPLST_Select() {
87 for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++)
88 delete m_aItems.GetAt(i);
89
90 m_aItems.RemoveAll();
91 }
92
Add(int32_t nItemIndex)93 void CPLST_Select::Add(int32_t nItemIndex) {
94 int32_t nIndex = Find(nItemIndex);
95
96 if (nIndex < 0) {
97 m_aItems.Add(new CPLST_Select_Item(nItemIndex, 1));
98 } else {
99 if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex)) {
100 pItem->nState = 1;
101 }
102 }
103 }
104
Add(int32_t nBeginIndex,int32_t nEndIndex)105 void CPLST_Select::Add(int32_t nBeginIndex, int32_t nEndIndex) {
106 if (nBeginIndex > nEndIndex) {
107 int32_t nTemp = nEndIndex;
108 nEndIndex = nBeginIndex;
109 nBeginIndex = nTemp;
110 }
111
112 for (int32_t i = nBeginIndex; i <= nEndIndex; i++)
113 Add(i);
114 }
115
Sub(int32_t nItemIndex)116 void CPLST_Select::Sub(int32_t nItemIndex) {
117 for (int32_t i = m_aItems.GetSize() - 1; i >= 0; i--) {
118 if (CPLST_Select_Item* pItem = m_aItems.GetAt(i))
119 if (pItem->nItemIndex == nItemIndex)
120 pItem->nState = -1;
121 }
122 }
123
Sub(int32_t nBeginIndex,int32_t nEndIndex)124 void CPLST_Select::Sub(int32_t nBeginIndex, int32_t nEndIndex) {
125 if (nBeginIndex > nEndIndex) {
126 int32_t nTemp = nEndIndex;
127 nEndIndex = nBeginIndex;
128 nBeginIndex = nTemp;
129 }
130
131 for (int32_t i = nBeginIndex; i <= nEndIndex; i++)
132 Sub(i);
133 }
134
Find(int32_t nItemIndex) const135 int32_t CPLST_Select::Find(int32_t nItemIndex) const {
136 for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++) {
137 if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
138 if (pItem->nItemIndex == nItemIndex)
139 return i;
140 }
141 }
142
143 return -1;
144 }
145
IsExist(int32_t nItemIndex) const146 bool CPLST_Select::IsExist(int32_t nItemIndex) const {
147 return Find(nItemIndex) >= 0;
148 }
149
GetCount() const150 int32_t CPLST_Select::GetCount() const {
151 return m_aItems.GetSize();
152 }
153
GetItemIndex(int32_t nIndex) const154 int32_t CPLST_Select::GetItemIndex(int32_t nIndex) const {
155 if (nIndex >= 0 && nIndex < m_aItems.GetSize())
156 if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex))
157 return pItem->nItemIndex;
158
159 return -1;
160 }
161
GetState(int32_t nIndex) const162 int32_t CPLST_Select::GetState(int32_t nIndex) const {
163 if (nIndex >= 0 && nIndex < m_aItems.GetSize())
164 if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex))
165 return pItem->nState;
166
167 return 0;
168 }
169
DeselectAll()170 void CPLST_Select::DeselectAll() {
171 for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++) {
172 if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
173 pItem->nState = -1;
174 }
175 }
176 }
177
Done()178 void CPLST_Select::Done() {
179 for (int32_t i = m_aItems.GetSize() - 1; i >= 0; i--) {
180 if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
181 if (pItem->nState == -1) {
182 delete pItem;
183 m_aItems.RemoveAt(i);
184 } else {
185 pItem->nState = 0;
186 }
187 }
188 }
189 }
190
CFX_ListCtrl()191 CFX_ListCtrl::CFX_ListCtrl()
192 : m_pNotify(nullptr),
193 m_bNotifyFlag(false),
194 m_nSelItem(-1),
195 m_nFootIndex(-1),
196 m_bCtrlSel(false),
197 m_nCaretIndex(-1),
198 m_fFontSize(0.0f),
199 m_pFontMap(nullptr),
200 m_bMultiple(false) {}
201
~CFX_ListCtrl()202 CFX_ListCtrl::~CFX_ListCtrl() {
203 Empty();
204 }
205
SetNotify(CPWL_List_Notify * pNotify)206 void CFX_ListCtrl::SetNotify(CPWL_List_Notify* pNotify) {
207 m_pNotify = pNotify;
208 }
209
InToOut(const CFX_PointF & point) const210 CFX_PointF CFX_ListCtrl::InToOut(const CFX_PointF& point) const {
211 CFX_FloatRect rcPlate = GetPlateRect();
212 return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
213 point.y - (m_ptScrollPos.y - rcPlate.top));
214 }
215
OutToIn(const CFX_PointF & point) const216 CFX_PointF CFX_ListCtrl::OutToIn(const CFX_PointF& point) const {
217 CFX_FloatRect rcPlate = GetPlateRect();
218 return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left),
219 point.y + (m_ptScrollPos.y - rcPlate.top));
220 }
221
InToOut(const CFX_FloatRect & rect) const222 CFX_FloatRect CFX_ListCtrl::InToOut(const CFX_FloatRect& rect) const {
223 CFX_PointF ptLeftBottom = InToOut(CFX_PointF(rect.left, rect.bottom));
224 CFX_PointF ptRightTop = InToOut(CFX_PointF(rect.right, rect.top));
225 return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
226 ptRightTop.y);
227 }
228
OutToIn(const CFX_FloatRect & rect) const229 CFX_FloatRect CFX_ListCtrl::OutToIn(const CFX_FloatRect& rect) const {
230 CFX_PointF ptLeftBottom = OutToIn(CFX_PointF(rect.left, rect.bottom));
231 CFX_PointF ptRightTop = OutToIn(CFX_PointF(rect.right, rect.top));
232 return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
233 ptRightTop.y);
234 }
235
OnMouseDown(const CFX_PointF & point,bool bShift,bool bCtrl)236 void CFX_ListCtrl::OnMouseDown(const CFX_PointF& point,
237 bool bShift,
238 bool bCtrl) {
239 int32_t nHitIndex = GetItemIndex(point);
240
241 if (IsMultipleSel()) {
242 if (bCtrl) {
243 if (IsItemSelected(nHitIndex)) {
244 m_aSelItems.Sub(nHitIndex);
245 SelectItems();
246 m_bCtrlSel = false;
247 } else {
248 m_aSelItems.Add(nHitIndex);
249 SelectItems();
250 m_bCtrlSel = true;
251 }
252
253 m_nFootIndex = nHitIndex;
254 } else if (bShift) {
255 m_aSelItems.DeselectAll();
256 m_aSelItems.Add(m_nFootIndex, nHitIndex);
257 SelectItems();
258 } else {
259 m_aSelItems.DeselectAll();
260 m_aSelItems.Add(nHitIndex);
261 SelectItems();
262
263 m_nFootIndex = nHitIndex;
264 }
265
266 SetCaret(nHitIndex);
267 } else {
268 SetSingleSelect(nHitIndex);
269 }
270
271 if (!IsItemVisible(nHitIndex))
272 ScrollToListItem(nHitIndex);
273 }
274
OnMouseMove(const CFX_PointF & point,bool bShift,bool bCtrl)275 void CFX_ListCtrl::OnMouseMove(const CFX_PointF& point,
276 bool bShift,
277 bool bCtrl) {
278 int32_t nHitIndex = GetItemIndex(point);
279
280 if (IsMultipleSel()) {
281 if (bCtrl) {
282 if (m_bCtrlSel)
283 m_aSelItems.Add(m_nFootIndex, nHitIndex);
284 else
285 m_aSelItems.Sub(m_nFootIndex, nHitIndex);
286
287 SelectItems();
288 } else {
289 m_aSelItems.DeselectAll();
290 m_aSelItems.Add(m_nFootIndex, nHitIndex);
291 SelectItems();
292 }
293
294 SetCaret(nHitIndex);
295 } else {
296 SetSingleSelect(nHitIndex);
297 }
298
299 if (!IsItemVisible(nHitIndex))
300 ScrollToListItem(nHitIndex);
301 }
302
OnVK(int32_t nItemIndex,bool bShift,bool bCtrl)303 void CFX_ListCtrl::OnVK(int32_t nItemIndex, bool bShift, bool bCtrl) {
304 if (IsMultipleSel()) {
305 if (nItemIndex >= 0 && nItemIndex < GetCount()) {
306 if (bCtrl) {
307 } else if (bShift) {
308 m_aSelItems.DeselectAll();
309 m_aSelItems.Add(m_nFootIndex, nItemIndex);
310 SelectItems();
311 } else {
312 m_aSelItems.DeselectAll();
313 m_aSelItems.Add(nItemIndex);
314 SelectItems();
315 m_nFootIndex = nItemIndex;
316 }
317
318 SetCaret(nItemIndex);
319 }
320 } else {
321 SetSingleSelect(nItemIndex);
322 }
323
324 if (!IsItemVisible(nItemIndex))
325 ScrollToListItem(nItemIndex);
326 }
327
OnVK_UP(bool bShift,bool bCtrl)328 void CFX_ListCtrl::OnVK_UP(bool bShift, bool bCtrl) {
329 OnVK(IsMultipleSel() ? GetCaret() - 1 : GetSelect() - 1, bShift, bCtrl);
330 }
331
OnVK_DOWN(bool bShift,bool bCtrl)332 void CFX_ListCtrl::OnVK_DOWN(bool bShift, bool bCtrl) {
333 OnVK(IsMultipleSel() ? GetCaret() + 1 : GetSelect() + 1, bShift, bCtrl);
334 }
335
OnVK_LEFT(bool bShift,bool bCtrl)336 void CFX_ListCtrl::OnVK_LEFT(bool bShift, bool bCtrl) {
337 OnVK(0, bShift, bCtrl);
338 }
339
OnVK_RIGHT(bool bShift,bool bCtrl)340 void CFX_ListCtrl::OnVK_RIGHT(bool bShift, bool bCtrl) {
341 OnVK(GetCount() - 1, bShift, bCtrl);
342 }
343
OnVK_HOME(bool bShift,bool bCtrl)344 void CFX_ListCtrl::OnVK_HOME(bool bShift, bool bCtrl) {
345 OnVK(0, bShift, bCtrl);
346 }
347
OnVK_END(bool bShift,bool bCtrl)348 void CFX_ListCtrl::OnVK_END(bool bShift, bool bCtrl) {
349 OnVK(GetCount() - 1, bShift, bCtrl);
350 }
351
OnChar(uint16_t nChar,bool bShift,bool bCtrl)352 bool CFX_ListCtrl::OnChar(uint16_t nChar, bool bShift, bool bCtrl) {
353 int32_t nIndex = GetLastSelected();
354 int32_t nFindIndex = FindNext(nIndex, nChar);
355
356 if (nFindIndex != nIndex) {
357 OnVK(nFindIndex, bShift, bCtrl);
358 return true;
359 }
360 return false;
361 }
362
SetPlateRect(const CFX_FloatRect & rect)363 void CFX_ListCtrl::SetPlateRect(const CFX_FloatRect& rect) {
364 CFX_ListContainer::SetPlateRect(rect);
365 m_ptScrollPos.x = rect.left;
366 SetScrollPos(CFX_PointF(rect.left, rect.top));
367 ReArrange(0);
368 InvalidateItem(-1);
369 }
370
GetItemRect(int32_t nIndex) const371 CFX_FloatRect CFX_ListCtrl::GetItemRect(int32_t nIndex) const {
372 return InToOut(GetItemRectInternal(nIndex));
373 }
374
GetItemRectInternal(int32_t nIndex) const375 CFX_FloatRect CFX_ListCtrl::GetItemRectInternal(int32_t nIndex) const {
376 if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
377 CFX_FloatRect rcItem = pListItem->GetRect();
378 rcItem.left = 0.0f;
379 rcItem.right = GetPlateRect().Width();
380 return InnerToOuter(CLST_Rect(rcItem));
381 }
382
383 return CFX_FloatRect();
384 }
385
GetCaret() const386 int32_t CFX_ListCtrl::GetCaret() const {
387 return m_nCaretIndex;
388 }
389
GetSelect() const390 int32_t CFX_ListCtrl::GetSelect() const {
391 return m_nSelItem;
392 }
393
AddString(const CFX_WideString & str)394 void CFX_ListCtrl::AddString(const CFX_WideString& str) {
395 AddItem(str);
396 ReArrange(GetCount() - 1);
397 }
398
SetMultipleSelect(int32_t nItemIndex,bool bSelected)399 void CFX_ListCtrl::SetMultipleSelect(int32_t nItemIndex, bool bSelected) {
400 if (!IsValid(nItemIndex))
401 return;
402
403 if (bSelected != IsItemSelected(nItemIndex)) {
404 if (bSelected) {
405 SetItemSelect(nItemIndex, true);
406 InvalidateItem(nItemIndex);
407 } else {
408 SetItemSelect(nItemIndex, false);
409 InvalidateItem(nItemIndex);
410 }
411 }
412 }
413
SetSingleSelect(int32_t nItemIndex)414 void CFX_ListCtrl::SetSingleSelect(int32_t nItemIndex) {
415 if (!IsValid(nItemIndex))
416 return;
417
418 if (m_nSelItem != nItemIndex) {
419 if (m_nSelItem >= 0) {
420 SetItemSelect(m_nSelItem, false);
421 InvalidateItem(m_nSelItem);
422 }
423
424 SetItemSelect(nItemIndex, true);
425 InvalidateItem(nItemIndex);
426 m_nSelItem = nItemIndex;
427 }
428 }
429
SetCaret(int32_t nItemIndex)430 void CFX_ListCtrl::SetCaret(int32_t nItemIndex) {
431 if (!IsValid(nItemIndex))
432 return;
433
434 if (IsMultipleSel()) {
435 int32_t nOldIndex = m_nCaretIndex;
436
437 if (nOldIndex != nItemIndex) {
438 m_nCaretIndex = nItemIndex;
439 InvalidateItem(nOldIndex);
440 InvalidateItem(nItemIndex);
441 }
442 }
443 }
444
InvalidateItem(int32_t nItemIndex)445 void CFX_ListCtrl::InvalidateItem(int32_t nItemIndex) {
446 if (m_pNotify) {
447 if (nItemIndex == -1) {
448 if (!m_bNotifyFlag) {
449 m_bNotifyFlag = true;
450 CFX_FloatRect rcRefresh = GetPlateRect();
451 m_pNotify->IOnInvalidateRect(&rcRefresh);
452 m_bNotifyFlag = false;
453 }
454 } else {
455 if (!m_bNotifyFlag) {
456 m_bNotifyFlag = true;
457 CFX_FloatRect rcRefresh = GetItemRect(nItemIndex);
458 rcRefresh.left -= 1.0f;
459 rcRefresh.right += 1.0f;
460 rcRefresh.bottom -= 1.0f;
461 rcRefresh.top += 1.0f;
462
463 m_pNotify->IOnInvalidateRect(&rcRefresh);
464 m_bNotifyFlag = false;
465 }
466 }
467 }
468 }
469
SelectItems()470 void CFX_ListCtrl::SelectItems() {
471 for (int32_t i = 0, sz = m_aSelItems.GetCount(); i < sz; i++) {
472 int32_t nItemIndex = m_aSelItems.GetItemIndex(i);
473 int32_t nState = m_aSelItems.GetState(i);
474
475 switch (nState) {
476 case 1:
477 SetMultipleSelect(nItemIndex, true);
478 break;
479 case -1:
480 SetMultipleSelect(nItemIndex, false);
481 break;
482 }
483 }
484
485 m_aSelItems.Done();
486 }
487
Select(int32_t nItemIndex)488 void CFX_ListCtrl::Select(int32_t nItemIndex) {
489 if (!IsValid(nItemIndex))
490 return;
491
492 if (IsMultipleSel()) {
493 m_aSelItems.Add(nItemIndex);
494 SelectItems();
495 } else {
496 SetSingleSelect(nItemIndex);
497 }
498 }
499
IsItemVisible(int32_t nItemIndex) const500 bool CFX_ListCtrl::IsItemVisible(int32_t nItemIndex) const {
501 CFX_FloatRect rcPlate = GetPlateRect();
502 CFX_FloatRect rcItem = GetItemRect(nItemIndex);
503
504 return rcItem.bottom >= rcPlate.bottom && rcItem.top <= rcPlate.top;
505 }
506
ScrollToListItem(int32_t nItemIndex)507 void CFX_ListCtrl::ScrollToListItem(int32_t nItemIndex) {
508 if (!IsValid(nItemIndex))
509 return;
510
511 CFX_FloatRect rcPlate = GetPlateRect();
512 CFX_FloatRect rcItem = GetItemRectInternal(nItemIndex);
513 CFX_FloatRect rcItemCtrl = GetItemRect(nItemIndex);
514
515 if (IsFloatSmaller(rcItemCtrl.bottom, rcPlate.bottom)) {
516 if (IsFloatSmaller(rcItemCtrl.top, rcPlate.top)) {
517 SetScrollPosY(rcItem.bottom + rcPlate.Height());
518 }
519 } else if (IsFloatBigger(rcItemCtrl.top, rcPlate.top)) {
520 if (IsFloatBigger(rcItemCtrl.bottom, rcPlate.bottom)) {
521 SetScrollPosY(rcItem.top);
522 }
523 }
524 }
525
SetScrollInfo()526 void CFX_ListCtrl::SetScrollInfo() {
527 if (m_pNotify) {
528 CFX_FloatRect rcPlate = GetPlateRect();
529 CFX_FloatRect rcContent = GetContentRectInternal();
530
531 if (!m_bNotifyFlag) {
532 m_bNotifyFlag = true;
533 m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top,
534 rcContent.bottom, rcContent.top,
535 GetFirstHeight(), rcPlate.Height());
536 m_bNotifyFlag = false;
537 }
538 }
539 }
540
SetScrollPos(const CFX_PointF & point)541 void CFX_ListCtrl::SetScrollPos(const CFX_PointF& point) {
542 SetScrollPosY(point.y);
543 }
544
SetScrollPosY(FX_FLOAT fy)545 void CFX_ListCtrl::SetScrollPosY(FX_FLOAT fy) {
546 if (!IsFloatEqual(m_ptScrollPos.y, fy)) {
547 CFX_FloatRect rcPlate = GetPlateRect();
548 CFX_FloatRect rcContent = GetContentRectInternal();
549
550 if (rcPlate.Height() > rcContent.Height()) {
551 fy = rcPlate.top;
552 } else {
553 if (IsFloatSmaller(fy - rcPlate.Height(), rcContent.bottom)) {
554 fy = rcContent.bottom + rcPlate.Height();
555 } else if (IsFloatBigger(fy, rcContent.top)) {
556 fy = rcContent.top;
557 }
558 }
559
560 m_ptScrollPos.y = fy;
561 InvalidateItem(-1);
562
563 if (m_pNotify) {
564 if (!m_bNotifyFlag) {
565 m_bNotifyFlag = true;
566 m_pNotify->IOnSetScrollPosY(fy);
567 m_bNotifyFlag = false;
568 }
569 }
570 }
571 }
572
GetContentRectInternal() const573 CFX_FloatRect CFX_ListCtrl::GetContentRectInternal() const {
574 return InnerToOuter(CFX_ListContainer::GetContentRect());
575 }
576
GetContentRect() const577 CFX_FloatRect CFX_ListCtrl::GetContentRect() const {
578 return InToOut(GetContentRectInternal());
579 }
580
ReArrange(int32_t nItemIndex)581 void CFX_ListCtrl::ReArrange(int32_t nItemIndex) {
582 FX_FLOAT fPosY = 0.0f;
583
584 if (CFX_ListItem* pPrevItem = m_aListItems.GetAt(nItemIndex - 1))
585 fPosY = pPrevItem->GetRect().bottom;
586
587 for (int32_t i = nItemIndex, sz = m_aListItems.GetSize(); i < sz; i++) {
588 if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
589 FX_FLOAT fListItemHeight = pListItem->GetItemHeight();
590 pListItem->SetRect(CLST_Rect(0.0f, fPosY, 0.0f, fPosY + fListItemHeight));
591 fPosY += fListItemHeight;
592 }
593 }
594
595 SetContentRect(CLST_Rect(0.0f, 0.0f, 0.0f, fPosY));
596 SetScrollInfo();
597 }
598
SetTopItem(int32_t nIndex)599 void CFX_ListCtrl::SetTopItem(int32_t nIndex) {
600 if (IsValid(nIndex)) {
601 GetPlateRect();
602 CFX_FloatRect rcItem = GetItemRectInternal(nIndex);
603 SetScrollPosY(rcItem.top);
604 }
605 }
606
GetTopItem() const607 int32_t CFX_ListCtrl::GetTopItem() const {
608 int32_t nItemIndex = GetItemIndex(GetBTPoint());
609
610 if (!IsItemVisible(nItemIndex) && IsItemVisible(nItemIndex + 1))
611 nItemIndex += 1;
612
613 return nItemIndex;
614 }
615
Empty()616 void CFX_ListCtrl::Empty() {
617 for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++)
618 delete m_aListItems.GetAt(i);
619
620 m_aListItems.RemoveAll();
621
622 InvalidateItem(-1);
623 }
624
Cancel()625 void CFX_ListCtrl::Cancel() {
626 m_aSelItems.DeselectAll();
627 }
628
GetItemIndex(const CFX_PointF & point) const629 int32_t CFX_ListCtrl::GetItemIndex(const CFX_PointF& point) const {
630 CFX_PointF pt = OuterToInner(OutToIn(point));
631
632 bool bFirst = true;
633 bool bLast = true;
634
635 for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
636 if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
637 CLST_Rect rcListItem = pListItem->GetRect();
638
639 if (IsFloatBigger(pt.y, rcListItem.top)) {
640 bFirst = false;
641 }
642
643 if (IsFloatSmaller(pt.y, rcListItem.bottom)) {
644 bLast = false;
645 }
646
647 if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom) {
648 return i;
649 }
650 }
651 }
652
653 if (bFirst)
654 return 0;
655 if (bLast)
656 return m_aListItems.GetSize() - 1;
657
658 return -1;
659 }
660
GetText() const661 CFX_WideString CFX_ListCtrl::GetText() const {
662 if (IsMultipleSel())
663 return GetItemText(m_nCaretIndex);
664 return GetItemText(m_nSelItem);
665 }
666
SetFontMap(IPVT_FontMap * pFontMap)667 void CFX_ListCtrl::SetFontMap(IPVT_FontMap* pFontMap) {
668 m_pFontMap = pFontMap;
669 }
670
SetFontSize(FX_FLOAT fFontSize)671 void CFX_ListCtrl::SetFontSize(FX_FLOAT fFontSize) {
672 m_fFontSize = fFontSize;
673 }
674
AddItem(const CFX_WideString & str)675 void CFX_ListCtrl::AddItem(const CFX_WideString& str) {
676 CFX_ListItem* pListItem = new CFX_ListItem();
677 pListItem->SetFontMap(m_pFontMap);
678 pListItem->SetFontSize(m_fFontSize);
679 pListItem->SetText(str);
680 m_aListItems.Add(pListItem);
681 }
682
GetItemEdit(int32_t nIndex) const683 CFX_Edit* CFX_ListCtrl::GetItemEdit(int32_t nIndex) const {
684 if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
685 return pListItem->GetEdit();
686 }
687
688 return nullptr;
689 }
690
GetCount() const691 int32_t CFX_ListCtrl::GetCount() const {
692 return m_aListItems.GetSize();
693 }
694
GetPlateRect() const695 CFX_FloatRect CFX_ListCtrl::GetPlateRect() const {
696 return CFX_ListContainer::GetPlateRect();
697 }
698
GetFontSize() const699 FX_FLOAT CFX_ListCtrl::GetFontSize() const {
700 return m_fFontSize;
701 }
702
GetFirstHeight() const703 FX_FLOAT CFX_ListCtrl::GetFirstHeight() const {
704 if (CFX_ListItem* pListItem = m_aListItems.GetAt(0)) {
705 return pListItem->GetItemHeight();
706 }
707
708 return 1.0f;
709 }
710
GetFirstSelected() const711 int32_t CFX_ListCtrl::GetFirstSelected() const {
712 for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
713 if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
714 if (pListItem->IsSelected())
715 return i;
716 }
717 }
718 return -1;
719 }
720
GetLastSelected() const721 int32_t CFX_ListCtrl::GetLastSelected() const {
722 for (int32_t i = m_aListItems.GetSize() - 1; i >= 0; i--) {
723 if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
724 if (pListItem->IsSelected())
725 return i;
726 }
727 }
728 return -1;
729 }
730
Toupper(FX_WCHAR c) const731 FX_WCHAR CFX_ListCtrl::Toupper(FX_WCHAR c) const {
732 if ((c >= 'a') && (c <= 'z'))
733 c = c - ('a' - 'A');
734 return c;
735 }
736
FindNext(int32_t nIndex,FX_WCHAR nChar) const737 int32_t CFX_ListCtrl::FindNext(int32_t nIndex, FX_WCHAR nChar) const {
738 int32_t nCircleIndex = nIndex;
739
740 for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
741 nCircleIndex++;
742 if (nCircleIndex >= sz)
743 nCircleIndex = 0;
744
745 if (CFX_ListItem* pListItem = m_aListItems.GetAt(nCircleIndex)) {
746 if (Toupper(pListItem->GetFirstChar()) == Toupper(nChar))
747 return nCircleIndex;
748 }
749 }
750
751 return nCircleIndex;
752 }
753
IsItemSelected(int32_t nIndex) const754 bool CFX_ListCtrl::IsItemSelected(int32_t nIndex) const {
755 if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex))
756 return pListItem->IsSelected();
757 return false;
758 }
759
SetItemSelect(int32_t nItemIndex,bool bSelected)760 void CFX_ListCtrl::SetItemSelect(int32_t nItemIndex, bool bSelected) {
761 if (CFX_ListItem* pListItem = m_aListItems.GetAt(nItemIndex)) {
762 pListItem->SetSelect(bSelected);
763 }
764 }
765
SetMultipleSel(bool bMultiple)766 void CFX_ListCtrl::SetMultipleSel(bool bMultiple) {
767 m_bMultiple = bMultiple;
768 }
769
IsMultipleSel() const770 bool CFX_ListCtrl::IsMultipleSel() const {
771 return m_bMultiple;
772 }
773
IsValid(int32_t nItemIndex) const774 bool CFX_ListCtrl::IsValid(int32_t nItemIndex) const {
775 return nItemIndex >= 0 && nItemIndex < m_aListItems.GetSize();
776 }
777
GetItemText(int32_t nIndex) const778 CFX_WideString CFX_ListCtrl::GetItemText(int32_t nIndex) const {
779 if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
780 return pListItem->GetText();
781 }
782
783 return L"";
784 }
785