Home | History | Annotate | Download | only in fxedit
      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 
     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 
     20 CFX_ListItem::~CFX_ListItem() {
     21   IFX_Edit::DelEdit(m_pEdit);
     22 }
     23 
     24 void CFX_ListItem::SetFontMap(IFX_Edit_FontMap* pFontMap) {
     25   if (m_pEdit)
     26     m_pEdit->SetFontMap(pFontMap);
     27 }
     28 
     29 IFX_Edit* CFX_ListItem::GetEdit() const {
     30   return m_pEdit;
     31 }
     32 
     33 IFX_Edit_Iterator* CFX_ListItem::GetIterator() const {
     34   if (m_pEdit)
     35     return m_pEdit->GetIterator();
     36 
     37   return NULL;
     38 }
     39 
     40 void CFX_ListItem::SetRect(const CLST_Rect& rect) {
     41   m_rcListItem = rect;
     42 }
     43 
     44 CLST_Rect CFX_ListItem::GetRect() const {
     45   return m_rcListItem;
     46 }
     47 
     48 FX_BOOL CFX_ListItem::IsSelected() const {
     49   return m_bSelected;
     50 }
     51 
     52 void CFX_ListItem::SetSelect(FX_BOOL bSelected) {
     53   m_bSelected = bSelected;
     54 }
     55 
     56 FX_BOOL CFX_ListItem::IsCaret() const {
     57   return m_bCaret;
     58 }
     59 
     60 void CFX_ListItem::SetCaret(FX_BOOL bCaret) {
     61   m_bCaret = bCaret;
     62 }
     63 
     64 void CFX_ListItem::SetText(const FX_WCHAR* text) {
     65   if (m_pEdit)
     66     m_pEdit->SetText(text);
     67 }
     68 
     69 void CFX_ListItem::SetFontSize(FX_FLOAT fFontSize) {
     70   if (m_pEdit)
     71     m_pEdit->SetFontSize(fFontSize);
     72 }
     73 
     74 FX_FLOAT CFX_ListItem::GetItemHeight() const {
     75   if (m_pEdit)
     76     return m_pEdit->GetContentRect().Height();
     77 
     78   return 0.0f;
     79 }
     80 
     81 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 
     92 CFX_WideString CFX_ListItem::GetText() const {
     93   if (m_pEdit)
     94     return m_pEdit->GetText();
     95 
     96   return L"";
     97 }
     98 
     99 CFX_List::CFX_List()
    100     : m_fFontSize(0.0f), m_pFontMap(NULL), m_bMultiple(FALSE) {}
    101 
    102 CFX_List::~CFX_List() {
    103   Empty();
    104 }
    105 
    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 
    113 void CFX_List::SetFontMap(IFX_Edit_FontMap* pFontMap) {
    114   m_pFontMap = pFontMap;
    115 }
    116 
    117 void CFX_List::SetFontSize(FX_FLOAT fFontSize) {
    118   m_fFontSize = fFontSize;
    119 }
    120 
    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 
    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 
    146 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 
    154 int32_t CFX_List::GetCount() const {
    155   return m_aListItems.GetSize();
    156 }
    157 
    158 CPDF_Rect CFX_List::GetPlateRect() const {
    159   return CFX_ListContainer::GetPlateRect();
    160 }
    161 
    162 CPDF_Rect CFX_List::GetContentRect() const {
    163   return InnerToOuter(CFX_ListContainer::GetContentRect());
    164 }
    165 
    166 FX_FLOAT CFX_List::GetFontSize() const {
    167   return m_fFontSize;
    168 }
    169 
    170 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 
    202 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 
    210 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 
    220 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 
    230 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 
    236 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 
    253 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 
    264 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 
    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 
    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 
    284 void CFX_List::SetMultipleSel(FX_BOOL bMultiple) {
    285   m_bMultiple = bMultiple;
    286 }
    287 
    288 FX_BOOL CFX_List::IsMultipleSel() const {
    289   return m_bMultiple;
    290 }
    291 
    292 FX_BOOL CFX_List::IsValid(int32_t nItemIndex) const {
    293   return nItemIndex >= 0 && nItemIndex < m_aListItems.GetSize();
    294 }
    295 
    296 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 
    304 CPLST_Select::CPLST_Select() {}
    305 
    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 
    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 
    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 
    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 
    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 
    355 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 
    366 FX_BOOL CPLST_Select::IsExist(int32_t nItemIndex) const {
    367   return Find(nItemIndex) >= 0;
    368 }
    369 
    370 int32_t CPLST_Select::GetCount() const {
    371   return m_aItems.GetSize();
    372 }
    373 
    374 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 
    382 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 
    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 
    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 
    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 
    420 CFX_ListCtrl::~CFX_ListCtrl() {}
    421 
    422 void CFX_ListCtrl::SetNotify(IFX_List_Notify* pNotify) {
    423   m_pNotify = pNotify;
    424 }
    425 
    426 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 
    433 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 
    440 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 
    447 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 
    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 
    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 
    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 
    546 void CFX_ListCtrl::OnVK_UP(FX_BOOL bShift, FX_BOOL bCtrl) {
    547   OnVK(IsMultipleSel() ? GetCaret() - 1 : GetSelect() - 1, bShift, bCtrl);
    548 }
    549 
    550 void CFX_ListCtrl::OnVK_DOWN(FX_BOOL bShift, FX_BOOL bCtrl) {
    551   OnVK(IsMultipleSel() ? GetCaret() + 1 : GetSelect() + 1, bShift, bCtrl);
    552 }
    553 
    554 void CFX_ListCtrl::OnVK_LEFT(FX_BOOL bShift, FX_BOOL bCtrl) {
    555   OnVK(0, bShift, bCtrl);
    556 }
    557 
    558 void CFX_ListCtrl::OnVK_RIGHT(FX_BOOL bShift, FX_BOOL bCtrl) {
    559   OnVK(GetCount() - 1, bShift, bCtrl);
    560 }
    561 
    562 void CFX_ListCtrl::OnVK_HOME(FX_BOOL bShift, FX_BOOL bCtrl) {
    563   OnVK(0, bShift, bCtrl);
    564 }
    565 
    566 void CFX_ListCtrl::OnVK_END(FX_BOOL bShift, FX_BOOL bCtrl) {
    567   OnVK(GetCount() - 1, bShift, bCtrl);
    568 }
    569 
    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 
    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 
    589 CPDF_Rect CFX_ListCtrl::GetItemRect(int32_t nIndex) const {
    590   return InToOut(CFX_List::GetItemRect(nIndex));
    591 }
    592 
    593 void CFX_ListCtrl::AddString(const FX_WCHAR* string) {
    594   AddItem(string);
    595   ReArrange(GetCount() - 1);
    596 }
    597 
    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 
    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 
    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 
    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 
    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 
    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 
    703 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 
    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 
    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 
    744 void CFX_ListCtrl::SetScrollPos(const CPDF_Point& point) {
    745   SetScrollPosY(point.y);
    746 }
    747 
    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 
    776 CPDF_Rect CFX_ListCtrl::GetContentRect() const {
    777   return InToOut(CFX_List::GetContentRect());
    778 }
    779 
    780 void CFX_ListCtrl::ReArrange(int32_t nItemIndex) {
    781   CFX_List::ReArrange(nItemIndex);
    782   SetScrollInfo();
    783 }
    784 
    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 
    793 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 
    802 void CFX_ListCtrl::Empty() {
    803   CFX_List::Empty();
    804   InvalidateItem(-1);
    805 }
    806 
    807 void CFX_ListCtrl::Cancel() {
    808   m_aSelItems.DeselectAll();
    809 }
    810 
    811 int32_t CFX_ListCtrl::GetItemIndex(const CPDF_Point& point) const {
    812   return CFX_List::GetItemIndex(OutToIn(point));
    813 }
    814 
    815 CFX_WideString CFX_ListCtrl::GetText() const {
    816   if (IsMultipleSel())
    817     return GetItemText(m_nCaretIndex);
    818   return GetItemText(m_nSelItem);
    819 }
    820