6d48b302697523662b44b9af917c7b5581d7f075
[pdfium.git] / fpdfsdk / src / fxedit / fxet_list.cpp
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 "../../include/fxedit/fxet_stub.h"
8 #include "../../include/fxedit/fxet_edit.h"
9 #include "../../include/fxedit/fxet_list.h"
10
11 /* ------------------------------- CFX_ListItem ---------------------------------- */
12
13 CFX_ListItem::CFX_ListItem() : m_pEdit(NULL),
14         m_bSelected(FALSE),
15         m_bCaret(FALSE),
16         m_rcListItem(0.0f,0.0f,0.0f,0.0f)
17 {
18         m_pEdit = IFX_Edit::NewEdit();
19         ASSERT(m_pEdit != NULL);
20
21         m_pEdit->SetAlignmentV(1);
22         m_pEdit->Initialize();
23 }
24
25 CFX_ListItem::~CFX_ListItem()
26 {
27         IFX_Edit::DelEdit(m_pEdit);
28 }
29
30 void CFX_ListItem::SetFontMap(IFX_Edit_FontMap * pFontMap)
31 {
32         if (m_pEdit)
33                 m_pEdit->SetFontMap(pFontMap);
34 }
35
36 IFX_Edit* CFX_ListItem::GetEdit() const
37 {
38         return m_pEdit;
39 }
40
41 IFX_Edit_Iterator*      CFX_ListItem::GetIterator() const
42 {
43         if (m_pEdit)
44                 return m_pEdit->GetIterator();
45
46         return NULL;
47 }
48
49 void CFX_ListItem::SetRect(const CLST_Rect & rect)
50 {
51         m_rcListItem = rect;
52 }
53
54 CLST_Rect CFX_ListItem::GetRect() const
55 {
56         return m_rcListItem;
57 }
58
59 FX_BOOL CFX_ListItem::IsSelected() const
60 {
61         return m_bSelected;
62 }
63
64 void CFX_ListItem::SetSelect(FX_BOOL bSelected)
65 {
66         m_bSelected = bSelected;
67 }
68
69 FX_BOOL CFX_ListItem::IsCaret() const
70 {
71         return m_bCaret;
72 }
73
74 void CFX_ListItem::SetCaret(FX_BOOL bCaret)
75 {
76         m_bCaret = bCaret;
77 }
78
79 void CFX_ListItem::SetText(const FX_WCHAR* text)
80 {
81         if (m_pEdit)
82                 m_pEdit->SetText(text);
83 }
84
85 void CFX_ListItem::SetFontSize(FX_FLOAT fFontSize)
86 {
87         if (m_pEdit)
88                 m_pEdit->SetFontSize(fFontSize);
89 }
90
91 FX_FLOAT CFX_ListItem::GetItemHeight() const
92 {
93         if (m_pEdit)
94                 return m_pEdit->GetContentRect().Height();
95
96         return 0.0f;
97 }
98
99 FX_WORD CFX_ListItem::GetFirstChar() const
100 {
101         CPVT_Word word;
102
103         if (IFX_Edit_Iterator*  pIterator = GetIterator())
104         {
105                 pIterator->SetAt(1);            
106                 pIterator->GetWord(word);
107         }
108
109         return word.Word;
110 }
111
112 CFX_WideString CFX_ListItem::GetText() const
113 {
114         if (m_pEdit)
115                 return m_pEdit->GetText();
116
117         return L"";
118 }
119
120 /* ------------------------------------ CFX_List --------------------------------- */
121
122 CFX_List::CFX_List() : m_fFontSize(0.0f), m_pFontMap(NULL), m_bMultiple(FALSE)
123 {
124 }
125
126 CFX_List::~CFX_List()
127 {
128         Empty();
129 }
130
131 void CFX_List::Empty()
132 {
133         for (int32_t i=0,sz=m_aListItems.GetSize(); i<sz; i++)
134                 delete m_aListItems.GetAt(i);
135
136         m_aListItems.RemoveAll();
137 }
138
139 void CFX_List::SetFontMap(IFX_Edit_FontMap * pFontMap)
140 {
141         m_pFontMap = pFontMap;
142 }
143
144 void CFX_List::SetFontSize(FX_FLOAT fFontSize)
145 {
146         m_fFontSize = fFontSize;
147 }
148
149 void CFX_List::AddItem(const FX_WCHAR* str)
150 {       
151         if (CFX_ListItem * pListItem = new CFX_ListItem())
152         {
153                 pListItem->SetFontMap(m_pFontMap);
154                 pListItem->SetFontSize(m_fFontSize);
155                 pListItem->SetText(str);
156                 m_aListItems.Add(pListItem);
157         }
158 }
159
160 void CFX_List::ReArrange(int32_t nItemIndex)
161 {
162         FX_FLOAT fPosY = 0.0f;
163
164         if (CFX_ListItem * pPrevItem = m_aListItems.GetAt(nItemIndex - 1))
165                 fPosY = pPrevItem->GetRect().bottom;
166         
167         for (int32_t i=nItemIndex,sz=m_aListItems.GetSize(); i<sz; i++)
168         {
169                 if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))
170                 {
171                         FX_FLOAT fListItemHeight = pListItem->GetItemHeight();
172                         pListItem->SetRect(CLST_Rect(0.0f,fPosY,0.0f,fPosY + fListItemHeight));
173                         fPosY += fListItemHeight;                       
174                 }
175         }
176
177         SetContentRect(CLST_Rect(0.0f,0.0f,0.0f,fPosY));        
178 }
179
180 IFX_Edit * CFX_List::GetItemEdit(int32_t nIndex) const
181 {
182         if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))
183         {
184                 return pListItem->GetEdit();
185         }
186
187         return NULL;
188 }
189
190 int32_t CFX_List::GetCount() const
191 {
192         return m_aListItems.GetSize();
193 }
194
195 CPDF_Rect CFX_List::GetPlateRect() const
196 {
197         return CFX_ListContainer::GetPlateRect();
198 }
199
200 CPDF_Rect CFX_List::GetContentRect() const
201 {
202         return InnerToOuter(CFX_ListContainer::GetContentRect());
203 }
204
205 FX_FLOAT CFX_List::GetFontSize() const
206 {
207         return m_fFontSize;
208 }
209
210 int32_t CFX_List::GetItemIndex(const CPDF_Point & point) const
211 {
212         CPDF_Point pt = OuterToInner(point);
213
214         FX_BOOL bFirst = TRUE;
215         FX_BOOL bLast = TRUE;
216
217         for (int32_t i=0,sz=m_aListItems.GetSize(); i<sz; i++)
218         {
219                 if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))
220                 {
221                         CLST_Rect rcListItem = pListItem->GetRect();
222
223                         if (FX_EDIT_IsFloatBigger(pt.y, rcListItem.top))
224                         {                       
225                                 bFirst = FALSE;
226                         }
227
228                         if (FX_EDIT_IsFloatSmaller(pt.y, rcListItem.bottom))
229                         {
230                                 bLast = FALSE;
231                         }
232
233                         if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom)
234                         {
235                                 return i;
236                         }
237                 }
238         }
239
240         if (bFirst) return 0;
241         if (bLast) return m_aListItems.GetSize()-1;
242
243         return -1;
244 }
245
246 FX_FLOAT CFX_List::GetFirstHeight() const
247 {
248         if (CFX_ListItem * pListItem = m_aListItems.GetAt(0))
249         {
250                 return pListItem->GetItemHeight();
251         }
252
253         return 1.0f;
254 }
255
256 int32_t CFX_List::GetFirstSelected() const
257 {
258         for (int32_t i=0,sz=m_aListItems.GetSize(); i<sz; i++)
259         {
260                 if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))
261                 {
262                         if (pListItem->IsSelected())
263                                 return i;
264                 }
265         }
266         return -1;
267 }
268
269 int32_t CFX_List::GetLastSelected() const
270 {
271         for (int32_t i=m_aListItems.GetSize()-1; i>=0; i--)
272         {
273                 if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))
274                 {
275                         if (pListItem->IsSelected())
276                                 return i;
277                 }
278         }
279         return -1;
280 }
281
282 FX_WCHAR CFX_List::Toupper(FX_WCHAR c) const
283 {
284         if ( (c >= 'a') && (c <= 'z') )
285                 c = c - ('a' - 'A');
286         return c;
287 }
288
289 int32_t CFX_List::FindNext(int32_t nIndex,FX_WCHAR nChar) const
290 {
291         int32_t nCircleIndex = nIndex;
292
293         for (int32_t i=0,sz=m_aListItems.GetSize(); i<sz; i++)
294         {
295                 nCircleIndex ++;
296                 if (nCircleIndex >= sz) nCircleIndex = 0;
297
298                 if (CFX_ListItem * pListItem = m_aListItems.GetAt(nCircleIndex))
299                 {
300                         if (Toupper(pListItem->GetFirstChar()) == Toupper(nChar))
301                                 return nCircleIndex;
302                 }
303         }
304
305         return nCircleIndex;
306 }
307
308 CPDF_Rect CFX_List::GetItemRect(int32_t nIndex) const
309 {
310         if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))
311         {
312                 CPDF_Rect rcItem = pListItem->GetRect();
313                 rcItem.left = 0.0f;
314                 rcItem.right = GetPlateRect().Width();
315                 return InnerToOuter(rcItem);
316         }
317
318         return CPDF_Rect();
319 }
320
321 FX_BOOL CFX_List::IsItemSelected(int32_t nIndex) const
322 {
323         if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))
324         {
325                 return pListItem->IsSelected();
326         }
327
328         return FALSE;
329 }
330
331 void CFX_List::SetItemSelect(int32_t nItemIndex, FX_BOOL bSelected)
332 {
333         if (CFX_ListItem * pListItem = m_aListItems.GetAt(nItemIndex))
334         {
335                 pListItem->SetSelect(bSelected);
336         }
337 }
338
339 void CFX_List::SetItemCaret(int32_t nItemIndex, FX_BOOL bCaret)
340 {
341         if (CFX_ListItem * pListItem = m_aListItems.GetAt(nItemIndex))
342         {
343                 pListItem->SetCaret(bCaret);            
344         }
345 }
346
347 void CFX_List::SetMultipleSel(FX_BOOL bMultiple)
348 {
349         m_bMultiple = bMultiple;
350 }
351
352 FX_BOOL CFX_List::IsMultipleSel() const
353 {
354         return m_bMultiple;
355 }
356
357 FX_BOOL CFX_List::IsValid(int32_t nItemIndex) const
358 {
359         return nItemIndex >= 0 && nItemIndex < m_aListItems.GetSize();
360 }
361
362 CFX_WideString CFX_List::GetItemText(int32_t nIndex) const
363 {
364         if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))
365         {
366                 return pListItem->GetText();
367         }
368
369         return L"";
370 }
371
372 /* ------------------------------------ CPLST_Select ---------------------------------- */
373
374 CPLST_Select::CPLST_Select()
375 {
376 }
377
378 CPLST_Select::~CPLST_Select()
379 {
380         for (int32_t i=0,sz=m_aItems.GetSize(); i<sz; i++)
381                 delete m_aItems.GetAt(i);
382
383         m_aItems.RemoveAll();
384 }
385
386 void CPLST_Select::Add(int32_t nItemIndex)
387 {
388         int32_t nIndex = Find(nItemIndex);
389
390         if (nIndex < 0) 
391                 m_aItems.Add(new CPLST_Select_Item(nItemIndex,1));
392         else
393         {
394                 if (CPLST_Select_Item * pItem = m_aItems.GetAt(nIndex))
395                 {
396                         pItem->nState = 1;
397                 }
398         }
399 }
400
401 void CPLST_Select::Add(int32_t nBeginIndex, int32_t nEndIndex)
402 {
403         if (nBeginIndex > nEndIndex)
404         {
405                 int32_t nTemp = nEndIndex;
406                 nEndIndex = nBeginIndex;
407                 nBeginIndex = nTemp;
408         }
409
410         for (int32_t i=nBeginIndex; i<=nEndIndex; i++)  Add(i);
411 }
412
413 void CPLST_Select::Sub(int32_t nItemIndex)
414 {
415         for (int32_t i=m_aItems.GetSize()-1; i>=0; i--)
416         {
417                 if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))
418                         if (pItem->nItemIndex == nItemIndex)
419                                 pItem->nState = -1;
420         }
421 }
422
423 void CPLST_Select::Sub(int32_t nBeginIndex, int32_t nEndIndex)
424 {
425         if (nBeginIndex > nEndIndex)
426         {
427                 int32_t nTemp = nEndIndex;
428                 nEndIndex = nBeginIndex;
429                 nBeginIndex = nTemp;
430         }
431
432         for (int32_t i=nBeginIndex; i<=nEndIndex; i++)  Sub(i);
433 }
434
435 int32_t CPLST_Select::Find(int32_t nItemIndex) const
436 {
437         for (int32_t i=0,sz=m_aItems.GetSize(); i<sz; i++)
438         {
439                 if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))
440                 {
441                         if (pItem->nItemIndex == nItemIndex)
442                                 return i;
443                 }
444         }
445
446         return -1;
447 }
448
449 FX_BOOL CPLST_Select::IsExist(int32_t nItemIndex) const
450 {
451         return Find(nItemIndex) >= 0;
452 }
453
454 int32_t CPLST_Select::GetCount() const
455 {
456         return m_aItems.GetSize();
457 }
458
459 int32_t CPLST_Select::GetItemIndex(int32_t nIndex) const
460 {
461         if (nIndex >= 0 && nIndex < m_aItems.GetSize())
462                 if (CPLST_Select_Item * pItem = m_aItems.GetAt(nIndex))
463                         return pItem->nItemIndex;
464
465         return -1;
466 }
467
468 int32_t CPLST_Select::GetState(int32_t nIndex) const
469 {
470         if (nIndex >= 0 && nIndex < m_aItems.GetSize())
471                 if (CPLST_Select_Item * pItem = m_aItems.GetAt(nIndex))
472                         return pItem->nState;
473
474         return 0;
475 }
476
477 void CPLST_Select::DeselectAll()
478 {
479         for (int32_t i=0,sz=m_aItems.GetSize(); i<sz; i++)
480         {
481                 if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))
482                 {
483                         pItem->nState = -1;
484                 }
485         }
486 }
487
488 void CPLST_Select::Done()
489 {
490         for (int32_t i=m_aItems.GetSize()-1; i>=0; i--)
491         {       
492                 if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))
493                 {
494                         if (pItem->nState == -1)
495                         {
496                                 delete pItem;
497                                 m_aItems.RemoveAt(i);
498                         }
499                         else
500                         {
501                                 pItem->nState = 0;
502                         }
503                 }
504         }
505 }
506
507 /* ------------------------------------ CFX_ListCtrl --------------------------------- */
508
509 CFX_ListCtrl::CFX_ListCtrl() : m_pNotify(NULL),
510         m_bNotifyFlag(FALSE),
511         m_ptScrollPos(0.0f,0.0f),
512         m_nSelItem(-1),
513         m_nFootIndex(-1),
514         m_bCtrlSel(FALSE),
515         m_nCaretIndex(-1)
516 {
517 }
518
519 CFX_ListCtrl::~CFX_ListCtrl()
520 {
521 }
522
523 void CFX_ListCtrl::SetNotify(IFX_List_Notify * pNotify)
524 {
525         m_pNotify = pNotify;
526 }
527
528 CPDF_Point CFX_ListCtrl::InToOut(const CPDF_Point & point) const
529 {
530         CPDF_Rect rcPlate = GetPlateRect();
531
532         return CPDF_Point(point.x - (m_ptScrollPos.x - rcPlate.left),
533                 point.y - (m_ptScrollPos.y - rcPlate.top));
534 }
535
536 CPDF_Point CFX_ListCtrl::OutToIn(const CPDF_Point & point) const
537 {
538         CPDF_Rect rcPlate = GetPlateRect();
539
540         return CPDF_Point(point.x + (m_ptScrollPos.x - rcPlate.left),
541                 point.y + (m_ptScrollPos.y - rcPlate.top));
542 }
543
544 CPDF_Rect CFX_ListCtrl::InToOut(const CPDF_Rect & rect) const
545 {
546         CPDF_Point ptLeftBottom = InToOut(CPDF_Point(rect.left,rect.bottom));
547         CPDF_Point ptRightTop = InToOut(CPDF_Point(rect.right,rect.top));
548
549         return CPDF_Rect(ptLeftBottom.x,ptLeftBottom.y,ptRightTop.x,ptRightTop.y);
550 }
551
552 CPDF_Rect CFX_ListCtrl::OutToIn(const CPDF_Rect & rect) const
553 {
554         CPDF_Point ptLeftBottom = OutToIn(CPDF_Point(rect.left,rect.bottom));
555         CPDF_Point ptRightTop = OutToIn(CPDF_Point(rect.right,rect.top));
556
557         return CPDF_Rect(ptLeftBottom.x,ptLeftBottom.y,ptRightTop.x,ptRightTop.y);
558 }
559
560 void CFX_ListCtrl::OnMouseDown(const CPDF_Point & point,FX_BOOL bShift,FX_BOOL bCtrl)
561 {
562         int32_t nHitIndex = this->GetItemIndex(point);
563
564         if (IsMultipleSel())
565         {
566                 if (bCtrl)
567                 {
568                         if (IsItemSelected(nHitIndex))
569                         {
570                                 m_aSelItems.Sub(nHitIndex);
571                                 SelectItems();
572                                 m_bCtrlSel = FALSE;
573                         }
574                         else
575                         {
576                                 m_aSelItems.Add(nHitIndex);
577                                 SelectItems();
578                                 m_bCtrlSel = TRUE;
579                         }               
580                         
581                         m_nFootIndex = nHitIndex;
582                 }
583                 else if (bShift)
584                 {
585                         m_aSelItems.DeselectAll();
586                         m_aSelItems.Add(m_nFootIndex,nHitIndex);
587                         SelectItems();
588                 }
589                 else
590                 {
591                         m_aSelItems.DeselectAll();
592                         m_aSelItems.Add(nHitIndex);
593                         SelectItems();
594
595                         m_nFootIndex = nHitIndex;
596                 }
597
598                 SetCaret(nHitIndex);
599         }
600         else
601         {
602                 SetSingleSelect(nHitIndex);
603         }
604
605         if (!this->IsItemVisible(nHitIndex))
606                 this->ScrollToListItem(nHitIndex);
607 }
608
609 void CFX_ListCtrl::OnMouseMove(const CPDF_Point & point,FX_BOOL bShift,FX_BOOL bCtrl)
610 {
611         int32_t nHitIndex = this->GetItemIndex(point);
612
613         if (IsMultipleSel())
614         {                       
615                 if (bCtrl)
616                 {
617                         if (m_bCtrlSel)
618                                 m_aSelItems.Add(m_nFootIndex,nHitIndex);
619                         else
620                                 m_aSelItems.Sub(m_nFootIndex,nHitIndex);                        
621                         
622                         SelectItems();
623                 }
624                 else
625                 {
626                         m_aSelItems.DeselectAll();
627                         m_aSelItems.Add(m_nFootIndex,nHitIndex);
628                         SelectItems();
629                 }
630
631                 SetCaret(nHitIndex);
632         }
633         else
634         {
635                 SetSingleSelect(nHitIndex);
636         }
637
638         if (!this->IsItemVisible(nHitIndex))
639                 this->ScrollToListItem(nHitIndex);
640 }
641
642 void CFX_ListCtrl::OnVK(int32_t nItemIndex,FX_BOOL bShift,FX_BOOL bCtrl)
643 {
644         if (IsMultipleSel())
645         {
646                 if (nItemIndex >= 0 && nItemIndex < GetCount())
647                 {
648                         if (bCtrl)
649                         {
650                         }
651                         else if (bShift)
652                         {
653                                 m_aSelItems.DeselectAll();
654                                 m_aSelItems.Add(m_nFootIndex,nItemIndex);
655                                 SelectItems();
656                         }
657                         else
658                         {
659                                 m_aSelItems.DeselectAll();
660                                 m_aSelItems.Add(nItemIndex);
661                                 SelectItems();
662                                 m_nFootIndex = nItemIndex;
663                         }
664
665                         SetCaret(nItemIndex);   
666                 }
667         }
668         else
669         {
670                 SetSingleSelect(nItemIndex);
671         }
672
673         if (!this->IsItemVisible(nItemIndex))
674                 this->ScrollToListItem(nItemIndex);
675 }
676
677 void CFX_ListCtrl::OnVK_UP(FX_BOOL bShift,FX_BOOL bCtrl)
678 {
679         OnVK(IsMultipleSel() ? GetCaret()-1 : GetSelect()-1, bShift, bCtrl);
680 }
681
682 void CFX_ListCtrl::OnVK_DOWN(FX_BOOL bShift,FX_BOOL bCtrl)
683 {
684         OnVK(IsMultipleSel() ? GetCaret()+1 : GetSelect()+1, bShift, bCtrl);
685 }
686
687 void CFX_ListCtrl::OnVK_LEFT(FX_BOOL bShift,FX_BOOL bCtrl)
688 {
689         OnVK(0, bShift, bCtrl);
690 }
691
692 void CFX_ListCtrl::OnVK_RIGHT(FX_BOOL bShift,FX_BOOL bCtrl)
693 {
694         OnVK(GetCount()-1, bShift, bCtrl);
695 }
696
697 void CFX_ListCtrl::OnVK_HOME(FX_BOOL bShift,FX_BOOL bCtrl)
698 {
699         OnVK(0, bShift, bCtrl);
700 }
701
702 void CFX_ListCtrl::OnVK_END(FX_BOOL bShift,FX_BOOL bCtrl)
703 {
704         OnVK(GetCount()-1, bShift, bCtrl);
705 }
706
707 FX_BOOL CFX_ListCtrl::OnChar(FX_WORD nChar,FX_BOOL bShift,FX_BOOL bCtrl)
708 {
709         int32_t nIndex = GetLastSelected();     
710         int32_t nFindIndex = FindNext(nIndex,nChar);
711
712         if (nFindIndex != nIndex)
713         {
714                 OnVK(nFindIndex, bShift, bCtrl);
715                 return TRUE;
716         }
717         return FALSE;
718 }
719
720 /* -------- inner methods ------- */
721
722 void CFX_ListCtrl::SetPlateRect(const CPDF_Rect & rect)
723 {
724         CFX_ListContainer::SetPlateRect(rect);
725         m_ptScrollPos.x = rect.left;
726         SetScrollPos(CPDF_Point(rect.left,rect.top));   
727         ReArrange(0);
728         InvalidateItem(-1);
729 }
730
731 CPDF_Rect CFX_ListCtrl::GetItemRect(int32_t nIndex) const
732 {
733         return InToOut(CFX_List::GetItemRect(nIndex));
734 }
735
736 void CFX_ListCtrl::AddString(const FX_WCHAR* string)
737 {
738         AddItem(string);
739         ReArrange(GetCount() - 1);
740 }
741
742 void CFX_ListCtrl::SetMultipleSelect(int32_t nItemIndex, FX_BOOL bSelected)
743 {
744         if (!IsValid(nItemIndex)) return;
745
746         if (bSelected != this->IsItemSelected(nItemIndex))
747         {
748                 if (bSelected)
749                 {
750                         SetItemSelect(nItemIndex,TRUE);
751                         InvalidateItem(nItemIndex);
752                 }
753                 else
754                 {
755                         SetItemSelect(nItemIndex,FALSE);
756                         InvalidateItem(nItemIndex);
757                 }
758         }
759 }
760
761 void CFX_ListCtrl::SetSingleSelect(int32_t nItemIndex)
762 {
763         if (!IsValid(nItemIndex)) return;
764
765         if (m_nSelItem != nItemIndex)
766         {
767                 if (m_nSelItem >= 0)
768                 {
769                         SetItemSelect(m_nSelItem,FALSE);
770                         InvalidateItem(m_nSelItem);
771                 }
772                 
773                 SetItemSelect(nItemIndex,TRUE);
774                 InvalidateItem(nItemIndex);
775                 m_nSelItem = nItemIndex;                
776         }
777 }
778
779 void CFX_ListCtrl::SetCaret(int32_t nItemIndex)
780 {
781         if (!IsValid(nItemIndex)) return;
782
783         if (this->IsMultipleSel())
784         {               
785                 int32_t nOldIndex = m_nCaretIndex;
786
787                 if (nOldIndex != nItemIndex)
788                 {
789                         m_nCaretIndex = nItemIndex;
790
791                         SetItemCaret(nOldIndex, FALSE);
792                         SetItemCaret(nItemIndex,TRUE);
793
794                         InvalidateItem(nOldIndex);
795                         InvalidateItem(nItemIndex);                     
796                 }
797         }
798 }
799
800 void CFX_ListCtrl::InvalidateItem(int32_t nItemIndex)
801 {
802         if (m_pNotify)
803         {
804                 if (nItemIndex == -1)
805                 {
806                         if (!m_bNotifyFlag)
807                         {
808                                 m_bNotifyFlag = TRUE;
809                                 CPDF_Rect rcRefresh = GetPlateRect();
810                                 m_pNotify->IOnInvalidateRect(&rcRefresh);
811                                 m_bNotifyFlag = FALSE;
812                         }
813                 }
814                 else
815                 {
816                         if (!m_bNotifyFlag)
817                         {
818                                 m_bNotifyFlag = TRUE;
819                                 CPDF_Rect rcRefresh = GetItemRect(nItemIndex);
820                                 rcRefresh.left -= 1.0f;
821                                 rcRefresh.right += 1.0f;
822                                 rcRefresh.bottom -= 1.0f;
823                                 rcRefresh.top += 1.0f;
824
825                                 m_pNotify->IOnInvalidateRect(&rcRefresh);
826                                 m_bNotifyFlag = FALSE;
827                         }
828                 }
829         }
830 }
831
832 void CFX_ListCtrl::SelectItems()
833 {
834         for (int32_t i=0,sz=m_aSelItems.GetCount(); i<sz; i++)
835         {
836                 int32_t nItemIndex = m_aSelItems.GetItemIndex(i);
837                 int32_t nState = m_aSelItems.GetState(i);
838
839                 switch(nState)
840                 {
841                 case 1:
842                         SetMultipleSelect(nItemIndex, TRUE);                    
843                         break;
844                 case -1:
845                         SetMultipleSelect(nItemIndex, FALSE);
846                         break;
847                 }
848         }
849
850         m_aSelItems.Done();
851 }
852
853 void CFX_ListCtrl::Select(int32_t nItemIndex)
854 {
855         if (!IsValid(nItemIndex)) return;
856
857         if (this->IsMultipleSel())
858         {
859                 m_aSelItems.Add(nItemIndex);
860                 SelectItems();
861         }
862         else
863                 SetSingleSelect(nItemIndex);
864 }
865
866 FX_BOOL CFX_ListCtrl::IsItemVisible(int32_t nItemIndex) const
867 {
868         CPDF_Rect rcPlate = this->GetPlateRect();
869         CPDF_Rect rcItem = this->GetItemRect(nItemIndex);
870
871         return rcItem.bottom >= rcPlate.bottom && rcItem.top <= rcPlate.top;
872 }
873
874 void CFX_ListCtrl::ScrollToListItem(int32_t nItemIndex)
875 {
876         if (!IsValid(nItemIndex)) return;
877
878         CPDF_Rect rcPlate = this->GetPlateRect();
879         CPDF_Rect rcItem = CFX_List::GetItemRect(nItemIndex);
880         CPDF_Rect rcItemCtrl = GetItemRect(nItemIndex);
881
882         if (FX_EDIT_IsFloatSmaller(rcItemCtrl.bottom, rcPlate.bottom))
883         {
884                 if (FX_EDIT_IsFloatSmaller(rcItemCtrl.top, rcPlate.top))
885                 {
886                         SetScrollPosY(rcItem.bottom + rcPlate.Height());
887                 }
888         }
889         else if (FX_EDIT_IsFloatBigger(rcItemCtrl.top, rcPlate.top))
890         {
891                 if (FX_EDIT_IsFloatBigger(rcItemCtrl.bottom, rcPlate.bottom))
892                 {
893                         SetScrollPosY(rcItem.top);
894                 }
895         }
896 }
897
898 void CFX_ListCtrl::SetScrollInfo()
899 {
900         if (m_pNotify)
901         {
902                 CPDF_Rect rcPlate = GetPlateRect();
903                 CPDF_Rect rcContent = CFX_List::GetContentRect();
904
905                 if (!m_bNotifyFlag)
906                 {
907                         m_bNotifyFlag = TRUE;
908                         m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top, 
909                                         rcContent.bottom, rcContent.top, GetFirstHeight(), rcPlate.Height());
910                         m_bNotifyFlag = FALSE;
911                 }
912         }
913 }
914
915 void CFX_ListCtrl::SetScrollPos(const CPDF_Point & point)
916 {
917         SetScrollPosY(point.y);
918 }
919
920 void CFX_ListCtrl::SetScrollPosY(FX_FLOAT fy)
921 {
922         if (!FX_EDIT_IsFloatEqual(m_ptScrollPos.y,fy))
923         {
924                 CPDF_Rect rcPlate = this->GetPlateRect();
925                 CPDF_Rect rcContent = CFX_List::GetContentRect();
926
927                 if (rcPlate.Height() > rcContent.Height())
928                 {
929                         fy = rcPlate.top;
930                 }
931                 else
932                 {
933                         if (FX_EDIT_IsFloatSmaller(fy - rcPlate.Height(), rcContent.bottom))
934                         {
935                                 fy = rcContent.bottom + rcPlate.Height();
936                         }
937                         else if (FX_EDIT_IsFloatBigger(fy, rcContent.top))
938                         {
939                                 fy = rcContent.top;
940                         }
941                 }
942
943                 m_ptScrollPos.y = fy;
944                 InvalidateItem(-1);
945
946                 if (m_pNotify) 
947                 {
948                         if (!m_bNotifyFlag)
949                         {
950                                 m_bNotifyFlag = TRUE;
951                                 m_pNotify->IOnSetScrollPosY(fy);
952                                 m_bNotifyFlag = FALSE;
953                         }
954                 }
955         }
956 }
957
958 CPDF_Rect CFX_ListCtrl::GetContentRect() const
959 {
960         return InToOut(CFX_List::GetContentRect());
961 }
962
963 void CFX_ListCtrl::ReArrange(int32_t nItemIndex)
964 {
965         CFX_List::ReArrange(nItemIndex);
966         SetScrollInfo();
967 }
968
969 void CFX_ListCtrl::SetTopItem(int32_t nIndex)
970 {
971         if (IsValid(nIndex))
972         {
973                 this->GetPlateRect();
974                 CPDF_Rect rcItem = CFX_List::GetItemRect(nIndex);
975                 SetScrollPosY(rcItem.top);
976         }
977 }
978
979 int32_t CFX_ListCtrl::GetTopItem() const
980 {
981         int32_t nItemIndex = this->GetItemIndex(this->GetBTPoint());
982
983         if (!IsItemVisible(nItemIndex) && IsItemVisible(nItemIndex + 1))
984                         nItemIndex += 1;
985
986         return nItemIndex;
987 }
988
989 void CFX_ListCtrl::Empty()
990 {
991         CFX_List::Empty();
992         InvalidateItem(-1);
993 }
994
995 void CFX_ListCtrl::Cancel()
996 {
997         m_aSelItems.DeselectAll();
998 }
999
1000 int32_t CFX_ListCtrl::GetItemIndex(const CPDF_Point & point) const
1001 {
1002         return CFX_List::GetItemIndex(OutToIn(point));
1003 }
1004
1005 CFX_WideString CFX_ListCtrl::GetText() const
1006 {
1007         if (this->IsMultipleSel())
1008                 return this->GetItemText(this->m_nCaretIndex);  
1009         else
1010                 return this->GetItemText(this->m_nSelItem);
1011 }
1012