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