Home | History | Annotate | Download | only in basewidget
      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 "xfa/src/foxitlib.h"
      8 #include "xfa/src/fwl/src/core/include/fwl_targetimp.h"
      9 #include "xfa/src/fwl/src/core/include/fwl_noteimp.h"
     10 #include "xfa/src/fwl/src/core/include/fwl_widgetimp.h"
     11 #include "xfa/src/fwl/src/basewidget/include/fwl_scrollbarimp.h"
     12 #include "xfa/src/fwl/src/basewidget/include/fwl_listboximp.h"
     13 #include "xfa/src/fwl/src/basewidget/include/fwl_comboboximp.h"
     14 
     15 #define FWL_LISTBOX_ItemTextMargin 2
     16 
     17 // static
     18 IFWL_ListBox* IFWL_ListBox::Create(const CFWL_WidgetImpProperties& properties,
     19                                    IFWL_Widget* pOuter) {
     20   IFWL_ListBox* pListBox = new IFWL_ListBox;
     21   CFWL_ListBoxImp* pListBoxImpl = new CFWL_ListBoxImp(properties, pOuter);
     22   pListBox->SetImpl(pListBoxImpl);
     23   pListBoxImpl->SetInterface(pListBox);
     24   return pListBox;
     25 }
     26 // static
     27 IFWL_ListBox* IFWL_ListBox::CreateComboList(
     28     const CFWL_WidgetImpProperties& properties,
     29     IFWL_Widget* pOuter) {
     30   IFWL_ListBox* pListBox = new IFWL_ListBox;
     31   CFWL_ListBoxImp* pComboListImpl = new CFWL_ComboListImp(properties, pOuter);
     32   pListBox->SetImpl(pComboListImpl);
     33   pComboListImpl->SetInterface(pListBox);
     34   return pListBox;
     35 }
     36 IFWL_ListBox::IFWL_ListBox() {}
     37 int32_t IFWL_ListBox::CountSelItems() {
     38   return static_cast<CFWL_ListBoxImp*>(GetImpl())->CountSelItems();
     39 }
     40 FWL_HLISTITEM IFWL_ListBox::GetSelItem(int32_t nIndexSel) {
     41   return static_cast<CFWL_ListBoxImp*>(GetImpl())->GetSelItem(nIndexSel);
     42 }
     43 int32_t IFWL_ListBox::GetSelIndex(int32_t nIndex) {
     44   return static_cast<CFWL_ListBoxImp*>(GetImpl())->GetSelIndex(nIndex);
     45 }
     46 FWL_ERR IFWL_ListBox::SetSelItem(FWL_HLISTITEM hItem, FX_BOOL bSelect) {
     47   return static_cast<CFWL_ListBoxImp*>(GetImpl())->SetSelItem(hItem, bSelect);
     48 }
     49 FWL_ERR IFWL_ListBox::GetItemText(FWL_HLISTITEM hItem, CFX_WideString& wsText) {
     50   return static_cast<CFWL_ListBoxImp*>(GetImpl())->GetItemText(hItem, wsText);
     51 }
     52 FWL_ERR IFWL_ListBox::GetScrollPos(FX_FLOAT& fPos, FX_BOOL bVert) {
     53   return static_cast<CFWL_ListBoxImp*>(GetImpl())->GetScrollPos(fPos, bVert);
     54 }
     55 FWL_ERR* IFWL_ListBox::Sort(IFWL_ListBoxCompare* pCom) {
     56   return static_cast<CFWL_ListBoxImp*>(GetImpl())->Sort(pCom);
     57 }
     58 
     59 CFWL_ListBoxImp::CFWL_ListBoxImp(const CFWL_WidgetImpProperties& properties,
     60                                  IFWL_Widget* pOuter)
     61     : CFWL_WidgetImp(properties, pOuter),
     62       m_dwTTOStyles(0),
     63       m_iTTOAligns(0),
     64       m_hAnchor(NULL),
     65       m_fScorllBarWidth(0),
     66       m_bLButtonDown(FALSE),
     67       m_pScrollBarTP(NULL) {
     68   m_rtClient.Reset();
     69   m_rtConent.Reset();
     70   m_rtStatic.Reset();
     71 }
     72 CFWL_ListBoxImp::~CFWL_ListBoxImp() {
     73 }
     74 FWL_ERR CFWL_ListBoxImp::GetClassName(CFX_WideString& wsClass) const {
     75   wsClass = FWL_CLASS_ListBox;
     76   return FWL_ERR_Succeeded;
     77 }
     78 FX_DWORD CFWL_ListBoxImp::GetClassID() const {
     79   return FWL_CLASSHASH_ListBox;
     80 }
     81 FWL_ERR CFWL_ListBoxImp::Initialize() {
     82   if (CFWL_WidgetImp::Initialize() != FWL_ERR_Succeeded)
     83     return FWL_ERR_Indefinite;
     84   m_pDelegate = new CFWL_ListBoxImpDelegate(this);
     85   return FWL_ERR_Succeeded;
     86 }
     87 FWL_ERR CFWL_ListBoxImp::Finalize() {
     88   if (m_pVertScrollBar) {
     89     m_pVertScrollBar->Finalize();
     90   }
     91   if (m_pHorzScrollBar) {
     92     m_pHorzScrollBar->Finalize();
     93   }
     94   delete m_pDelegate;
     95   m_pDelegate = nullptr;
     96   return CFWL_WidgetImp::Finalize();
     97 }
     98 FWL_ERR CFWL_ListBoxImp::GetWidgetRect(CFX_RectF& rect, FX_BOOL bAutoSize) {
     99   if (bAutoSize) {
    100     rect.Set(0, 0, 0, 0);
    101     if (!m_pProperties->m_pThemeProvider) {
    102       m_pProperties->m_pThemeProvider = GetAvailableTheme();
    103     }
    104     CFX_SizeF fs = CalcSize(TRUE);
    105     rect.Set(0, 0, fs.x, fs.y);
    106     CFWL_WidgetImp::GetWidgetRect(rect, TRUE);
    107   } else {
    108     rect = m_pProperties->m_rtWidget;
    109   }
    110   return FWL_ERR_Succeeded;
    111 }
    112 FWL_ERR CFWL_ListBoxImp::Update() {
    113   if (IsLocked()) {
    114     return FWL_ERR_Indefinite;
    115   }
    116   if (!m_pProperties->m_pThemeProvider) {
    117     m_pProperties->m_pThemeProvider = GetAvailableTheme();
    118   }
    119   m_iTTOAligns = FDE_TTOALIGNMENT_Center;
    120   switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_AlignMask) {
    121     case FWL_STYLEEXT_LTB_LeftAlign: {
    122       m_iTTOAligns = FDE_TTOALIGNMENT_CenterLeft;
    123       break;
    124     }
    125     case FWL_STYLEEXT_LTB_RightAlign: {
    126       m_iTTOAligns = FDE_TTOALIGNMENT_CenterRight;
    127       break;
    128     }
    129     case FWL_STYLEEXT_LTB_CenterAlign:
    130     default: { m_iTTOAligns = FDE_TTOALIGNMENT_Center; }
    131   }
    132   if (m_pProperties->m_dwStyleExes & FWL_WGTSTYLE_RTLReading) {
    133     m_dwTTOStyles |= FDE_TTOSTYLE_RTL;
    134   }
    135   m_dwTTOStyles |= FDE_TTOSTYLE_SingleLine;
    136   m_fScorllBarWidth = GetScrollWidth();
    137   SortItem();
    138   CalcSize();
    139   return FWL_ERR_Succeeded;
    140 }
    141 FX_DWORD CFWL_ListBoxImp::HitTest(FX_FLOAT fx, FX_FLOAT fy) {
    142   if (IsShowScrollBar(FALSE)) {
    143     CFX_RectF rect;
    144     m_pHorzScrollBar->GetWidgetRect(rect);
    145     if (rect.Contains(fx, fy)) {
    146       return FWL_WGTHITTEST_HScrollBar;
    147     }
    148   }
    149   if (IsShowScrollBar(TRUE)) {
    150     CFX_RectF rect;
    151     m_pVertScrollBar->GetWidgetRect(rect);
    152     if (rect.Contains(fx, fy)) {
    153       return FWL_WGTHITTEST_VScrollBar;
    154     }
    155   }
    156   if (m_rtClient.Contains(fx, fy)) {
    157     return FWL_WGTHITTEST_Client;
    158   }
    159   return FWL_WGTHITTEST_Unknown;
    160 }
    161 FWL_ERR CFWL_ListBoxImp::DrawWidget(CFX_Graphics* pGraphics,
    162                                     const CFX_Matrix* pMatrix) {
    163   if (!pGraphics)
    164     return FWL_ERR_Indefinite;
    165   if (!m_pProperties->m_pThemeProvider)
    166     return FWL_ERR_Indefinite;
    167   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
    168   pGraphics->SaveGraphState();
    169   if (HasBorder()) {
    170     DrawBorder(pGraphics, FWL_PART_LTB_Border, pTheme, pMatrix);
    171   }
    172   if (HasEdge()) {
    173     DrawEdge(pGraphics, FWL_PART_LTB_Edge, pTheme, pMatrix);
    174   }
    175   CFX_RectF rtClip(m_rtConent);
    176   if (IsShowScrollBar(FALSE)) {
    177     rtClip.height -= m_fScorllBarWidth;
    178   }
    179   if (IsShowScrollBar(TRUE)) {
    180     rtClip.width -= m_fScorllBarWidth;
    181   }
    182   if (pMatrix) {
    183     pMatrix->TransformRect(rtClip);
    184   }
    185   pGraphics->SetClipRect(rtClip);
    186   if ((m_pProperties->m_dwStyles & FWL_WGTSTYLE_NoBackground) == 0) {
    187     DrawBkground(pGraphics, pTheme, pMatrix);
    188   }
    189   DrawItems(pGraphics, pTheme, pMatrix);
    190   pGraphics->RestoreGraphState();
    191   return FWL_ERR_Succeeded;
    192 }
    193 FWL_ERR CFWL_ListBoxImp::SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) {
    194   if (!pThemeProvider)
    195     return FWL_ERR_Indefinite;
    196   if (!pThemeProvider->IsValidWidget(m_pInterface)) {
    197     m_pScrollBarTP = pThemeProvider;
    198     return FWL_ERR_Succeeded;
    199   }
    200   m_pProperties->m_pThemeProvider = pThemeProvider;
    201   return FWL_ERR_Succeeded;
    202 }
    203 int32_t CFWL_ListBoxImp::CountSelItems() {
    204   if (!m_pProperties->m_pDataProvider)
    205     return 0;
    206   int32_t iRet = 0;
    207   IFWL_ListBoxDP* pData =
    208       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    209   int32_t iCount = pData->CountItems(m_pInterface);
    210   for (int32_t i = 0; i < iCount; i++) {
    211     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, i);
    212     if (!hItem) {
    213       continue;
    214     }
    215     FX_DWORD dwStyle = pData->GetItemStyles(m_pInterface, hItem);
    216     if (dwStyle & FWL_ITEMSTATE_LTB_Selected) {
    217       iRet++;
    218     }
    219   }
    220   return iRet;
    221 }
    222 FWL_HLISTITEM CFWL_ListBoxImp::GetSelItem(int32_t nIndexSel) {
    223   if (!m_pProperties->m_pDataProvider)
    224     return NULL;
    225   int32_t index = 0;
    226   IFWL_ListBoxDP* pData =
    227       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    228   int32_t iCount = pData->CountItems(m_pInterface);
    229   for (int32_t i = 0; i < iCount; i++) {
    230     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, i);
    231     if (!hItem) {
    232       return NULL;
    233     }
    234     FX_DWORD dwStyle = pData->GetItemStyles(m_pInterface, hItem);
    235     if (dwStyle & FWL_ITEMSTATE_LTB_Selected) {
    236       if (index == nIndexSel) {
    237         return hItem;
    238       } else {
    239         index++;
    240       }
    241     }
    242   }
    243   return NULL;
    244 }
    245 int32_t CFWL_ListBoxImp::GetSelIndex(int32_t nIndex) {
    246   if (!m_pProperties->m_pDataProvider)
    247     return -1;
    248   int32_t index = 0;
    249   IFWL_ListBoxDP* pData =
    250       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    251   int32_t iCount = pData->CountItems(m_pInterface);
    252   for (int32_t i = 0; i < iCount; i++) {
    253     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, i);
    254     if (!hItem) {
    255       return -1;
    256     }
    257     FX_DWORD dwStyle = pData->GetItemStyles(m_pInterface, hItem);
    258     if (dwStyle & FWL_ITEMSTATE_LTB_Selected) {
    259       if (index == nIndex) {
    260         return i;
    261       } else {
    262         index++;
    263       }
    264     }
    265   }
    266   return -1;
    267 }
    268 FWL_ERR CFWL_ListBoxImp::SetSelItem(FWL_HLISTITEM hItem, FX_BOOL bSelect) {
    269   if (!m_pProperties->m_pDataProvider)
    270     return FWL_ERR_Indefinite;
    271   if (!hItem) {
    272     if (bSelect) {
    273       SelectAll();
    274     } else {
    275       ClearSelection();
    276       SetFocusItem(NULL);
    277     }
    278     return FWL_ERR_Indefinite;
    279   }
    280   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_MultiSelection) {
    281     SetSelectionDirect(hItem, bSelect);
    282   } else {
    283     SetSelection(hItem, hItem, bSelect);
    284   }
    285   return FWL_ERR_Succeeded;
    286 }
    287 FWL_ERR CFWL_ListBoxImp::GetItemText(FWL_HLISTITEM hItem,
    288                                      CFX_WideString& wsText) {
    289   if (!m_pProperties->m_pDataProvider)
    290     return FWL_ERR_Indefinite;
    291   IFWL_ListBoxDP* pData =
    292       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    293   if (!hItem)
    294     return FWL_ERR_Indefinite;
    295   pData->GetItemText(m_pInterface, hItem, wsText);
    296   return FWL_ERR_Succeeded;
    297 }
    298 FWL_ERR CFWL_ListBoxImp::GetScrollPos(FX_FLOAT& fPos, FX_BOOL bVert) {
    299   if ((bVert && IsShowScrollBar(TRUE)) || (!bVert && IsShowScrollBar(FALSE))) {
    300     IFWL_ScrollBar* pScrollBar =
    301         bVert ? m_pVertScrollBar.get() : m_pHorzScrollBar.get();
    302     fPos = pScrollBar->GetPos();
    303     return FWL_ERR_Succeeded;
    304   }
    305   return FWL_ERR_Indefinite;
    306 }
    307 FWL_ERR* CFWL_ListBoxImp::Sort(IFWL_ListBoxCompare* pCom) {
    308   FWL_HLISTITEM hTemp;
    309   IFWL_ListBoxDP* pData =
    310       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    311   int32_t sz = pData->CountItems(m_pInterface);
    312   for (int32_t i = 0; i < sz - 1; i++) {
    313     for (int32_t j = i + 1; j < sz; j++) {
    314       if (pCom->Compare(pData->GetItem(m_pInterface, i),
    315                         pData->GetItem(m_pInterface, j)) > 0) {
    316         hTemp = pData->GetItem(m_pInterface, i);
    317         pData->SetItemIndex(m_pInterface, pData->GetItem(m_pInterface, j), i);
    318         pData->SetItemIndex(m_pInterface, hTemp, j);
    319       }
    320     }
    321   }
    322   return FWL_ERR_Succeeded;
    323 }
    324 FWL_HLISTITEM CFWL_ListBoxImp::GetItem(FWL_HLISTITEM hItem,
    325                                        FX_DWORD dwKeyCode) {
    326   FWL_HLISTITEM hRet = NULL;
    327   switch (dwKeyCode) {
    328     case FWL_VKEY_Up:
    329     case FWL_VKEY_Down:
    330     case FWL_VKEY_Home:
    331     case FWL_VKEY_End: {
    332       FX_BOOL bUp = dwKeyCode == FWL_VKEY_Up;
    333       FX_BOOL bDown = dwKeyCode == FWL_VKEY_Down;
    334       FX_BOOL bHome = dwKeyCode == FWL_VKEY_Home;
    335       IFWL_ListBoxDP* pData =
    336           static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    337       int32_t iDstItem = -1;
    338       if (bUp || bDown) {
    339         int32_t index = pData->GetItemIndex(m_pInterface, hItem);
    340         iDstItem = dwKeyCode == FWL_VKEY_Up ? index - 1 : index + 1;
    341       } else if (bHome) {
    342         iDstItem = 0;
    343       } else {
    344         int32_t iCount = pData->CountItems(m_pInterface);
    345         iDstItem = iCount - 1;
    346       }
    347       hRet = pData->GetItem(m_pInterface, iDstItem);
    348       break;
    349     }
    350     default: {}
    351   }
    352   return hRet;
    353 }
    354 void CFWL_ListBoxImp::SetSelection(FWL_HLISTITEM hStart,
    355                                    FWL_HLISTITEM hEnd,
    356                                    FX_BOOL bSelected) {
    357   IFWL_ListBoxDP* pData =
    358       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    359   int32_t iStart = pData->GetItemIndex(m_pInterface, hStart);
    360   int32_t iEnd = pData->GetItemIndex(m_pInterface, hEnd);
    361   if (iStart > iEnd) {
    362     int32_t iTemp = iStart;
    363     iStart = iEnd;
    364     iEnd = iTemp;
    365   }
    366   if (bSelected) {
    367     int32_t iCount = pData->CountItems(m_pInterface);
    368     for (int32_t i = 0; i < iCount; i++) {
    369       FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, i);
    370       SetSelectionDirect(hItem, FALSE);
    371     }
    372   }
    373   for (; iStart <= iEnd; iStart++) {
    374     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, iStart);
    375     SetSelectionDirect(hItem, bSelected);
    376   }
    377 }
    378 void CFWL_ListBoxImp::SetSelectionDirect(FWL_HLISTITEM hItem, FX_BOOL bSelect) {
    379   IFWL_ListBoxDP* pData =
    380       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    381   FX_DWORD dwOldStyle = pData->GetItemStyles(m_pInterface, hItem);
    382   bSelect ? dwOldStyle |= FWL_ITEMSTATE_LTB_Selected
    383           : dwOldStyle &= ~FWL_ITEMSTATE_LTB_Selected;
    384   pData->SetItemStyles(m_pInterface, hItem, dwOldStyle);
    385 }
    386 FX_BOOL CFWL_ListBoxImp::IsItemSelected(FWL_HLISTITEM hItem) {
    387   IFWL_ListBoxDP* pData =
    388       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    389   FX_DWORD dwState = pData->GetItemStyles(m_pInterface, hItem);
    390   return (dwState & FWL_ITEMSTATE_LTB_Selected) != 0;
    391 }
    392 void CFWL_ListBoxImp::ClearSelection() {
    393   FX_BOOL bMulti =
    394       m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_MultiSelection;
    395   IFWL_ListBoxDP* pData =
    396       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    397   int32_t iCount = pData->CountItems(m_pInterface);
    398   for (int32_t i = 0; i < iCount; i++) {
    399     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, i);
    400     FX_DWORD dwState = pData->GetItemStyles(m_pInterface, hItem);
    401     FX_BOOL bFindSel = dwState & FWL_ITEMSTATE_LTB_Selected;
    402     if (!bFindSel) {
    403       continue;
    404     }
    405     SetSelectionDirect(hItem, FALSE);
    406     if (!bMulti) {
    407       return;
    408     }
    409   }
    410 }
    411 void CFWL_ListBoxImp::SelectAll() {
    412   FX_BOOL bMulti =
    413       m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_MultiSelection;
    414   if (!bMulti) {
    415     return;
    416   }
    417   IFWL_ListBoxDP* pData =
    418       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    419   int32_t iCount = pData->CountItems(m_pInterface);
    420   if (iCount > 0) {
    421     FWL_HLISTITEM hItemStart = pData->GetItem(m_pInterface, 0);
    422     FWL_HLISTITEM hItemEnd = pData->GetItem(m_pInterface, iCount - 1);
    423     SetSelection(hItemStart, hItemEnd, FALSE);
    424   }
    425 }
    426 FWL_HLISTITEM CFWL_ListBoxImp::GetFocusedItem() {
    427   IFWL_ListBoxDP* pData =
    428       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    429   int32_t iCount = pData->CountItems(m_pInterface);
    430   for (int32_t i = 0; i < iCount; i++) {
    431     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, i);
    432     if (!hItem)
    433       return NULL;
    434     if (pData->GetItemStyles(m_pInterface, hItem) & FWL_ITEMSTATE_LTB_Focused) {
    435       return hItem;
    436     }
    437   }
    438   return NULL;
    439 }
    440 void CFWL_ListBoxImp::SetFocusItem(FWL_HLISTITEM hItem) {
    441   IFWL_ListBoxDP* pData =
    442       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    443   FWL_HLISTITEM hFocus = GetFocusedItem();
    444   if (hItem != hFocus) {
    445     if (hFocus) {
    446       FX_DWORD dwStyle = pData->GetItemStyles(m_pInterface, hFocus);
    447       dwStyle &= ~FWL_ITEMSTATE_LTB_Focused;
    448       pData->SetItemStyles(m_pInterface, hFocus, dwStyle);
    449     }
    450     if (hItem) {
    451       FX_DWORD dwStyle = pData->GetItemStyles(m_pInterface, hItem);
    452       dwStyle |= FWL_ITEMSTATE_LTB_Focused;
    453       pData->SetItemStyles(m_pInterface, hItem, dwStyle);
    454     }
    455   }
    456 }
    457 FWL_HLISTITEM CFWL_ListBoxImp::GetItemAtPoint(FX_FLOAT fx, FX_FLOAT fy) {
    458   fx -= m_rtConent.left, fy -= m_rtConent.top;
    459   FX_FLOAT fPosX = 0.0f;
    460   if (m_pHorzScrollBar) {
    461     fPosX = m_pHorzScrollBar->GetPos();
    462   }
    463   FX_FLOAT fPosY = 0.0;
    464   if (m_pVertScrollBar) {
    465     fPosY = m_pVertScrollBar->GetPos();
    466   }
    467   IFWL_ListBoxDP* pData =
    468       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    469   int32_t nCount = pData->CountItems(m_pInterface);
    470   for (int32_t i = 0; i < nCount; i++) {
    471     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, i);
    472     if (!hItem) {
    473       continue;
    474     }
    475     CFX_RectF rtItem;
    476     pData->GetItemRect(m_pInterface, hItem, rtItem);
    477     rtItem.Offset(-fPosX, -fPosY);
    478     if (rtItem.Contains(fx, fy)) {
    479       return hItem;
    480     }
    481   }
    482   return NULL;
    483 }
    484 FX_BOOL CFWL_ListBoxImp::GetItemCheckRect(FWL_HLISTITEM hItem,
    485                                           CFX_RectF& rtCheck) {
    486   if (!m_pProperties->m_pDataProvider)
    487     return FALSE;
    488   if (!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_Check)) {
    489     return FALSE;
    490   }
    491   IFWL_ListBoxDP* pData =
    492       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    493   pData->GetItemCheckRect(m_pInterface, hItem, rtCheck);
    494   return TRUE;
    495 }
    496 FX_BOOL CFWL_ListBoxImp::GetItemChecked(FWL_HLISTITEM hItem) {
    497   if (!m_pProperties->m_pDataProvider)
    498     return FALSE;
    499   if (!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_Check)) {
    500     return FALSE;
    501   }
    502   IFWL_ListBoxDP* pData =
    503       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    504   return (pData->GetItemCheckState(m_pInterface, hItem) &
    505           FWL_ITEMSTATE_LTB_Checked);
    506 }
    507 FX_BOOL CFWL_ListBoxImp::SetItemChecked(FWL_HLISTITEM hItem, FX_BOOL bChecked) {
    508   if (!m_pProperties->m_pDataProvider)
    509     return FALSE;
    510   if (!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_Check)) {
    511     return FALSE;
    512   }
    513   IFWL_ListBoxDP* pData =
    514       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    515   pData->SetItemCheckState(m_pInterface, hItem,
    516                            bChecked ? FWL_ITEMSTATE_LTB_Checked : 0);
    517   return TRUE;
    518 }
    519 FX_BOOL CFWL_ListBoxImp::ScrollToVisible(FWL_HLISTITEM hItem) {
    520   if (!m_pVertScrollBar)
    521     return FALSE;
    522   CFX_RectF rtItem;
    523   IFWL_ListBoxDP* pData =
    524       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    525   pData->GetItemRect(m_pInterface, hItem, rtItem);
    526   FX_BOOL bScroll = FALSE;
    527   FX_FLOAT fPosY = m_pVertScrollBar->GetPos();
    528   rtItem.Offset(0, -fPosY + m_rtConent.top);
    529   if (rtItem.top < m_rtConent.top) {
    530     fPosY += rtItem.top - m_rtConent.top;
    531     bScroll = TRUE;
    532   } else if (rtItem.bottom() > m_rtConent.bottom()) {
    533     fPosY += rtItem.bottom() - m_rtConent.bottom();
    534     bScroll = TRUE;
    535   }
    536   if (!bScroll) {
    537     return FALSE;
    538   }
    539   m_pVertScrollBar->SetPos(fPosY);
    540   m_pVertScrollBar->SetTrackPos(fPosY);
    541   Repaint(&m_rtClient);
    542   return TRUE;
    543 }
    544 void CFWL_ListBoxImp::DrawBkground(CFX_Graphics* pGraphics,
    545                                    IFWL_ThemeProvider* pTheme,
    546                                    const CFX_Matrix* pMatrix) {
    547   if (!pGraphics)
    548     return;
    549   if (!pTheme)
    550     return;
    551   CFWL_ThemeBackground param;
    552   param.m_pWidget = m_pInterface;
    553   param.m_iPart = FWL_PART_LTB_Background;
    554   param.m_dwStates = 0;
    555   param.m_pGraphics = pGraphics;
    556   param.m_matrix.Concat(*pMatrix);
    557   param.m_rtPart = m_rtClient;
    558   if (IsShowScrollBar(FALSE) && IsShowScrollBar(TRUE)) {
    559     param.m_pData = &m_rtStatic;
    560   }
    561   if (!IsEnabled()) {
    562     param.m_dwStates = FWL_PARTSTATE_LTB_Disabled;
    563   }
    564   pTheme->DrawBackground(&param);
    565 }
    566 void CFWL_ListBoxImp::DrawItems(CFX_Graphics* pGraphics,
    567                                 IFWL_ThemeProvider* pTheme,
    568                                 const CFX_Matrix* pMatrix) {
    569   FX_FLOAT fPosX = 0.0f;
    570   if (m_pHorzScrollBar) {
    571     fPosX = m_pHorzScrollBar->GetPos();
    572   }
    573   FX_FLOAT fPosY = 0.0f;
    574   if (m_pVertScrollBar) {
    575     fPosY = m_pVertScrollBar->GetPos();
    576   }
    577   CFX_RectF rtView(m_rtConent);
    578   if (m_pHorzScrollBar) {
    579     rtView.height -= m_fScorllBarWidth;
    580   }
    581   if (m_pVertScrollBar) {
    582     rtView.width -= m_fScorllBarWidth;
    583   }
    584   FX_BOOL bMultiCol =
    585       m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_MultiColumn;
    586   IFWL_ListBoxDP* pData =
    587       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    588   int32_t iCount = pData->CountItems(m_pInterface);
    589   for (int32_t i = 0; i < iCount; i++) {
    590     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, i);
    591     if (!hItem) {
    592       continue;
    593     }
    594     CFX_RectF rtItem;
    595     pData->GetItemRect(m_pInterface, hItem, rtItem);
    596     rtItem.Offset(m_rtConent.left - fPosX, m_rtConent.top - fPosY);
    597     if (rtItem.bottom() < m_rtConent.top) {
    598       continue;
    599     }
    600     if (rtItem.top >= m_rtConent.bottom()) {
    601       break;
    602     }
    603     if (bMultiCol && rtItem.left > m_rtConent.right()) {
    604       break;
    605     }
    606     if (GetStylesEx() & FWL_STYLEEXT_LTB_OwnerDraw) {
    607       CFWL_EvtLtbDrawItem ev;
    608       ev.m_pSrcTarget = m_pInterface;
    609       ev.m_pGraphics = pGraphics;
    610       ev.m_matrix = *pMatrix;
    611       ev.m_index = i;
    612       ev.m_rect = rtItem;
    613       DispatchEvent(&ev);
    614     } else {
    615       DrawItem(pGraphics, pTheme, hItem, i, rtItem, pMatrix);
    616     }
    617   }
    618 }
    619 void CFWL_ListBoxImp::DrawItem(CFX_Graphics* pGraphics,
    620                                IFWL_ThemeProvider* pTheme,
    621                                FWL_HLISTITEM hItem,
    622                                int32_t Index,
    623                                const CFX_RectF& rtItem,
    624                                const CFX_Matrix* pMatrix) {
    625   IFWL_ListBoxDP* pData =
    626       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    627   FX_DWORD dwItemStyles = pData->GetItemStyles(m_pInterface, hItem);
    628   FX_DWORD dwPartStates = FWL_PARTSTATE_LTB_Normal;
    629   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) {
    630     dwPartStates = FWL_PARTSTATE_LTB_Disabled;
    631   } else if (dwItemStyles & FWL_ITEMSTATE_LTB_Selected) {
    632     dwPartStates = FWL_PARTSTATE_LTB_Selected;
    633   }
    634   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused &&
    635       dwItemStyles & FWL_ITEMSTATE_LTB_Focused) {
    636     dwPartStates |= FWL_PARTSTATE_LTB_Focused;
    637   }
    638   FWL_ListBoxItemData itemData;
    639   itemData.pDataProvider = pData;
    640   itemData.iIndex = Index;
    641   {
    642     CFWL_ThemeBackground param;
    643     param.m_pWidget = m_pInterface;
    644     param.m_iPart = FWL_PART_LTB_ListItem;
    645     param.m_dwStates = dwPartStates;
    646     param.m_pGraphics = pGraphics;
    647     param.m_matrix.Concat(*pMatrix);
    648     param.m_rtPart = rtItem;
    649     param.m_dwData = (FX_DWORD)(uintptr_t)(&itemData);
    650     CFX_RectF rtFocus(rtItem);
    651     param.m_pData = &rtFocus;
    652     if (m_pVertScrollBar && !m_pHorzScrollBar &&
    653         (dwPartStates & FWL_PARTSTATE_LTB_Focused)) {
    654       param.m_rtPart.left += 1;
    655       param.m_rtPart.width -= (m_fScorllBarWidth + 1);
    656       rtFocus.Deflate(0.5, 0.5, 1 + m_fScorllBarWidth, 1);
    657     }
    658     pTheme->DrawBackground(&param);
    659   }
    660   {
    661     FX_BOOL bHasIcon = GetStylesEx() & FWL_STYLEEXT_LTB_Icon;
    662     if (bHasIcon) {
    663       CFX_RectF rtDIB;
    664       CFX_DIBitmap* pDib = pData->GetItemIcon(m_pInterface, hItem);
    665       rtDIB.Set(rtItem.left, rtItem.top, rtItem.height, rtItem.height);
    666       if (pDib) {
    667         CFWL_ThemeBackground param;
    668         param.m_pWidget = m_pInterface;
    669         param.m_iPart = FWL_PART_LTB_Icon;
    670         param.m_pGraphics = pGraphics;
    671         param.m_matrix.Concat(*pMatrix);
    672         param.m_rtPart = rtDIB;
    673         param.m_dwData = (FX_DWORD)(uintptr_t)(&itemData);
    674         param.m_pImage = pDib;
    675         pTheme->DrawBackground(&param);
    676       }
    677     }
    678     FX_BOOL bHasCheck = GetStylesEx() & FWL_STYLEEXT_LTB_Check;
    679     if (bHasCheck) {
    680       CFX_RectF rtCheck;
    681       rtCheck.Set(rtItem.left, rtItem.top, rtItem.height, rtItem.height);
    682       rtCheck.Deflate(2, 2, 2, 2);
    683       pData->SetItemCheckRect(m_pInterface, hItem, rtCheck);
    684       CFWL_ThemeBackground param;
    685       param.m_pWidget = m_pInterface;
    686       param.m_iPart = FWL_PART_LTB_Check;
    687       param.m_pGraphics = pGraphics;
    688       if (GetItemChecked(hItem)) {
    689         param.m_dwStates = FWL_PARTSTATE_LTB_Checked;
    690       } else {
    691         param.m_dwStates = FWL_PARTSTATE_LTB_UnChecked;
    692       }
    693       param.m_matrix.Concat(*pMatrix);
    694       param.m_rtPart = rtCheck;
    695       param.m_dwData = (FX_DWORD)(uintptr_t)(&itemData);
    696       pTheme->DrawBackground(&param);
    697     }
    698     CFX_WideString wsText;
    699     pData->GetItemText(m_pInterface, hItem, wsText);
    700     if (wsText.GetLength() <= 0) {
    701       return;
    702     }
    703     CFX_RectF rtText(rtItem);
    704     rtText.Deflate(FWL_LISTBOX_ItemTextMargin, FWL_LISTBOX_ItemTextMargin);
    705     if (bHasIcon || bHasCheck) {
    706       rtText.Deflate(rtItem.height, 0, 0, 0);
    707     }
    708     CFWL_ThemeText textParam;
    709     textParam.m_pWidget = m_pInterface;
    710     textParam.m_iPart = FWL_PART_LTB_ListItem;
    711     textParam.m_dwStates = dwPartStates;
    712     textParam.m_pGraphics = pGraphics;
    713     textParam.m_matrix.Concat(*pMatrix);
    714     textParam.m_rtPart = rtText;
    715     textParam.m_wsText = wsText;
    716     textParam.m_dwTTOStyles = m_dwTTOStyles;
    717     textParam.m_iTTOAlign = m_iTTOAligns;
    718     textParam.m_dwData = (FX_DWORD)(uintptr_t)(&itemData);
    719     pTheme->DrawText(&textParam);
    720   }
    721 }
    722 CFX_SizeF CFWL_ListBoxImp::CalcSize(FX_BOOL bAutoSize) {
    723   CFX_SizeF fs;
    724   fs.Set(0, 0);
    725   if (!m_pProperties->m_pThemeProvider)
    726     return fs;
    727   GetClientRect(m_rtClient);
    728   m_rtConent = m_rtClient;
    729   CFX_RectF rtUIMargin;
    730   rtUIMargin.Set(0, 0, 0, 0);
    731   if (!m_pOuter) {
    732     CFX_RectF* pUIMargin =
    733         static_cast<CFX_RectF*>(GetThemeCapacity(FWL_WGTCAPACITY_UIMargin));
    734     if (pUIMargin) {
    735       m_rtConent.Deflate(pUIMargin->left, pUIMargin->top, pUIMargin->width,
    736                          pUIMargin->height);
    737     }
    738   }
    739   FX_FLOAT fWidth = 0;
    740   if (m_pProperties->m_pThemeProvider->IsCustomizedLayout(m_pInterface)) {
    741     IFWL_ListBoxDP* pData =
    742         static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    743     if (!bAutoSize) {
    744     }
    745     int32_t iCount = pData->CountItems(m_pInterface);
    746     for (int32_t i = 0; i < iCount; i++) {
    747       FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, i);
    748       CFWL_ThemePart itemPart;
    749       itemPart.m_pWidget = m_pInterface;
    750       itemPart.m_iPart = FWL_PART_LTB_ListItem;
    751       itemPart.m_pData = m_pProperties->m_pDataProvider;
    752       itemPart.m_dwData = i;
    753       CFX_RectF r;
    754       m_pProperties->m_pThemeProvider->GetPartRect(&itemPart, r);
    755       if (!bAutoSize) {
    756         CFX_RectF rtItem;
    757         rtItem.Set(m_rtClient.left, m_rtClient.top + fs.y, r.width, r.height);
    758         IFWL_ListBoxDP* pData =
    759             static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    760         pData->SetItemRect(m_pInterface, hItem, rtItem);
    761       }
    762       fs.y += r.height;
    763       if (fs.x < r.width) {
    764         fs.x = r.width;
    765         fWidth = r.width;
    766       }
    767     }
    768   } else {
    769     fWidth = GetMaxTextWidth();
    770     fWidth += 2 * FWL_LISTBOX_ItemTextMargin;
    771     if (!bAutoSize) {
    772       FX_FLOAT fActualWidth =
    773           m_rtClient.width - rtUIMargin.left - rtUIMargin.width;
    774       if (fWidth < fActualWidth) {
    775         fWidth = fActualWidth;
    776       }
    777     }
    778     IFWL_ListBoxDP* pData =
    779         static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    780     m_fItemHeight = GetItemHeigt();
    781     FX_BOOL bHasIcon;
    782     bHasIcon = GetStylesEx() & FWL_STYLEEXT_LTB_Icon;
    783     if (bHasIcon) {
    784       fWidth += m_fItemHeight;
    785     }
    786     int32_t iCount = pData->CountItems(m_pInterface);
    787     for (int32_t i = 0; i < iCount; i++) {
    788       FWL_HLISTITEM htem = pData->GetItem(m_pInterface, i);
    789       GetItemSize(fs, htem, fWidth, m_fItemHeight, bAutoSize);
    790     }
    791   }
    792   if (bAutoSize) {
    793     return fs;
    794   }
    795   FX_FLOAT iWidth = m_rtClient.width - rtUIMargin.left - rtUIMargin.width;
    796   FX_FLOAT iHeight = m_rtClient.height;
    797   FX_BOOL bShowVertScr =
    798       (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_ShowScrollBarAlaways) &&
    799       (m_pProperties->m_dwStyles & FWL_WGTSTYLE_VScroll);
    800   FX_BOOL bShowHorzScr =
    801       (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_ShowScrollBarAlaways) &&
    802       (m_pProperties->m_dwStyles & FWL_WGTSTYLE_HScroll);
    803   if (!bShowVertScr && m_pProperties->m_dwStyles & FWL_WGTSTYLE_VScroll &&
    804       (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_MultiColumn) == 0) {
    805     bShowVertScr = (fs.y > iHeight);
    806   }
    807   if (!bShowHorzScr && m_pProperties->m_dwStyles & FWL_WGTSTYLE_HScroll) {
    808     bShowHorzScr = (fs.x > iWidth);
    809   }
    810   CFX_SizeF szRange;
    811   if (bShowVertScr) {
    812     if (!m_pVertScrollBar) {
    813       InitScrollBar();
    814     }
    815     CFX_RectF rtScrollBar;
    816     rtScrollBar.Set(m_rtClient.right() - m_fScorllBarWidth, m_rtClient.top,
    817                     m_fScorllBarWidth, m_rtClient.height - 1);
    818     if (bShowHorzScr) {
    819       rtScrollBar.height -= m_fScorllBarWidth;
    820     }
    821     m_pVertScrollBar->SetWidgetRect(rtScrollBar);
    822     szRange.x = 0, szRange.y = fs.y - m_rtConent.height;
    823     if (szRange.y < m_fItemHeight) {
    824       szRange.y = m_fItemHeight;
    825     }
    826     m_pVertScrollBar->SetRange(szRange.x, szRange.y);
    827     m_pVertScrollBar->SetPageSize(rtScrollBar.height * 9 / 10);
    828     m_pVertScrollBar->SetStepSize(m_fItemHeight);
    829     FX_FLOAT fPos = m_pVertScrollBar->GetPos();
    830     if (fPos < 0) {
    831       fPos = 0;
    832     }
    833     if (fPos > szRange.y) {
    834       fPos = szRange.y;
    835     }
    836     m_pVertScrollBar->SetPos(fPos);
    837     m_pVertScrollBar->SetTrackPos(fPos);
    838     if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_ShowScrollBarFocus) ==
    839             0 ||
    840         (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)) {
    841       m_pVertScrollBar->SetStates(FWL_WGTSTATE_Invisible, FALSE);
    842     }
    843     m_pVertScrollBar->Update();
    844   } else if (m_pVertScrollBar) {
    845     m_pVertScrollBar->SetPos(0);
    846     m_pVertScrollBar->SetTrackPos(0);
    847     m_pVertScrollBar->SetStates(FWL_WGTSTATE_Invisible, TRUE);
    848   }
    849   if (bShowHorzScr) {
    850     if (!m_pHorzScrollBar) {
    851       InitScrollBar(FALSE);
    852     }
    853     CFX_RectF rtScrollBar;
    854     rtScrollBar.Set(m_rtClient.left, m_rtClient.bottom() - m_fScorllBarWidth,
    855                     m_rtClient.width, m_fScorllBarWidth);
    856     if (bShowVertScr) {
    857       rtScrollBar.width -= m_fScorllBarWidth;
    858     }
    859     m_pHorzScrollBar->SetWidgetRect(rtScrollBar);
    860     szRange.x = 0, szRange.y = fs.x - rtScrollBar.width;
    861     m_pHorzScrollBar->SetRange(szRange.x, szRange.y);
    862     m_pHorzScrollBar->SetPageSize(fWidth * 9 / 10);
    863     m_pHorzScrollBar->SetStepSize(fWidth / 10);
    864     FX_FLOAT fPos = m_pHorzScrollBar->GetPos();
    865     if (fPos < 0) {
    866       fPos = 0;
    867     }
    868     if (fPos > szRange.y) {
    869       fPos = szRange.y;
    870     }
    871     m_pHorzScrollBar->SetPos(fPos);
    872     m_pHorzScrollBar->SetTrackPos(fPos);
    873     if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_ShowScrollBarFocus) ==
    874             0 ||
    875         (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)) {
    876       m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible, FALSE);
    877     }
    878     m_pHorzScrollBar->Update();
    879   } else if (m_pHorzScrollBar) {
    880     m_pHorzScrollBar->SetPos(0);
    881     m_pHorzScrollBar->SetTrackPos(0);
    882     m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible, TRUE);
    883   }
    884   if (bShowVertScr && bShowHorzScr) {
    885     m_rtStatic.Set(m_rtClient.right() - m_fScorllBarWidth,
    886                    m_rtClient.bottom() - m_fScorllBarWidth, m_fScorllBarWidth,
    887                    m_fScorllBarWidth);
    888   }
    889   return fs;
    890 }
    891 void CFWL_ListBoxImp::GetItemSize(CFX_SizeF& size,
    892                                   FWL_HLISTITEM hItem,
    893                                   FX_FLOAT fWidth,
    894                                   FX_FLOAT m_fItemHeight,
    895                                   FX_BOOL bAutoSize) {
    896   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_MultiColumn) {
    897   } else {
    898     if (!bAutoSize) {
    899       CFX_RectF rtItem;
    900       rtItem.Set(0, size.y, fWidth, m_fItemHeight);
    901       IFWL_ListBoxDP* pData =
    902           static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    903       pData->SetItemRect(m_pInterface, hItem, rtItem);
    904     }
    905     size.x = fWidth;
    906     size.y += m_fItemHeight;
    907   }
    908 }
    909 FX_FLOAT CFWL_ListBoxImp::GetMaxTextWidth() {
    910   FX_FLOAT fRet = 0.0f;
    911   IFWL_ListBoxDP* pData =
    912       static_cast<IFWL_ListBoxDP*>(m_pProperties->m_pDataProvider);
    913   int32_t iCount = pData->CountItems(m_pInterface);
    914   for (int32_t i = 0; i < iCount; i++) {
    915     FWL_HLISTITEM hItem = pData->GetItem(m_pInterface, i);
    916     if (!hItem) {
    917       continue;
    918     }
    919     CFX_WideString wsText;
    920     pData->GetItemText(m_pInterface, hItem, wsText);
    921     CFX_SizeF sz = CalcTextSize(wsText, m_pProperties->m_pThemeProvider);
    922     if (sz.x > fRet) {
    923       fRet = sz.x;
    924     }
    925   }
    926   return fRet;
    927 }
    928 FX_FLOAT CFWL_ListBoxImp::GetScrollWidth() {
    929   FX_FLOAT* pfWidth =
    930       static_cast<FX_FLOAT*>(GetThemeCapacity(FWL_WGTCAPACITY_ScrollBarWidth));
    931   if (!pfWidth)
    932     return 0;
    933   return *pfWidth;
    934 }
    935 FX_FLOAT CFWL_ListBoxImp::GetItemHeigt() {
    936   FX_FLOAT* pfFont =
    937       static_cast<FX_FLOAT*>(GetThemeCapacity(FWL_WGTCAPACITY_FontSize));
    938   if (!pfFont)
    939     return 20;
    940   return *pfFont + 2 * FWL_LISTBOX_ItemTextMargin;
    941 }
    942 void CFWL_ListBoxImp::InitScrollBar(FX_BOOL bVert) {
    943   if ((bVert && m_pVertScrollBar) || (!bVert && m_pHorzScrollBar)) {
    944     return;
    945   }
    946   CFWL_WidgetImpProperties prop;
    947   prop.m_dwStyleExes = bVert ? FWL_STYLEEXT_SCB_Vert : FWL_STYLEEXT_SCB_Horz;
    948   prop.m_dwStates = FWL_WGTSTATE_Invisible;
    949   prop.m_pParent = m_pInterface;
    950   prop.m_pThemeProvider = m_pScrollBarTP;
    951   IFWL_ScrollBar* pScrollBar = IFWL_ScrollBar::Create(prop, m_pInterface);
    952   pScrollBar->Initialize();
    953   (bVert ? &m_pVertScrollBar : &m_pHorzScrollBar)->reset(pScrollBar);
    954 }
    955 void CFWL_ListBoxImp::SortItem() {}
    956 FX_BOOL CFWL_ListBoxImp::IsShowScrollBar(FX_BOOL bVert) {
    957   IFWL_ScrollBar* pScrollbar =
    958       bVert ? m_pVertScrollBar.get() : m_pHorzScrollBar.get();
    959   if (!pScrollbar || (pScrollbar->GetStates() & FWL_WGTSTATE_Invisible)) {
    960     return FALSE;
    961   }
    962   return !(m_pProperties->m_dwStyleExes &
    963            FWL_STYLEEXT_LTB_ShowScrollBarFocus) ||
    964          (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused);
    965 }
    966 void CFWL_ListBoxImp::ProcessSelChanged() {
    967   CFWL_EvtLtbSelChanged selEvent;
    968   selEvent.m_pSrcTarget = m_pInterface;
    969   CFX_Int32Array arrSels;
    970   int32_t iCount = CountSelItems();
    971   for (int32_t i = 0; i < iCount; i++) {
    972     FWL_HLISTITEM item = GetSelItem(i);
    973     if (item == NULL) {
    974       continue;
    975     }
    976     selEvent.iarraySels.Add(i);
    977   }
    978   DispatchEvent(&selEvent);
    979 }
    980 CFWL_ListBoxImpDelegate::CFWL_ListBoxImpDelegate(CFWL_ListBoxImp* pOwner)
    981     : m_pOwner(pOwner) {}
    982 int32_t CFWL_ListBoxImpDelegate::OnProcessMessage(CFWL_Message* pMessage) {
    983   if (!pMessage)
    984     return 0;
    985   if (!m_pOwner->IsEnabled()) {
    986     return 1;
    987   }
    988   FX_DWORD dwMsgCode = pMessage->GetClassID();
    989   int32_t iRet = 1;
    990   switch (dwMsgCode) {
    991     case FWL_MSGHASH_SetFocus:
    992     case FWL_MSGHASH_KillFocus: {
    993       OnFocusChanged(pMessage, dwMsgCode == FWL_MSGHASH_SetFocus);
    994       break;
    995     }
    996     case FWL_MSGHASH_Mouse: {
    997       CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage);
    998       FX_DWORD dwCmd = pMsg->m_dwCmd;
    999       switch (dwCmd) {
   1000         case FWL_MSGMOUSECMD_LButtonDown: {
   1001           OnLButtonDown(pMsg);
   1002           break;
   1003         }
   1004         case FWL_MSGMOUSECMD_LButtonUp: {
   1005           OnLButtonUp(pMsg);
   1006           break;
   1007         }
   1008         default: {}
   1009       }
   1010       break;
   1011     }
   1012     case FWL_MSGHASH_MouseWheel: {
   1013       OnMouseWheel(static_cast<CFWL_MsgMouseWheel*>(pMessage));
   1014       break;
   1015     }
   1016     case FWL_MSGHASH_Key: {
   1017       CFWL_MsgKey* pMsg = static_cast<CFWL_MsgKey*>(pMessage);
   1018       if (pMsg->m_dwCmd == FWL_MSGKEYCMD_KeyDown)
   1019         OnKeyDown(pMsg);
   1020       break;
   1021     }
   1022     default: { iRet = 0; }
   1023   }
   1024   CFWL_WidgetImpDelegate::OnProcessMessage(pMessage);
   1025   return iRet;
   1026 }
   1027 FWL_ERR CFWL_ListBoxImpDelegate::OnProcessEvent(CFWL_Event* pEvent) {
   1028   if (!pEvent)
   1029     return FWL_ERR_Indefinite;
   1030   if (pEvent->GetClassID() != FWL_EVTHASH_Scroll) {
   1031     return FWL_ERR_Succeeded;
   1032   }
   1033   IFWL_Widget* pSrcTarget = pEvent->m_pSrcTarget;
   1034   if ((pSrcTarget == m_pOwner->m_pVertScrollBar.get() &&
   1035        m_pOwner->m_pVertScrollBar) ||
   1036       (pSrcTarget == m_pOwner->m_pHorzScrollBar.get() &&
   1037        m_pOwner->m_pHorzScrollBar)) {
   1038     CFWL_EvtScroll* pScrollEvent = static_cast<CFWL_EvtScroll*>(pEvent);
   1039     OnScroll(static_cast<IFWL_ScrollBar*>(pSrcTarget),
   1040              pScrollEvent->m_iScrollCode, pScrollEvent->m_fPos);
   1041   }
   1042   return FWL_ERR_Succeeded;
   1043 }
   1044 FWL_ERR CFWL_ListBoxImpDelegate::OnDrawWidget(CFX_Graphics* pGraphics,
   1045                                               const CFX_Matrix* pMatrix) {
   1046   return m_pOwner->DrawWidget(pGraphics, pMatrix);
   1047 }
   1048 void CFWL_ListBoxImpDelegate::OnFocusChanged(CFWL_Message* pMsg, FX_BOOL bSet) {
   1049   if (m_pOwner->GetStylesEx() & FWL_STYLEEXT_LTB_ShowScrollBarFocus) {
   1050     if (m_pOwner->m_pVertScrollBar) {
   1051       m_pOwner->m_pVertScrollBar->SetStates(FWL_WGTSTATE_Invisible, !bSet);
   1052     }
   1053     if (m_pOwner->m_pHorzScrollBar) {
   1054       m_pOwner->m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Invisible, !bSet);
   1055     }
   1056   }
   1057   if (bSet) {
   1058     m_pOwner->m_pProperties->m_dwStates |= (FWL_WGTSTATE_Focused);
   1059   } else {
   1060     m_pOwner->m_pProperties->m_dwStates &= ~(FWL_WGTSTATE_Focused);
   1061   }
   1062   m_pOwner->Repaint(&m_pOwner->m_rtClient);
   1063 }
   1064 void CFWL_ListBoxImpDelegate::OnLButtonDown(CFWL_MsgMouse* pMsg) {
   1065   m_pOwner->m_bLButtonDown = TRUE;
   1066   if ((m_pOwner->m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0) {
   1067     m_pOwner->SetFocus(TRUE);
   1068   }
   1069   FWL_HLISTITEM hItem = m_pOwner->GetItemAtPoint(pMsg->m_fx, pMsg->m_fy);
   1070   if (!hItem) {
   1071     return;
   1072   }
   1073   if (m_pOwner->m_pProperties->m_dwStyleExes &
   1074       FWL_STYLEEXT_LTB_MultiSelection) {
   1075     if (pMsg->m_dwFlags & FWL_KEYFLAG_Ctrl) {
   1076       FX_BOOL bSelected = m_pOwner->IsItemSelected(hItem);
   1077       m_pOwner->SetSelectionDirect(hItem, !bSelected);
   1078       m_pOwner->m_hAnchor = hItem;
   1079     } else if (pMsg->m_dwFlags & FWL_KEYFLAG_Shift) {
   1080       if (m_pOwner->m_hAnchor) {
   1081         m_pOwner->SetSelection(m_pOwner->m_hAnchor, hItem, TRUE);
   1082       } else {
   1083         m_pOwner->SetSelectionDirect(hItem, TRUE);
   1084       }
   1085     } else {
   1086       m_pOwner->SetSelection(hItem, hItem, TRUE);
   1087       m_pOwner->m_hAnchor = hItem;
   1088     }
   1089   } else {
   1090     m_pOwner->SetSelection(hItem, hItem, TRUE);
   1091   }
   1092   if (m_pOwner->m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_Check) {
   1093     FWL_HLISTITEM hSelectedItem =
   1094         m_pOwner->GetItemAtPoint(pMsg->m_fx, pMsg->m_fy);
   1095     CFX_RectF rtCheck;
   1096     m_pOwner->GetItemCheckRect(hSelectedItem, rtCheck);
   1097     FX_BOOL bChecked = m_pOwner->GetItemChecked(hItem);
   1098     if (rtCheck.Contains(pMsg->m_fx, pMsg->m_fy)) {
   1099       if (bChecked) {
   1100         m_pOwner->SetItemChecked(hItem, FALSE);
   1101       } else {
   1102         m_pOwner->SetItemChecked(hItem, TRUE);
   1103       }
   1104       m_pOwner->Update();
   1105     }
   1106   }
   1107   m_pOwner->SetFocusItem(hItem);
   1108   m_pOwner->ScrollToVisible(hItem);
   1109   m_pOwner->SetGrab(TRUE);
   1110   m_pOwner->ProcessSelChanged();
   1111   m_pOwner->Repaint(&m_pOwner->m_rtClient);
   1112 }
   1113 void CFWL_ListBoxImpDelegate::OnLButtonUp(CFWL_MsgMouse* pMsg) {
   1114   if (m_pOwner->m_bLButtonDown) {
   1115     m_pOwner->m_bLButtonDown = FALSE;
   1116     m_pOwner->SetGrab(FALSE);
   1117     DispatchSelChangedEv();
   1118   }
   1119 }
   1120 void CFWL_ListBoxImpDelegate::OnMouseWheel(CFWL_MsgMouseWheel* pMsg) {
   1121   if (!m_pOwner->IsShowScrollBar(TRUE)) {
   1122     return;
   1123   }
   1124   IFWL_WidgetDelegate* pDelegate =
   1125       m_pOwner->m_pVertScrollBar->SetDelegate(NULL);
   1126   pDelegate->OnProcessMessage(pMsg);
   1127 }
   1128 void CFWL_ListBoxImpDelegate::OnKeyDown(CFWL_MsgKey* pMsg) {
   1129   FX_DWORD dwKeyCode = pMsg->m_dwKeyCode;
   1130   switch (dwKeyCode) {
   1131     case FWL_VKEY_Tab:
   1132     case FWL_VKEY_Up:
   1133     case FWL_VKEY_Down:
   1134     case FWL_VKEY_Home:
   1135     case FWL_VKEY_End: {
   1136       FWL_HLISTITEM hItem = m_pOwner->GetFocusedItem();
   1137       hItem = m_pOwner->GetItem(hItem, dwKeyCode);
   1138       FX_BOOL bShift = pMsg->m_dwFlags & FWL_KEYFLAG_Shift;
   1139       FX_BOOL bCtrl = pMsg->m_dwFlags & FWL_KEYFLAG_Ctrl;
   1140       OnVK(hItem, bShift, bCtrl);
   1141       DispatchSelChangedEv();
   1142       m_pOwner->ProcessSelChanged();
   1143       break;
   1144     }
   1145     default: {}
   1146   }
   1147 }
   1148 void CFWL_ListBoxImpDelegate::OnVK(FWL_HLISTITEM hItem,
   1149                                    FX_BOOL bShift,
   1150                                    FX_BOOL bCtrl) {
   1151   if (!hItem) {
   1152     return;
   1153   }
   1154   if (m_pOwner->m_pProperties->m_dwStyleExes &
   1155       FWL_STYLEEXT_LTB_MultiSelection) {
   1156     if (bCtrl) {
   1157     } else if (bShift) {
   1158       if (m_pOwner->m_hAnchor) {
   1159         m_pOwner->SetSelection(m_pOwner->m_hAnchor, hItem, TRUE);
   1160       } else {
   1161         m_pOwner->SetSelectionDirect(hItem, TRUE);
   1162       }
   1163     } else {
   1164       m_pOwner->SetSelection(hItem, hItem, TRUE);
   1165       m_pOwner->m_hAnchor = hItem;
   1166     }
   1167   } else {
   1168     m_pOwner->SetSelection(hItem, hItem, TRUE);
   1169   }
   1170   m_pOwner->SetFocusItem(hItem);
   1171   m_pOwner->ScrollToVisible(hItem);
   1172   {
   1173     CFX_RectF rtInvalidate;
   1174     rtInvalidate.Set(0, 0, m_pOwner->m_pProperties->m_rtWidget.width,
   1175                      m_pOwner->m_pProperties->m_rtWidget.height);
   1176     m_pOwner->Repaint(&rtInvalidate);
   1177   }
   1178 }
   1179 FX_BOOL CFWL_ListBoxImpDelegate::OnScroll(IFWL_ScrollBar* pScrollBar,
   1180                                           FX_DWORD dwCode,
   1181                                           FX_FLOAT fPos) {
   1182   CFX_SizeF fs;
   1183   pScrollBar->GetRange(fs.x, fs.y);
   1184   FX_FLOAT iCurPos = pScrollBar->GetPos();
   1185   FX_FLOAT fStep = pScrollBar->GetStepSize();
   1186   switch (dwCode) {
   1187     case FWL_SCBCODE_Min: {
   1188       fPos = fs.x;
   1189       break;
   1190     }
   1191     case FWL_SCBCODE_Max: {
   1192       fPos = fs.y;
   1193       break;
   1194     }
   1195     case FWL_SCBCODE_StepBackward: {
   1196       fPos -= fStep;
   1197       if (fPos < fs.x + fStep / 2) {
   1198         fPos = fs.x;
   1199       }
   1200       break;
   1201     }
   1202     case FWL_SCBCODE_StepForward: {
   1203       fPos += fStep;
   1204       if (fPos > fs.y - fStep / 2) {
   1205         fPos = fs.y;
   1206       }
   1207       break;
   1208     }
   1209     case FWL_SCBCODE_PageBackward: {
   1210       fPos -= pScrollBar->GetPageSize();
   1211       if (fPos < fs.x) {
   1212         fPos = fs.x;
   1213       }
   1214       break;
   1215     }
   1216     case FWL_SCBCODE_PageForward: {
   1217       fPos += pScrollBar->GetPageSize();
   1218       if (fPos > fs.y) {
   1219         fPos = fs.y;
   1220       }
   1221       break;
   1222     }
   1223     case FWL_SCBCODE_Pos:
   1224     case FWL_SCBCODE_TrackPos:
   1225       break;
   1226     case FWL_SCBCODE_EndScroll:
   1227       return FALSE;
   1228   }
   1229   if (iCurPos != fPos) {
   1230     pScrollBar->SetPos(fPos);
   1231     pScrollBar->SetTrackPos(fPos);
   1232     m_pOwner->Repaint(&m_pOwner->m_rtClient);
   1233   }
   1234   return TRUE;
   1235 }
   1236 void CFWL_ListBoxImpDelegate::DispatchSelChangedEv() {
   1237   CFWL_EvtLtbSelChanged ev;
   1238   ev.m_pSrcTarget = m_pOwner->m_pInterface;
   1239   m_pOwner->DispatchEvent(&ev);
   1240 }
   1241