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