Allow external font-path configuration from pdfium_test.
[pdfium.git] / fpdfsdk / src / fxedit / fxet_list.cpp
index dd70e0c..70dc8d5 100644 (file)
-// Copyright 2014 PDFium Authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
\r
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
-\r
-#include "../../include/fxedit/fxet_stub.h"\r
-#include "../../include/fxedit/fxet_edit.h"\r
-#include "../../include/fxedit/fxet_list.h"\r
-\r
-/* ------------------------------- CFX_ListItem ---------------------------------- */\r
-\r
-CFX_ListItem::CFX_ListItem() : m_pEdit(NULL),\r
-       m_bSelected(FALSE),\r
-       m_bCaret(FALSE),\r
-       m_rcListItem(0.0f,0.0f,0.0f,0.0f)\r
-{\r
-       m_pEdit = IFX_Edit::NewEdit();\r
-       ASSERT(m_pEdit != NULL);\r
-\r
-       m_pEdit->SetAlignmentV(1);\r
-       m_pEdit->Initialize();\r
-}\r
-\r
-CFX_ListItem::~CFX_ListItem()\r
-{\r
-       IFX_Edit::DelEdit(m_pEdit);\r
-}\r
-\r
-void CFX_ListItem::SetFontMap(IFX_Edit_FontMap * pFontMap)\r
-{\r
-       if (m_pEdit)\r
-               m_pEdit->SetFontMap(pFontMap);\r
-}\r
-\r
-IFX_Edit* CFX_ListItem::GetEdit() const\r
-{\r
-       return m_pEdit;\r
-}\r
-\r
-IFX_Edit_Iterator*     CFX_ListItem::GetIterator() const\r
-{\r
-       if (m_pEdit)\r
-               return m_pEdit->GetIterator();\r
-\r
-       return NULL;\r
-}\r
-\r
-void CFX_ListItem::SetRect(const CLST_Rect & rect)\r
-{\r
-       m_rcListItem = rect;\r
-}\r
-\r
-CLST_Rect CFX_ListItem::GetRect() const\r
-{\r
-       return m_rcListItem;\r
-}\r
-\r
-FX_BOOL CFX_ListItem::IsSelected() const\r
-{\r
-       return m_bSelected;\r
-}\r
-\r
-void CFX_ListItem::SetSelect(FX_BOOL bSelected)\r
-{\r
-       m_bSelected = bSelected;\r
-}\r
-\r
-FX_BOOL CFX_ListItem::IsCaret() const\r
-{\r
-       return m_bCaret;\r
-}\r
-\r
-void CFX_ListItem::SetCaret(FX_BOOL bCaret)\r
-{\r
-       m_bCaret = bCaret;\r
-}\r
-\r
-void CFX_ListItem::SetText(FX_LPCWSTR text)\r
-{\r
-       if (m_pEdit)\r
-               m_pEdit->SetText(text);\r
-}\r
-\r
-void CFX_ListItem::SetFontSize(FX_FLOAT fFontSize)\r
-{\r
-       if (m_pEdit)\r
-               m_pEdit->SetFontSize(fFontSize);\r
-}\r
-\r
-FX_FLOAT CFX_ListItem::GetItemHeight() const\r
-{\r
-       if (m_pEdit)\r
-               return m_pEdit->GetContentRect().Height();\r
-\r
-       return 0.0f;\r
-}\r
-\r
-FX_WORD CFX_ListItem::GetFirstChar() const\r
-{\r
-       CPVT_Word word;\r
-\r
-       if (IFX_Edit_Iterator*  pIterator = GetIterator())\r
-       {\r
-               pIterator->SetAt(1);            \r
-               pIterator->GetWord(word);\r
-       }\r
-\r
-       return word.Word;\r
-}\r
-\r
-CFX_WideString CFX_ListItem::GetText() const\r
-{\r
-       if (m_pEdit)\r
-               return m_pEdit->GetText();\r
-\r
-       return L"";\r
-}\r
-\r
-/* ------------------------------------ CFX_List --------------------------------- */\r
-\r
-CFX_List::CFX_List() : m_pFontMap(NULL), m_fFontSize(0.0f), m_bMultiple(FALSE) \r
-{\r
-}\r
-\r
-CFX_List::~CFX_List()\r
-{\r
-       Empty();\r
-}\r
-\r
-void CFX_List::Empty()\r
-{\r
-       for (FX_INT32 i=0,sz=m_aListItems.GetSize(); i<sz; i++)\r
-               delete m_aListItems.GetAt(i);\r
-\r
-       m_aListItems.RemoveAll();\r
-}\r
-\r
-void CFX_List::SetFontMap(IFX_Edit_FontMap * pFontMap)\r
-{\r
-       m_pFontMap = pFontMap;\r
-}\r
-\r
-void CFX_List::SetFontSize(FX_FLOAT fFontSize)\r
-{\r
-       m_fFontSize = fFontSize;\r
-}\r
-\r
-void CFX_List::AddItem(FX_LPCWSTR str)\r
-{      \r
-       if (CFX_ListItem * pListItem = new CFX_ListItem())\r
-       {\r
-               pListItem->SetFontMap(m_pFontMap);\r
-               pListItem->SetFontSize(m_fFontSize);\r
-               pListItem->SetText(str);\r
-               m_aListItems.Add(pListItem);\r
-       }\r
-}\r
-\r
-void CFX_List::ReArrange(FX_INT32 nItemIndex)\r
-{\r
-       FX_FLOAT fPosY = 0.0f;\r
-\r
-       if (CFX_ListItem * pPrevItem = m_aListItems.GetAt(nItemIndex - 1))\r
-               fPosY = pPrevItem->GetRect().bottom;\r
-       \r
-       for (FX_INT32 i=nItemIndex,sz=m_aListItems.GetSize(); i<sz; i++)\r
-       {\r
-               if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))\r
-               {\r
-                       FX_FLOAT fListItemHeight = pListItem->GetItemHeight();\r
-                       pListItem->SetRect(CLST_Rect(0.0f,fPosY,0.0f,fPosY + fListItemHeight));\r
-                       fPosY += fListItemHeight;                       \r
-               }\r
-       }\r
-\r
-       SetContentRect(CLST_Rect(0.0f,0.0f,0.0f,fPosY));        \r
-}\r
-\r
-IFX_Edit * CFX_List::GetItemEdit(FX_INT32 nIndex) const\r
-{\r
-       if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))\r
-       {\r
-               return pListItem->GetEdit();\r
-       }\r
-\r
-       return NULL;\r
-}\r
-\r
-FX_INT32 CFX_List::GetCount() const\r
-{\r
-       return m_aListItems.GetSize();\r
-}\r
-\r
-CPDF_Rect CFX_List::GetPlateRect() const\r
-{\r
-       return CFX_ListContainer::GetPlateRect();\r
-}\r
-\r
-CPDF_Rect CFX_List::GetContentRect() const\r
-{\r
-       return InnerToOuter(CFX_ListContainer::GetContentRect());\r
-}\r
-\r
-FX_FLOAT CFX_List::GetFontSize() const\r
-{\r
-       return m_fFontSize;\r
-}\r
-\r
-FX_INT32 CFX_List::GetItemIndex(const CPDF_Point & point) const\r
-{\r
-       CPDF_Point pt = OuterToInner(point);\r
-\r
-       FX_BOOL bFirst = TRUE;\r
-       FX_BOOL bLast = TRUE;\r
-\r
-       for (FX_INT32 i=0,sz=m_aListItems.GetSize(); i<sz; i++)\r
-       {\r
-               if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))\r
-               {\r
-                       CLST_Rect rcListItem = pListItem->GetRect();\r
-\r
-                       if (FX_EDIT_IsFloatBigger(pt.y, rcListItem.top))\r
-                       {                       \r
-                               bFirst = FALSE;\r
-                       }\r
-\r
-                       if (FX_EDIT_IsFloatSmaller(pt.y, rcListItem.bottom))\r
-                       {\r
-                               bLast = FALSE;\r
-                       }\r
-\r
-                       if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom)\r
-                       {\r
-                               return i;\r
-                       }\r
-               }\r
-       }\r
-\r
-       if (bFirst) return 0;\r
-       if (bLast) return m_aListItems.GetSize()-1;\r
-\r
-       return -1;\r
-}\r
-\r
-FX_FLOAT CFX_List::GetFirstHeight() const\r
-{\r
-       if (CFX_ListItem * pListItem = m_aListItems.GetAt(0))\r
-       {\r
-               return pListItem->GetItemHeight();\r
-       }\r
-\r
-       return 1.0f;\r
-}\r
-\r
-FX_INT32 CFX_List::GetFirstSelected() const\r
-{\r
-       for (FX_INT32 i=0,sz=m_aListItems.GetSize(); i<sz; i++)\r
-       {\r
-               if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))\r
-               {\r
-                       if (pListItem->IsSelected())\r
-                               return i;\r
-               }\r
-       }\r
-       return -1;\r
-}\r
-\r
-FX_INT32 CFX_List::GetLastSelected() const\r
-{\r
-       for (FX_INT32 i=m_aListItems.GetSize()-1; i>=0; i--)\r
-       {\r
-               if (CFX_ListItem * pListItem = m_aListItems.GetAt(i))\r
-               {\r
-                       if (pListItem->IsSelected())\r
-                               return i;\r
-               }\r
-       }\r
-       return -1;\r
-}\r
-\r
-FX_WCHAR CFX_List::Toupper(FX_WCHAR c) const\r
-{\r
-       if ( (c >= 'a') && (c <= 'z') )\r
-               c = c - ('a' - 'A');\r
-       return c;\r
-}\r
-\r
-FX_INT32 CFX_List::FindNext(FX_INT32 nIndex,FX_WCHAR nChar) const\r
-{\r
-       FX_INT32 nCircleIndex = nIndex;\r
-\r
-       for (FX_INT32 i=0,sz=m_aListItems.GetSize(); i<sz; i++)\r
-       {\r
-               nCircleIndex ++;\r
-               if (nCircleIndex >= sz) nCircleIndex = 0;\r
-\r
-               if (CFX_ListItem * pListItem = m_aListItems.GetAt(nCircleIndex))\r
-               {\r
-                       if (Toupper(pListItem->GetFirstChar()) == Toupper(nChar))\r
-                               return nCircleIndex;\r
-               }\r
-       }\r
-\r
-       return nCircleIndex;\r
-}\r
-\r
-CPDF_Rect CFX_List::GetItemRect(FX_INT32 nIndex) const\r
-{\r
-       if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))\r
-       {\r
-               CPDF_Rect rcItem = pListItem->GetRect();\r
-               rcItem.left = 0.0f;\r
-               rcItem.right = GetPlateRect().Width();\r
-               return InnerToOuter(rcItem);\r
-       }\r
-\r
-       return CPDF_Rect();\r
-}\r
-\r
-FX_BOOL CFX_List::IsItemSelected(FX_INT32 nIndex) const\r
-{\r
-       if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))\r
-       {\r
-               return pListItem->IsSelected();\r
-       }\r
-\r
-       return FALSE;\r
-}\r
-\r
-void CFX_List::SetItemSelect(FX_INT32 nItemIndex, FX_BOOL bSelected)\r
-{\r
-       if (CFX_ListItem * pListItem = m_aListItems.GetAt(nItemIndex))\r
-       {\r
-               pListItem->SetSelect(bSelected);\r
-       }\r
-}\r
-\r
-void CFX_List::SetItemCaret(FX_INT32 nItemIndex, FX_BOOL bCaret)\r
-{\r
-       if (CFX_ListItem * pListItem = m_aListItems.GetAt(nItemIndex))\r
-       {\r
-               pListItem->SetCaret(bCaret);            \r
-       }\r
-}\r
-\r
-void CFX_List::SetMultipleSel(FX_BOOL bMultiple)\r
-{\r
-       m_bMultiple = bMultiple;\r
-}\r
-\r
-FX_BOOL CFX_List::IsMultipleSel() const\r
-{\r
-       return m_bMultiple;\r
-}\r
-\r
-FX_BOOL CFX_List::IsValid(FX_INT32 nItemIndex) const\r
-{\r
-       return nItemIndex >= 0 && nItemIndex < m_aListItems.GetSize();\r
-}\r
-\r
-CFX_WideString CFX_List::GetItemText(FX_INT32 nIndex) const\r
-{\r
-       if (CFX_ListItem * pListItem = m_aListItems.GetAt(nIndex))\r
-       {\r
-               return pListItem->GetText();\r
-       }\r
-\r
-       return L"";\r
-}\r
-\r
-/* ------------------------------------ CPLST_Select ---------------------------------- */\r
-\r
-CPLST_Select::CPLST_Select()\r
-{\r
-}\r
-\r
-CPLST_Select::~CPLST_Select()\r
-{\r
-       for (FX_INT32 i=0,sz=m_aItems.GetSize(); i<sz; i++)\r
-               delete m_aItems.GetAt(i);\r
-\r
-       m_aItems.RemoveAll();\r
-}\r
-\r
-void CPLST_Select::Add(FX_INT32 nItemIndex)\r
-{\r
-       FX_INT32 nIndex = Find(nItemIndex);\r
-\r
-       if (nIndex < 0) \r
-               m_aItems.Add(new CPLST_Select_Item(nItemIndex,1));\r
-       else\r
-       {\r
-               if (CPLST_Select_Item * pItem = m_aItems.GetAt(nIndex))\r
-               {\r
-                       pItem->nState = 1;\r
-               }\r
-       }\r
-}\r
-\r
-void CPLST_Select::Add(FX_INT32 nBeginIndex, FX_INT32 nEndIndex)\r
-{\r
-       if (nBeginIndex > nEndIndex)\r
-       {\r
-               FX_INT32 nTemp = nEndIndex;\r
-               nEndIndex = nBeginIndex;\r
-               nBeginIndex = nTemp;\r
-       }\r
-\r
-       for (FX_INT32 i=nBeginIndex; i<=nEndIndex; i++) Add(i);\r
-}\r
-\r
-void CPLST_Select::Sub(FX_INT32 nItemIndex)\r
-{\r
-       for (FX_INT32 i=m_aItems.GetSize()-1; i>=0; i--)\r
-       {\r
-               if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))\r
-                       if (pItem->nItemIndex == nItemIndex)\r
-                               pItem->nState = -1;\r
-       }\r
-}\r
-\r
-void CPLST_Select::Sub(FX_INT32 nBeginIndex, FX_INT32 nEndIndex)\r
-{\r
-       if (nBeginIndex > nEndIndex)\r
-       {\r
-               FX_INT32 nTemp = nEndIndex;\r
-               nEndIndex = nBeginIndex;\r
-               nBeginIndex = nTemp;\r
-       }\r
-\r
-       for (FX_INT32 i=nBeginIndex; i<=nEndIndex; i++) Sub(i);\r
-}\r
-\r
-FX_INT32 CPLST_Select::Find(FX_INT32 nItemIndex) const\r
-{\r
-       for (FX_INT32 i=0,sz=m_aItems.GetSize(); i<sz; i++)\r
-       {\r
-               if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))\r
-               {\r
-                       if (pItem->nItemIndex == nItemIndex)\r
-                               return i;\r
-               }\r
-       }\r
-\r
-       return -1;\r
-}\r
-\r
-FX_BOOL CPLST_Select::IsExist(FX_INT32 nItemIndex) const\r
-{\r
-       return Find(nItemIndex) >= 0;\r
-}\r
-\r
-FX_INT32 CPLST_Select::GetCount() const\r
-{\r
-       return m_aItems.GetSize();\r
-}\r
-\r
-FX_INT32 CPLST_Select::GetItemIndex(FX_INT32 nIndex) const\r
-{\r
-       if (nIndex >= 0 && nIndex < m_aItems.GetSize())\r
-               if (CPLST_Select_Item * pItem = m_aItems.GetAt(nIndex))\r
-                       return pItem->nItemIndex;\r
-\r
-       return -1;\r
-}\r
-\r
-FX_INT32 CPLST_Select::GetState(FX_INT32 nIndex) const\r
-{\r
-       if (nIndex >= 0 && nIndex < m_aItems.GetSize())\r
-               if (CPLST_Select_Item * pItem = m_aItems.GetAt(nIndex))\r
-                       return pItem->nState;\r
-\r
-       return 0;\r
-}\r
-\r
-void CPLST_Select::DeselectAll()\r
-{\r
-       for (FX_INT32 i=0,sz=m_aItems.GetSize(); i<sz; i++)\r
-       {\r
-               if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))\r
-               {\r
-                       pItem->nState = -1;\r
-               }\r
-       }\r
-}\r
-\r
-void CPLST_Select::Done()\r
-{\r
-       for (FX_INT32 i=m_aItems.GetSize()-1; i>=0; i--)\r
-       {       \r
-               if (CPLST_Select_Item * pItem = m_aItems.GetAt(i))\r
-               {\r
-                       if (pItem->nState == -1)\r
-                       {\r
-                               delete pItem;\r
-                               m_aItems.RemoveAt(i);\r
-                       }\r
-                       else\r
-                       {\r
-                               pItem->nState = 0;\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-/* ------------------------------------ CFX_ListCtrl --------------------------------- */\r
-\r
-CFX_ListCtrl::CFX_ListCtrl() : m_pNotify(NULL),\r
-       m_ptScrollPos(0.0f,0.0f),\r
-       m_nSelItem(-1),\r
-       m_nFootIndex(-1),\r
-       m_bCtrlSel(FALSE),      \r
-       m_nCaretIndex(-1),\r
-       m_bNotifyFlag(FALSE)\r
-{\r
-}\r
-\r
-CFX_ListCtrl::~CFX_ListCtrl()\r
-{\r
-}\r
-\r
-void CFX_ListCtrl::SetNotify(IFX_List_Notify * pNotify)\r
-{\r
-       m_pNotify = pNotify;\r
-}\r
-\r
-CPDF_Point CFX_ListCtrl::InToOut(const CPDF_Point & point) const\r
-{\r
-       CPDF_Rect rcPlate = GetPlateRect();\r
-\r
-       return CPDF_Point(point.x - (m_ptScrollPos.x - rcPlate.left),\r
-               point.y - (m_ptScrollPos.y - rcPlate.top));\r
-}\r
-\r
-CPDF_Point CFX_ListCtrl::OutToIn(const CPDF_Point & point) const\r
-{\r
-       CPDF_Rect rcPlate = GetPlateRect();\r
-\r
-       return CPDF_Point(point.x + (m_ptScrollPos.x - rcPlate.left),\r
-               point.y + (m_ptScrollPos.y - rcPlate.top));\r
-}\r
-\r
-CPDF_Rect CFX_ListCtrl::InToOut(const CPDF_Rect & rect) const\r
-{\r
-       CPDF_Point ptLeftBottom = InToOut(CPDF_Point(rect.left,rect.bottom));\r
-       CPDF_Point ptRightTop = InToOut(CPDF_Point(rect.right,rect.top));\r
-\r
-       return CPDF_Rect(ptLeftBottom.x,ptLeftBottom.y,ptRightTop.x,ptRightTop.y);\r
-}\r
-\r
-CPDF_Rect CFX_ListCtrl::OutToIn(const CPDF_Rect & rect) const\r
-{\r
-       CPDF_Point ptLeftBottom = OutToIn(CPDF_Point(rect.left,rect.bottom));\r
-       CPDF_Point ptRightTop = OutToIn(CPDF_Point(rect.right,rect.top));\r
-\r
-       return CPDF_Rect(ptLeftBottom.x,ptLeftBottom.y,ptRightTop.x,ptRightTop.y);\r
-}\r
-\r
-void CFX_ListCtrl::OnMouseDown(const CPDF_Point & point,FX_BOOL bShift,FX_BOOL bCtrl)\r
-{\r
-       FX_INT32 nHitIndex = this->GetItemIndex(point);\r
-\r
-       if (IsMultipleSel())\r
-       {\r
-               if (bCtrl)\r
-               {\r
-                       if (IsItemSelected(nHitIndex))\r
-                       {\r
-                               m_aSelItems.Sub(nHitIndex);\r
-                               SelectItems();\r
-                               m_bCtrlSel = FALSE;\r
-                       }\r
-                       else\r
-                       {\r
-                               m_aSelItems.Add(nHitIndex);\r
-                               SelectItems();\r
-                               m_bCtrlSel = TRUE;\r
-                       }               \r
-                       \r
-                       m_nFootIndex = nHitIndex;\r
-               }\r
-               else if (bShift)\r
-               {\r
-                       m_aSelItems.DeselectAll();\r
-                       m_aSelItems.Add(m_nFootIndex,nHitIndex);\r
-                       SelectItems();\r
-               }\r
-               else\r
-               {\r
-                       m_aSelItems.DeselectAll();\r
-                       m_aSelItems.Add(nHitIndex);\r
-                       SelectItems();\r
-\r
-                       m_nFootIndex = nHitIndex;\r
-               }\r
-\r
-               SetCaret(nHitIndex);\r
-       }\r
-       else\r
-       {\r
-               SetSingleSelect(nHitIndex);\r
-       }\r
-\r
-       if (!this->IsItemVisible(nHitIndex))\r
-               this->ScrollToListItem(nHitIndex);\r
-}\r
-\r
-void CFX_ListCtrl::OnMouseMove(const CPDF_Point & point,FX_BOOL bShift,FX_BOOL bCtrl)\r
-{\r
-       FX_INT32 nHitIndex = this->GetItemIndex(point);\r
-\r
-       if (IsMultipleSel())\r
-       {                       \r
-               if (bCtrl)\r
-               {\r
-                       if (m_bCtrlSel)\r
-                               m_aSelItems.Add(m_nFootIndex,nHitIndex);\r
-                       else\r
-                               m_aSelItems.Sub(m_nFootIndex,nHitIndex);                        \r
-                       \r
-                       SelectItems();\r
-               }\r
-               else\r
-               {\r
-                       m_aSelItems.DeselectAll();\r
-                       m_aSelItems.Add(m_nFootIndex,nHitIndex);\r
-                       SelectItems();\r
-               }\r
-\r
-               SetCaret(nHitIndex);\r
-       }\r
-       else\r
-       {\r
-               SetSingleSelect(nHitIndex);\r
-       }\r
-\r
-       if (!this->IsItemVisible(nHitIndex))\r
-               this->ScrollToListItem(nHitIndex);\r
-}\r
-\r
-void CFX_ListCtrl::OnVK(FX_INT32 nItemIndex,FX_BOOL bShift,FX_BOOL bCtrl)\r
-{\r
-       if (IsMultipleSel())\r
-       {\r
-               if (nItemIndex >= 0 && nItemIndex < GetCount())\r
-               {\r
-                       if (bCtrl)\r
-                       {\r
-                       }\r
-                       else if (bShift)\r
-                       {\r
-                               m_aSelItems.DeselectAll();\r
-                               m_aSelItems.Add(m_nFootIndex,nItemIndex);\r
-                               SelectItems();\r
-                       }\r
-                       else\r
-                       {\r
-                               m_aSelItems.DeselectAll();\r
-                               m_aSelItems.Add(nItemIndex);\r
-                               SelectItems();\r
-                               m_nFootIndex = nItemIndex;\r
-                       }\r
-\r
-                       SetCaret(nItemIndex);   \r
-               }\r
-       }\r
-       else\r
-       {\r
-               SetSingleSelect(nItemIndex);\r
-       }\r
-\r
-       if (!this->IsItemVisible(nItemIndex))\r
-               this->ScrollToListItem(nItemIndex);\r
-}\r
-\r
-void CFX_ListCtrl::OnVK_UP(FX_BOOL bShift,FX_BOOL bCtrl)\r
-{\r
-       OnVK(IsMultipleSel() ? GetCaret()-1 : GetSelect()-1, bShift, bCtrl);\r
-}\r
-\r
-void CFX_ListCtrl::OnVK_DOWN(FX_BOOL bShift,FX_BOOL bCtrl)\r
-{\r
-       OnVK(IsMultipleSel() ? GetCaret()+1 : GetSelect()+1, bShift, bCtrl);\r
-}\r
-\r
-void CFX_ListCtrl::OnVK_LEFT(FX_BOOL bShift,FX_BOOL bCtrl)\r
-{\r
-       OnVK(0, bShift, bCtrl);\r
-}\r
-\r
-void CFX_ListCtrl::OnVK_RIGHT(FX_BOOL bShift,FX_BOOL bCtrl)\r
-{\r
-       OnVK(GetCount()-1, bShift, bCtrl);\r
-}\r
-\r
-void CFX_ListCtrl::OnVK_HOME(FX_BOOL bShift,FX_BOOL bCtrl)\r
-{\r
-       OnVK(0, bShift, bCtrl);\r
-}\r
-\r
-void CFX_ListCtrl::OnVK_END(FX_BOOL bShift,FX_BOOL bCtrl)\r
-{\r
-       OnVK(GetCount()-1, bShift, bCtrl);\r
-}\r
-\r
-FX_BOOL        CFX_ListCtrl::OnChar(FX_WORD nChar,FX_BOOL bShift,FX_BOOL bCtrl)\r
-{\r
-       FX_INT32 nIndex = GetLastSelected();    \r
-       FX_INT32 nFindIndex = FindNext(nIndex,nChar);\r
-\r
-       if (nFindIndex != nIndex)\r
-       {\r
-               OnVK(nFindIndex, bShift, bCtrl);\r
-               return TRUE;\r
-       }\r
-       return FALSE;\r
-}\r
-\r
-/* -------- inner methods ------- */\r
-\r
-void CFX_ListCtrl::SetPlateRect(const CPDF_Rect & rect)\r
-{\r
-       CFX_ListContainer::SetPlateRect(rect);\r
-       m_ptScrollPos.x = rect.left;\r
-       SetScrollPos(CPDF_Point(rect.left,rect.top));   \r
-       ReArrange(0);\r
-       InvalidateItem(-1);\r
-}\r
-\r
-CPDF_Rect CFX_ListCtrl::GetItemRect(FX_INT32 nIndex) const\r
-{\r
-       return InToOut(CFX_List::GetItemRect(nIndex));\r
-}\r
-\r
-void CFX_ListCtrl::AddString(FX_LPCWSTR string)\r
-{\r
-       AddItem(string);\r
-       ReArrange(GetCount() - 1);\r
-}\r
-\r
-void CFX_ListCtrl::SetMultipleSelect(FX_INT32 nItemIndex, FX_BOOL bSelected)\r
-{\r
-       if (!IsValid(nItemIndex)) return;\r
-\r
-       if (bSelected != this->IsItemSelected(nItemIndex))\r
-       {\r
-               if (bSelected)\r
-               {\r
-                       SetItemSelect(nItemIndex,TRUE);\r
-                       InvalidateItem(nItemIndex);\r
-               }\r
-               else\r
-               {\r
-                       SetItemSelect(nItemIndex,FALSE);\r
-                       InvalidateItem(nItemIndex);\r
-               }\r
-       }\r
-}\r
-\r
-void CFX_ListCtrl::SetSingleSelect(FX_INT32 nItemIndex)\r
-{\r
-       if (!IsValid(nItemIndex)) return;\r
-\r
-       if (m_nSelItem != nItemIndex)\r
-       {\r
-               if (m_nSelItem >= 0)\r
-               {\r
-                       SetItemSelect(m_nSelItem,FALSE);\r
-                       InvalidateItem(m_nSelItem);\r
-               }\r
-               \r
-               SetItemSelect(nItemIndex,TRUE);\r
-               InvalidateItem(nItemIndex);\r
-               m_nSelItem = nItemIndex;                \r
-       }\r
-}\r
-\r
-void CFX_ListCtrl::SetCaret(FX_INT32 nItemIndex)\r
-{\r
-       if (!IsValid(nItemIndex)) return;\r
-\r
-       if (this->IsMultipleSel())\r
-       {               \r
-               FX_INT32 nOldIndex = m_nCaretIndex;\r
-\r
-               if (nOldIndex != nItemIndex)\r
-               {\r
-                       m_nCaretIndex = nItemIndex;\r
-\r
-                       SetItemCaret(nOldIndex, FALSE);\r
-                       SetItemCaret(nItemIndex,TRUE);\r
-\r
-                       InvalidateItem(nOldIndex);\r
-                       InvalidateItem(nItemIndex);                     \r
-               }\r
-       }\r
-}\r
-\r
-void CFX_ListCtrl::InvalidateItem(FX_INT32 nItemIndex)\r
-{\r
-       if (m_pNotify)\r
-       {\r
-               if (nItemIndex == -1)\r
-               {\r
-                       if (!m_bNotifyFlag)\r
-                       {\r
-                               m_bNotifyFlag = TRUE;\r
-                               CPDF_Rect rcRefresh = GetPlateRect();\r
-                               m_pNotify->IOnInvalidateRect(&rcRefresh);\r
-                               m_bNotifyFlag = FALSE;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       if (!m_bNotifyFlag)\r
-                       {\r
-                               m_bNotifyFlag = TRUE;\r
-                               CPDF_Rect rcRefresh = GetItemRect(nItemIndex);\r
-                               rcRefresh.left -= 1.0f;\r
-                               rcRefresh.right += 1.0f;\r
-                               rcRefresh.bottom -= 1.0f;\r
-                               rcRefresh.top += 1.0f;\r
-\r
-                               m_pNotify->IOnInvalidateRect(&rcRefresh);\r
-                               m_bNotifyFlag = FALSE;\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-void CFX_ListCtrl::SelectItems()\r
-{\r
-       for (FX_INT32 i=0,sz=m_aSelItems.GetCount(); i<sz; i++)\r
-       {\r
-               FX_INT32 nItemIndex = m_aSelItems.GetItemIndex(i);\r
-               FX_INT32 nState = m_aSelItems.GetState(i);\r
-\r
-               switch(nState)\r
-               {\r
-               case 1:\r
-                       SetMultipleSelect(nItemIndex, TRUE);                    \r
-                       break;\r
-               case -1:\r
-                       SetMultipleSelect(nItemIndex, FALSE);\r
-                       break;\r
-               }\r
-       }\r
-\r
-       m_aSelItems.Done();\r
-}\r
-\r
-void CFX_ListCtrl::Select(FX_INT32 nItemIndex)\r
-{\r
-       if (!IsValid(nItemIndex)) return;\r
-\r
-       if (this->IsMultipleSel())\r
-       {\r
-               m_aSelItems.Add(nItemIndex);\r
-               SelectItems();\r
-       }\r
-       else\r
-               SetSingleSelect(nItemIndex);\r
-}\r
-\r
-FX_BOOL        CFX_ListCtrl::IsItemVisible(FX_INT32 nItemIndex) const\r
-{\r
-       CPDF_Rect rcPlate = this->GetPlateRect();\r
-       CPDF_Rect rcItem = this->GetItemRect(nItemIndex);\r
-\r
-       return rcItem.bottom >= rcPlate.bottom && rcItem.top <= rcPlate.top;\r
-}\r
-\r
-void CFX_ListCtrl::ScrollToListItem(FX_INT32 nItemIndex)\r
-{\r
-       if (!IsValid(nItemIndex)) return;\r
-\r
-       CPDF_Rect rcPlate = this->GetPlateRect();\r
-       CPDF_Rect rcItem = CFX_List::GetItemRect(nItemIndex);\r
-       CPDF_Rect rcItemCtrl = GetItemRect(nItemIndex);\r
-\r
-       if (FX_EDIT_IsFloatSmaller(rcItemCtrl.bottom, rcPlate.bottom))\r
-       {\r
-               if (FX_EDIT_IsFloatSmaller(rcItemCtrl.top, rcPlate.top))\r
-               {\r
-                       SetScrollPosY(rcItem.bottom + rcPlate.Height());\r
-               }\r
-       }\r
-       else if (FX_EDIT_IsFloatBigger(rcItemCtrl.top, rcPlate.top))\r
-       {\r
-               if (FX_EDIT_IsFloatBigger(rcItemCtrl.bottom, rcPlate.bottom))\r
-               {\r
-                       SetScrollPosY(rcItem.top);\r
-               }\r
-       }\r
-}\r
-\r
-void CFX_ListCtrl::SetScrollInfo()\r
-{\r
-       if (m_pNotify)\r
-       {\r
-               CPDF_Rect rcPlate = GetPlateRect();\r
-               CPDF_Rect rcContent = CFX_List::GetContentRect();\r
-\r
-               if (!m_bNotifyFlag)\r
-               {\r
-                       m_bNotifyFlag = TRUE;\r
-                       m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top, \r
-                                       rcContent.bottom, rcContent.top, GetFirstHeight(), rcPlate.Height());\r
-                       m_bNotifyFlag = FALSE;\r
-               }\r
-       }\r
-}\r
-\r
-void CFX_ListCtrl::SetScrollPos(const CPDF_Point & point)\r
-{\r
-       SetScrollPosY(point.y);\r
-}\r
-\r
-void CFX_ListCtrl::SetScrollPosY(FX_FLOAT fy)\r
-{\r
-       if (!FX_EDIT_IsFloatEqual(m_ptScrollPos.y,fy))\r
-       {\r
-               CPDF_Rect rcPlate = this->GetPlateRect();\r
-               CPDF_Rect rcContent = CFX_List::GetContentRect();\r
-\r
-               if (rcPlate.Height() > rcContent.Height())\r
-               {\r
-                       fy = rcPlate.top;\r
-               }\r
-               else\r
-               {\r
-                       if (FX_EDIT_IsFloatSmaller(fy - rcPlate.Height(), rcContent.bottom))\r
-                       {\r
-                               fy = rcContent.bottom + rcPlate.Height();\r
-                       }\r
-                       else if (FX_EDIT_IsFloatBigger(fy, rcContent.top))\r
-                       {\r
-                               fy = rcContent.top;\r
-                       }\r
-               }\r
-\r
-               m_ptScrollPos.y = fy;\r
-               InvalidateItem(-1);\r
-\r
-               if (m_pNotify) \r
-               {\r
-                       if (!m_bNotifyFlag)\r
-                       {\r
-                               m_bNotifyFlag = TRUE;\r
-                               m_pNotify->IOnSetScrollPosY(fy);\r
-                               m_bNotifyFlag = FALSE;\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-CPDF_Rect CFX_ListCtrl::GetContentRect() const\r
-{\r
-       return InToOut(CFX_List::GetContentRect());\r
-}\r
-\r
-void CFX_ListCtrl::ReArrange(FX_INT32 nItemIndex)\r
-{\r
-       CFX_List::ReArrange(nItemIndex);\r
-       SetScrollInfo();\r
-}\r
-\r
-void CFX_ListCtrl::SetTopItem(FX_INT32 nIndex)\r
-{\r
-       if (IsValid(nIndex))\r
-       {\r
-               this->GetPlateRect();\r
-               CPDF_Rect rcItem = CFX_List::GetItemRect(nIndex);\r
-               SetScrollPosY(rcItem.top);\r
-       }\r
-}\r
-\r
-FX_INT32 CFX_ListCtrl::GetTopItem() const\r
-{\r
-       FX_INT32 nItemIndex = this->GetItemIndex(this->GetBTPoint());\r
-\r
-       if (!IsItemVisible(nItemIndex) && IsItemVisible(nItemIndex + 1))\r
-                       nItemIndex += 1;\r
-\r
-       return nItemIndex;\r
-}\r
-\r
-void CFX_ListCtrl::Empty()\r
-{\r
-       CFX_List::Empty();\r
-       InvalidateItem(-1);\r
-}\r
-\r
-void CFX_ListCtrl::Cancel()\r
-{\r
-       m_aSelItems.DeselectAll();\r
-}\r
-\r
-FX_INT32 CFX_ListCtrl::GetItemIndex(const CPDF_Point & point) const\r
-{\r
-       return CFX_List::GetItemIndex(OutToIn(point));\r
-}\r
-\r
-CFX_WideString CFX_ListCtrl::GetText() const\r
-{\r
-       if (this->IsMultipleSel())\r
-               return this->GetItemText(this->m_nCaretIndex);  \r
-       else\r
-               return this->GetItemText(this->m_nSelItem);\r
-}\r
-\r
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "../../include/fxedit/fxet_stub.h"
+#include "../../include/fxedit/fxet_edit.h"
+#include "../../include/fxedit/fxet_list.h"
+
+/* ------------------------------- CFX_ListItem
+ * ---------------------------------- */
+
+CFX_ListItem::CFX_ListItem()
+    : m_pEdit(NULL),
+      m_bSelected(FALSE),
+      m_bCaret(FALSE),
+      m_rcListItem(0.0f, 0.0f, 0.0f, 0.0f) {
+  m_pEdit = IFX_Edit::NewEdit();
+  ASSERT(m_pEdit != NULL);
+
+  m_pEdit->SetAlignmentV(1);
+  m_pEdit->Initialize();
+}
+
+CFX_ListItem::~CFX_ListItem() {
+  IFX_Edit::DelEdit(m_pEdit);
+}
+
+void CFX_ListItem::SetFontMap(IFX_Edit_FontMap* pFontMap) {
+  if (m_pEdit)
+    m_pEdit->SetFontMap(pFontMap);
+}
+
+IFX_Edit* CFX_ListItem::GetEdit() const {
+  return m_pEdit;
+}
+
+IFX_Edit_Iterator* CFX_ListItem::GetIterator() const {
+  if (m_pEdit)
+    return m_pEdit->GetIterator();
+
+  return NULL;
+}
+
+void CFX_ListItem::SetRect(const CLST_Rect& rect) {
+  m_rcListItem = rect;
+}
+
+CLST_Rect CFX_ListItem::GetRect() const {
+  return m_rcListItem;
+}
+
+FX_BOOL CFX_ListItem::IsSelected() const {
+  return m_bSelected;
+}
+
+void CFX_ListItem::SetSelect(FX_BOOL bSelected) {
+  m_bSelected = bSelected;
+}
+
+FX_BOOL CFX_ListItem::IsCaret() const {
+  return m_bCaret;
+}
+
+void CFX_ListItem::SetCaret(FX_BOOL bCaret) {
+  m_bCaret = bCaret;
+}
+
+void CFX_ListItem::SetText(const FX_WCHAR* text) {
+  if (m_pEdit)
+    m_pEdit->SetText(text);
+}
+
+void CFX_ListItem::SetFontSize(FX_FLOAT fFontSize) {
+  if (m_pEdit)
+    m_pEdit->SetFontSize(fFontSize);
+}
+
+FX_FLOAT CFX_ListItem::GetItemHeight() const {
+  if (m_pEdit)
+    return m_pEdit->GetContentRect().Height();
+
+  return 0.0f;
+}
+
+FX_WORD CFX_ListItem::GetFirstChar() const {
+  CPVT_Word word;
+
+  if (IFX_Edit_Iterator* pIterator = GetIterator()) {
+    pIterator->SetAt(1);
+    pIterator->GetWord(word);
+  }
+
+  return word.Word;
+}
+
+CFX_WideString CFX_ListItem::GetText() const {
+  if (m_pEdit)
+    return m_pEdit->GetText();
+
+  return L"";
+}
+
+/* ------------------------------------ CFX_List
+ * --------------------------------- */
+
+CFX_List::CFX_List()
+    : m_fFontSize(0.0f), m_pFontMap(NULL), m_bMultiple(FALSE) {}
+
+CFX_List::~CFX_List() {
+  Empty();
+}
+
+void CFX_List::Empty() {
+  for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++)
+    delete m_aListItems.GetAt(i);
+
+  m_aListItems.RemoveAll();
+}
+
+void CFX_List::SetFontMap(IFX_Edit_FontMap* pFontMap) {
+  m_pFontMap = pFontMap;
+}
+
+void CFX_List::SetFontSize(FX_FLOAT fFontSize) {
+  m_fFontSize = fFontSize;
+}
+
+void CFX_List::AddItem(const FX_WCHAR* str) {
+  if (CFX_ListItem* pListItem = new CFX_ListItem()) {
+    pListItem->SetFontMap(m_pFontMap);
+    pListItem->SetFontSize(m_fFontSize);
+    pListItem->SetText(str);
+    m_aListItems.Add(pListItem);
+  }
+}
+
+void CFX_List::ReArrange(int32_t nItemIndex) {
+  FX_FLOAT fPosY = 0.0f;
+
+  if (CFX_ListItem* pPrevItem = m_aListItems.GetAt(nItemIndex - 1))
+    fPosY = pPrevItem->GetRect().bottom;
+
+  for (int32_t i = nItemIndex, sz = m_aListItems.GetSize(); i < sz; i++) {
+    if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
+      FX_FLOAT fListItemHeight = pListItem->GetItemHeight();
+      pListItem->SetRect(CLST_Rect(0.0f, fPosY, 0.0f, fPosY + fListItemHeight));
+      fPosY += fListItemHeight;
+    }
+  }
+
+  SetContentRect(CLST_Rect(0.0f, 0.0f, 0.0f, fPosY));
+}
+
+IFX_Edit* CFX_List::GetItemEdit(int32_t nIndex) const {
+  if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
+    return pListItem->GetEdit();
+  }
+
+  return NULL;
+}
+
+int32_t CFX_List::GetCount() const {
+  return m_aListItems.GetSize();
+}
+
+CPDF_Rect CFX_List::GetPlateRect() const {
+  return CFX_ListContainer::GetPlateRect();
+}
+
+CPDF_Rect CFX_List::GetContentRect() const {
+  return InnerToOuter(CFX_ListContainer::GetContentRect());
+}
+
+FX_FLOAT CFX_List::GetFontSize() const {
+  return m_fFontSize;
+}
+
+int32_t CFX_List::GetItemIndex(const CPDF_Point& point) const {
+  CPDF_Point pt = OuterToInner(point);
+
+  FX_BOOL bFirst = TRUE;
+  FX_BOOL bLast = TRUE;
+
+  for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
+    if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
+      CLST_Rect rcListItem = pListItem->GetRect();
+
+      if (FX_EDIT_IsFloatBigger(pt.y, rcListItem.top)) {
+        bFirst = FALSE;
+      }
+
+      if (FX_EDIT_IsFloatSmaller(pt.y, rcListItem.bottom)) {
+        bLast = FALSE;
+      }
+
+      if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom) {
+        return i;
+      }
+    }
+  }
+
+  if (bFirst)
+    return 0;
+  if (bLast)
+    return m_aListItems.GetSize() - 1;
+
+  return -1;
+}
+
+FX_FLOAT CFX_List::GetFirstHeight() const {
+  if (CFX_ListItem* pListItem = m_aListItems.GetAt(0)) {
+    return pListItem->GetItemHeight();
+  }
+
+  return 1.0f;
+}
+
+int32_t CFX_List::GetFirstSelected() const {
+  for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
+    if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
+      if (pListItem->IsSelected())
+        return i;
+    }
+  }
+  return -1;
+}
+
+int32_t CFX_List::GetLastSelected() const {
+  for (int32_t i = m_aListItems.GetSize() - 1; i >= 0; i--) {
+    if (CFX_ListItem* pListItem = m_aListItems.GetAt(i)) {
+      if (pListItem->IsSelected())
+        return i;
+    }
+  }
+  return -1;
+}
+
+FX_WCHAR CFX_List::Toupper(FX_WCHAR c) const {
+  if ((c >= 'a') && (c <= 'z'))
+    c = c - ('a' - 'A');
+  return c;
+}
+
+int32_t CFX_List::FindNext(int32_t nIndex, FX_WCHAR nChar) const {
+  int32_t nCircleIndex = nIndex;
+
+  for (int32_t i = 0, sz = m_aListItems.GetSize(); i < sz; i++) {
+    nCircleIndex++;
+    if (nCircleIndex >= sz)
+      nCircleIndex = 0;
+
+    if (CFX_ListItem* pListItem = m_aListItems.GetAt(nCircleIndex)) {
+      if (Toupper(pListItem->GetFirstChar()) == Toupper(nChar))
+        return nCircleIndex;
+    }
+  }
+
+  return nCircleIndex;
+}
+
+CPDF_Rect CFX_List::GetItemRect(int32_t nIndex) const {
+  if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
+    CPDF_Rect rcItem = pListItem->GetRect();
+    rcItem.left = 0.0f;
+    rcItem.right = GetPlateRect().Width();
+    return InnerToOuter(rcItem);
+  }
+
+  return CPDF_Rect();
+}
+
+FX_BOOL CFX_List::IsItemSelected(int32_t nIndex) const {
+  if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
+    return pListItem->IsSelected();
+  }
+
+  return FALSE;
+}
+
+void CFX_List::SetItemSelect(int32_t nItemIndex, FX_BOOL bSelected) {
+  if (CFX_ListItem* pListItem = m_aListItems.GetAt(nItemIndex)) {
+    pListItem->SetSelect(bSelected);
+  }
+}
+
+void CFX_List::SetItemCaret(int32_t nItemIndex, FX_BOOL bCaret) {
+  if (CFX_ListItem* pListItem = m_aListItems.GetAt(nItemIndex)) {
+    pListItem->SetCaret(bCaret);
+  }
+}
+
+void CFX_List::SetMultipleSel(FX_BOOL bMultiple) {
+  m_bMultiple = bMultiple;
+}
+
+FX_BOOL CFX_List::IsMultipleSel() const {
+  return m_bMultiple;
+}
+
+FX_BOOL CFX_List::IsValid(int32_t nItemIndex) const {
+  return nItemIndex >= 0 && nItemIndex < m_aListItems.GetSize();
+}
+
+CFX_WideString CFX_List::GetItemText(int32_t nIndex) const {
+  if (CFX_ListItem* pListItem = m_aListItems.GetAt(nIndex)) {
+    return pListItem->GetText();
+  }
+
+  return L"";
+}
+
+/* ------------------------------------ CPLST_Select
+ * ---------------------------------- */
+
+CPLST_Select::CPLST_Select() {}
+
+CPLST_Select::~CPLST_Select() {
+  for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++)
+    delete m_aItems.GetAt(i);
+
+  m_aItems.RemoveAll();
+}
+
+void CPLST_Select::Add(int32_t nItemIndex) {
+  int32_t nIndex = Find(nItemIndex);
+
+  if (nIndex < 0)
+    m_aItems.Add(new CPLST_Select_Item(nItemIndex, 1));
+  else {
+    if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex)) {
+      pItem->nState = 1;
+    }
+  }
+}
+
+void CPLST_Select::Add(int32_t nBeginIndex, int32_t nEndIndex) {
+  if (nBeginIndex > nEndIndex) {
+    int32_t nTemp = nEndIndex;
+    nEndIndex = nBeginIndex;
+    nBeginIndex = nTemp;
+  }
+
+  for (int32_t i = nBeginIndex; i <= nEndIndex; i++)
+    Add(i);
+}
+
+void CPLST_Select::Sub(int32_t nItemIndex) {
+  for (int32_t i = m_aItems.GetSize() - 1; i >= 0; i--) {
+    if (CPLST_Select_Item* pItem = m_aItems.GetAt(i))
+      if (pItem->nItemIndex == nItemIndex)
+        pItem->nState = -1;
+  }
+}
+
+void CPLST_Select::Sub(int32_t nBeginIndex, int32_t nEndIndex) {
+  if (nBeginIndex > nEndIndex) {
+    int32_t nTemp = nEndIndex;
+    nEndIndex = nBeginIndex;
+    nBeginIndex = nTemp;
+  }
+
+  for (int32_t i = nBeginIndex; i <= nEndIndex; i++)
+    Sub(i);
+}
+
+int32_t CPLST_Select::Find(int32_t nItemIndex) const {
+  for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++) {
+    if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
+      if (pItem->nItemIndex == nItemIndex)
+        return i;
+    }
+  }
+
+  return -1;
+}
+
+FX_BOOL CPLST_Select::IsExist(int32_t nItemIndex) const {
+  return Find(nItemIndex) >= 0;
+}
+
+int32_t CPLST_Select::GetCount() const {
+  return m_aItems.GetSize();
+}
+
+int32_t CPLST_Select::GetItemIndex(int32_t nIndex) const {
+  if (nIndex >= 0 && nIndex < m_aItems.GetSize())
+    if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex))
+      return pItem->nItemIndex;
+
+  return -1;
+}
+
+int32_t CPLST_Select::GetState(int32_t nIndex) const {
+  if (nIndex >= 0 && nIndex < m_aItems.GetSize())
+    if (CPLST_Select_Item* pItem = m_aItems.GetAt(nIndex))
+      return pItem->nState;
+
+  return 0;
+}
+
+void CPLST_Select::DeselectAll() {
+  for (int32_t i = 0, sz = m_aItems.GetSize(); i < sz; i++) {
+    if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
+      pItem->nState = -1;
+    }
+  }
+}
+
+void CPLST_Select::Done() {
+  for (int32_t i = m_aItems.GetSize() - 1; i >= 0; i--) {
+    if (CPLST_Select_Item* pItem = m_aItems.GetAt(i)) {
+      if (pItem->nState == -1) {
+        delete pItem;
+        m_aItems.RemoveAt(i);
+      } else {
+        pItem->nState = 0;
+      }
+    }
+  }
+}
+
+/* ------------------------------------ CFX_ListCtrl
+ * --------------------------------- */
+
+CFX_ListCtrl::CFX_ListCtrl()
+    : m_pNotify(NULL),
+      m_bNotifyFlag(FALSE),
+      m_ptScrollPos(0.0f, 0.0f),
+      m_nSelItem(-1),
+      m_nFootIndex(-1),
+      m_bCtrlSel(FALSE),
+      m_nCaretIndex(-1) {}
+
+CFX_ListCtrl::~CFX_ListCtrl() {}
+
+void CFX_ListCtrl::SetNotify(IFX_List_Notify* pNotify) {
+  m_pNotify = pNotify;
+}
+
+CPDF_Point CFX_ListCtrl::InToOut(const CPDF_Point& point) const {
+  CPDF_Rect rcPlate = GetPlateRect();
+
+  return CPDF_Point(point.x - (m_ptScrollPos.x - rcPlate.left),
+                    point.y - (m_ptScrollPos.y - rcPlate.top));
+}
+
+CPDF_Point CFX_ListCtrl::OutToIn(const CPDF_Point& point) const {
+  CPDF_Rect rcPlate = GetPlateRect();
+
+  return CPDF_Point(point.x + (m_ptScrollPos.x - rcPlate.left),
+                    point.y + (m_ptScrollPos.y - rcPlate.top));
+}
+
+CPDF_Rect CFX_ListCtrl::InToOut(const CPDF_Rect& rect) const {
+  CPDF_Point ptLeftBottom = InToOut(CPDF_Point(rect.left, rect.bottom));
+  CPDF_Point ptRightTop = InToOut(CPDF_Point(rect.right, rect.top));
+
+  return CPDF_Rect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x, ptRightTop.y);
+}
+
+CPDF_Rect CFX_ListCtrl::OutToIn(const CPDF_Rect& rect) const {
+  CPDF_Point ptLeftBottom = OutToIn(CPDF_Point(rect.left, rect.bottom));
+  CPDF_Point ptRightTop = OutToIn(CPDF_Point(rect.right, rect.top));
+
+  return CPDF_Rect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x, ptRightTop.y);
+}
+
+void CFX_ListCtrl::OnMouseDown(const CPDF_Point& point,
+                               FX_BOOL bShift,
+                               FX_BOOL bCtrl) {
+  int32_t nHitIndex = GetItemIndex(point);
+
+  if (IsMultipleSel()) {
+    if (bCtrl) {
+      if (IsItemSelected(nHitIndex)) {
+        m_aSelItems.Sub(nHitIndex);
+        SelectItems();
+        m_bCtrlSel = FALSE;
+      } else {
+        m_aSelItems.Add(nHitIndex);
+        SelectItems();
+        m_bCtrlSel = TRUE;
+      }
+
+      m_nFootIndex = nHitIndex;
+    } else if (bShift) {
+      m_aSelItems.DeselectAll();
+      m_aSelItems.Add(m_nFootIndex, nHitIndex);
+      SelectItems();
+    } else {
+      m_aSelItems.DeselectAll();
+      m_aSelItems.Add(nHitIndex);
+      SelectItems();
+
+      m_nFootIndex = nHitIndex;
+    }
+
+    SetCaret(nHitIndex);
+  } else {
+    SetSingleSelect(nHitIndex);
+  }
+
+  if (!IsItemVisible(nHitIndex))
+    ScrollToListItem(nHitIndex);
+}
+
+void CFX_ListCtrl::OnMouseMove(const CPDF_Point& point,
+                               FX_BOOL bShift,
+                               FX_BOOL bCtrl) {
+  int32_t nHitIndex = GetItemIndex(point);
+
+  if (IsMultipleSel()) {
+    if (bCtrl) {
+      if (m_bCtrlSel)
+        m_aSelItems.Add(m_nFootIndex, nHitIndex);
+      else
+        m_aSelItems.Sub(m_nFootIndex, nHitIndex);
+
+      SelectItems();
+    } else {
+      m_aSelItems.DeselectAll();
+      m_aSelItems.Add(m_nFootIndex, nHitIndex);
+      SelectItems();
+    }
+
+    SetCaret(nHitIndex);
+  } else {
+    SetSingleSelect(nHitIndex);
+  }
+
+  if (!IsItemVisible(nHitIndex))
+    ScrollToListItem(nHitIndex);
+}
+
+void CFX_ListCtrl::OnVK(int32_t nItemIndex, FX_BOOL bShift, FX_BOOL bCtrl) {
+  if (IsMultipleSel()) {
+    if (nItemIndex >= 0 && nItemIndex < GetCount()) {
+      if (bCtrl) {
+      } else if (bShift) {
+        m_aSelItems.DeselectAll();
+        m_aSelItems.Add(m_nFootIndex, nItemIndex);
+        SelectItems();
+      } else {
+        m_aSelItems.DeselectAll();
+        m_aSelItems.Add(nItemIndex);
+        SelectItems();
+        m_nFootIndex = nItemIndex;
+      }
+
+      SetCaret(nItemIndex);
+    }
+  } else {
+    SetSingleSelect(nItemIndex);
+  }
+
+  if (!IsItemVisible(nItemIndex))
+    ScrollToListItem(nItemIndex);
+}
+
+void CFX_ListCtrl::OnVK_UP(FX_BOOL bShift, FX_BOOL bCtrl) {
+  OnVK(IsMultipleSel() ? GetCaret() - 1 : GetSelect() - 1, bShift, bCtrl);
+}
+
+void CFX_ListCtrl::OnVK_DOWN(FX_BOOL bShift, FX_BOOL bCtrl) {
+  OnVK(IsMultipleSel() ? GetCaret() + 1 : GetSelect() + 1, bShift, bCtrl);
+}
+
+void CFX_ListCtrl::OnVK_LEFT(FX_BOOL bShift, FX_BOOL bCtrl) {
+  OnVK(0, bShift, bCtrl);
+}
+
+void CFX_ListCtrl::OnVK_RIGHT(FX_BOOL bShift, FX_BOOL bCtrl) {
+  OnVK(GetCount() - 1, bShift, bCtrl);
+}
+
+void CFX_ListCtrl::OnVK_HOME(FX_BOOL bShift, FX_BOOL bCtrl) {
+  OnVK(0, bShift, bCtrl);
+}
+
+void CFX_ListCtrl::OnVK_END(FX_BOOL bShift, FX_BOOL bCtrl) {
+  OnVK(GetCount() - 1, bShift, bCtrl);
+}
+
+FX_BOOL CFX_ListCtrl::OnChar(FX_WORD nChar, FX_BOOL bShift, FX_BOOL bCtrl) {
+  int32_t nIndex = GetLastSelected();
+  int32_t nFindIndex = FindNext(nIndex, nChar);
+
+  if (nFindIndex != nIndex) {
+    OnVK(nFindIndex, bShift, bCtrl);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/* -------- inner methods ------- */
+
+void CFX_ListCtrl::SetPlateRect(const CPDF_Rect& rect) {
+  CFX_ListContainer::SetPlateRect(rect);
+  m_ptScrollPos.x = rect.left;
+  SetScrollPos(CPDF_Point(rect.left, rect.top));
+  ReArrange(0);
+  InvalidateItem(-1);
+}
+
+CPDF_Rect CFX_ListCtrl::GetItemRect(int32_t nIndex) const {
+  return InToOut(CFX_List::GetItemRect(nIndex));
+}
+
+void CFX_ListCtrl::AddString(const FX_WCHAR* string) {
+  AddItem(string);
+  ReArrange(GetCount() - 1);
+}
+
+void CFX_ListCtrl::SetMultipleSelect(int32_t nItemIndex, FX_BOOL bSelected) {
+  if (!IsValid(nItemIndex))
+    return;
+
+  if (bSelected != IsItemSelected(nItemIndex)) {
+    if (bSelected) {
+      SetItemSelect(nItemIndex, TRUE);
+      InvalidateItem(nItemIndex);
+    } else {
+      SetItemSelect(nItemIndex, FALSE);
+      InvalidateItem(nItemIndex);
+    }
+  }
+}
+
+void CFX_ListCtrl::SetSingleSelect(int32_t nItemIndex) {
+  if (!IsValid(nItemIndex))
+    return;
+
+  if (m_nSelItem != nItemIndex) {
+    if (m_nSelItem >= 0) {
+      SetItemSelect(m_nSelItem, FALSE);
+      InvalidateItem(m_nSelItem);
+    }
+
+    SetItemSelect(nItemIndex, TRUE);
+    InvalidateItem(nItemIndex);
+    m_nSelItem = nItemIndex;
+  }
+}
+
+void CFX_ListCtrl::SetCaret(int32_t nItemIndex) {
+  if (!IsValid(nItemIndex))
+    return;
+
+  if (IsMultipleSel()) {
+    int32_t nOldIndex = m_nCaretIndex;
+
+    if (nOldIndex != nItemIndex) {
+      m_nCaretIndex = nItemIndex;
+
+      SetItemCaret(nOldIndex, FALSE);
+      SetItemCaret(nItemIndex, TRUE);
+
+      InvalidateItem(nOldIndex);
+      InvalidateItem(nItemIndex);
+    }
+  }
+}
+
+void CFX_ListCtrl::InvalidateItem(int32_t nItemIndex) {
+  if (m_pNotify) {
+    if (nItemIndex == -1) {
+      if (!m_bNotifyFlag) {
+        m_bNotifyFlag = TRUE;
+        CPDF_Rect rcRefresh = GetPlateRect();
+        m_pNotify->IOnInvalidateRect(&rcRefresh);
+        m_bNotifyFlag = FALSE;
+      }
+    } else {
+      if (!m_bNotifyFlag) {
+        m_bNotifyFlag = TRUE;
+        CPDF_Rect rcRefresh = GetItemRect(nItemIndex);
+        rcRefresh.left -= 1.0f;
+        rcRefresh.right += 1.0f;
+        rcRefresh.bottom -= 1.0f;
+        rcRefresh.top += 1.0f;
+
+        m_pNotify->IOnInvalidateRect(&rcRefresh);
+        m_bNotifyFlag = FALSE;
+      }
+    }
+  }
+}
+
+void CFX_ListCtrl::SelectItems() {
+  for (int32_t i = 0, sz = m_aSelItems.GetCount(); i < sz; i++) {
+    int32_t nItemIndex = m_aSelItems.GetItemIndex(i);
+    int32_t nState = m_aSelItems.GetState(i);
+
+    switch (nState) {
+      case 1:
+        SetMultipleSelect(nItemIndex, TRUE);
+        break;
+      case -1:
+        SetMultipleSelect(nItemIndex, FALSE);
+        break;
+    }
+  }
+
+  m_aSelItems.Done();
+}
+
+void CFX_ListCtrl::Select(int32_t nItemIndex) {
+  if (!IsValid(nItemIndex))
+    return;
+
+  if (IsMultipleSel()) {
+    m_aSelItems.Add(nItemIndex);
+    SelectItems();
+  } else
+    SetSingleSelect(nItemIndex);
+}
+
+FX_BOOL CFX_ListCtrl::IsItemVisible(int32_t nItemIndex) const {
+  CPDF_Rect rcPlate = GetPlateRect();
+  CPDF_Rect rcItem = GetItemRect(nItemIndex);
+
+  return rcItem.bottom >= rcPlate.bottom && rcItem.top <= rcPlate.top;
+}
+
+void CFX_ListCtrl::ScrollToListItem(int32_t nItemIndex) {
+  if (!IsValid(nItemIndex))
+    return;
+
+  CPDF_Rect rcPlate = GetPlateRect();
+  CPDF_Rect rcItem = CFX_List::GetItemRect(nItemIndex);
+  CPDF_Rect rcItemCtrl = GetItemRect(nItemIndex);
+
+  if (FX_EDIT_IsFloatSmaller(rcItemCtrl.bottom, rcPlate.bottom)) {
+    if (FX_EDIT_IsFloatSmaller(rcItemCtrl.top, rcPlate.top)) {
+      SetScrollPosY(rcItem.bottom + rcPlate.Height());
+    }
+  } else if (FX_EDIT_IsFloatBigger(rcItemCtrl.top, rcPlate.top)) {
+    if (FX_EDIT_IsFloatBigger(rcItemCtrl.bottom, rcPlate.bottom)) {
+      SetScrollPosY(rcItem.top);
+    }
+  }
+}
+
+void CFX_ListCtrl::SetScrollInfo() {
+  if (m_pNotify) {
+    CPDF_Rect rcPlate = GetPlateRect();
+    CPDF_Rect rcContent = CFX_List::GetContentRect();
+
+    if (!m_bNotifyFlag) {
+      m_bNotifyFlag = TRUE;
+      m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top,
+                                   rcContent.bottom, rcContent.top,
+                                   GetFirstHeight(), rcPlate.Height());
+      m_bNotifyFlag = FALSE;
+    }
+  }
+}
+
+void CFX_ListCtrl::SetScrollPos(const CPDF_Point& point) {
+  SetScrollPosY(point.y);
+}
+
+void CFX_ListCtrl::SetScrollPosY(FX_FLOAT fy) {
+  if (!FX_EDIT_IsFloatEqual(m_ptScrollPos.y, fy)) {
+    CPDF_Rect rcPlate = GetPlateRect();
+    CPDF_Rect rcContent = CFX_List::GetContentRect();
+
+    if (rcPlate.Height() > rcContent.Height()) {
+      fy = rcPlate.top;
+    } else {
+      if (FX_EDIT_IsFloatSmaller(fy - rcPlate.Height(), rcContent.bottom)) {
+        fy = rcContent.bottom + rcPlate.Height();
+      } else if (FX_EDIT_IsFloatBigger(fy, rcContent.top)) {
+        fy = rcContent.top;
+      }
+    }
+
+    m_ptScrollPos.y = fy;
+    InvalidateItem(-1);
+
+    if (m_pNotify) {
+      if (!m_bNotifyFlag) {
+        m_bNotifyFlag = TRUE;
+        m_pNotify->IOnSetScrollPosY(fy);
+        m_bNotifyFlag = FALSE;
+      }
+    }
+  }
+}
+
+CPDF_Rect CFX_ListCtrl::GetContentRect() const {
+  return InToOut(CFX_List::GetContentRect());
+}
+
+void CFX_ListCtrl::ReArrange(int32_t nItemIndex) {
+  CFX_List::ReArrange(nItemIndex);
+  SetScrollInfo();
+}
+
+void CFX_ListCtrl::SetTopItem(int32_t nIndex) {
+  if (IsValid(nIndex)) {
+    GetPlateRect();
+    CPDF_Rect rcItem = CFX_List::GetItemRect(nIndex);
+    SetScrollPosY(rcItem.top);
+  }
+}
+
+int32_t CFX_ListCtrl::GetTopItem() const {
+  int32_t nItemIndex = GetItemIndex(GetBTPoint());
+
+  if (!IsItemVisible(nItemIndex) && IsItemVisible(nItemIndex + 1))
+    nItemIndex += 1;
+
+  return nItemIndex;
+}
+
+void CFX_ListCtrl::Empty() {
+  CFX_List::Empty();
+  InvalidateItem(-1);
+}
+
+void CFX_ListCtrl::Cancel() {
+  m_aSelItems.DeselectAll();
+}
+
+int32_t CFX_ListCtrl::GetItemIndex(const CPDF_Point& point) const {
+  return CFX_List::GetItemIndex(OutToIn(point));
+}
+
+CFX_WideString CFX_ListCtrl::GetText() const {
+  if (IsMultipleSel())
+    return GetItemText(m_nCaretIndex);
+  return GetItemText(m_nSelItem);
+}