• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
Create(const CFWL_WidgetImpProperties & properties,IFWL_Widget * pOuter)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
CreateComboList(const CFWL_WidgetImpProperties & properties,IFWL_Widget * pOuter)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 }
IFWL_ListBox()36 IFWL_ListBox::IFWL_ListBox() {}
CountSelItems()37 int32_t IFWL_ListBox::CountSelItems() {
38   return static_cast<CFWL_ListBoxImp*>(GetImpl())->CountSelItems();
39 }
GetSelItem(int32_t nIndexSel)40 FWL_HLISTITEM IFWL_ListBox::GetSelItem(int32_t nIndexSel) {
41   return static_cast<CFWL_ListBoxImp*>(GetImpl())->GetSelItem(nIndexSel);
42 }
GetSelIndex(int32_t nIndex)43 int32_t IFWL_ListBox::GetSelIndex(int32_t nIndex) {
44   return static_cast<CFWL_ListBoxImp*>(GetImpl())->GetSelIndex(nIndex);
45 }
SetSelItem(FWL_HLISTITEM hItem,FX_BOOL bSelect)46 FWL_ERR IFWL_ListBox::SetSelItem(FWL_HLISTITEM hItem, FX_BOOL bSelect) {
47   return static_cast<CFWL_ListBoxImp*>(GetImpl())->SetSelItem(hItem, bSelect);
48 }
GetItemText(FWL_HLISTITEM hItem,CFX_WideString & wsText)49 FWL_ERR IFWL_ListBox::GetItemText(FWL_HLISTITEM hItem, CFX_WideString& wsText) {
50   return static_cast<CFWL_ListBoxImp*>(GetImpl())->GetItemText(hItem, wsText);
51 }
GetScrollPos(FX_FLOAT & fPos,FX_BOOL bVert)52 FWL_ERR IFWL_ListBox::GetScrollPos(FX_FLOAT& fPos, FX_BOOL bVert) {
53   return static_cast<CFWL_ListBoxImp*>(GetImpl())->GetScrollPos(fPos, bVert);
54 }
Sort(IFWL_ListBoxCompare * pCom)55 FWL_ERR* IFWL_ListBox::Sort(IFWL_ListBoxCompare* pCom) {
56   return static_cast<CFWL_ListBoxImp*>(GetImpl())->Sort(pCom);
57 }
58 
CFWL_ListBoxImp(const CFWL_WidgetImpProperties & properties,IFWL_Widget * pOuter)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 }
~CFWL_ListBoxImp()72 CFWL_ListBoxImp::~CFWL_ListBoxImp() {
73 }
GetClassName(CFX_WideString & wsClass) const74 FWL_ERR CFWL_ListBoxImp::GetClassName(CFX_WideString& wsClass) const {
75   wsClass = FWL_CLASS_ListBox;
76   return FWL_ERR_Succeeded;
77 }
GetClassID() const78 FX_DWORD CFWL_ListBoxImp::GetClassID() const {
79   return FWL_CLASSHASH_ListBox;
80 }
Initialize()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 }
Finalize()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 }
GetWidgetRect(CFX_RectF & rect,FX_BOOL bAutoSize)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 }
Update()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 }
HitTest(FX_FLOAT fx,FX_FLOAT fy)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 }
DrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)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 }
SetThemeProvider(IFWL_ThemeProvider * pThemeProvider)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 }
CountSelItems()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 }
GetSelItem(int32_t nIndexSel)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 }
GetSelIndex(int32_t nIndex)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 }
SetSelItem(FWL_HLISTITEM hItem,FX_BOOL bSelect)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 }
GetItemText(FWL_HLISTITEM hItem,CFX_WideString & wsText)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 }
GetScrollPos(FX_FLOAT & fPos,FX_BOOL bVert)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 }
Sort(IFWL_ListBoxCompare * pCom)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 }
GetItem(FWL_HLISTITEM hItem,FX_DWORD dwKeyCode)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 }
SetSelection(FWL_HLISTITEM hStart,FWL_HLISTITEM hEnd,FX_BOOL bSelected)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 }
SetSelectionDirect(FWL_HLISTITEM hItem,FX_BOOL bSelect)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 }
IsItemSelected(FWL_HLISTITEM hItem)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 }
ClearSelection()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 }
SelectAll()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 }
GetFocusedItem()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 }
SetFocusItem(FWL_HLISTITEM hItem)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 }
GetItemAtPoint(FX_FLOAT fx,FX_FLOAT fy)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 }
GetItemCheckRect(FWL_HLISTITEM hItem,CFX_RectF & rtCheck)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 }
GetItemChecked(FWL_HLISTITEM hItem)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 }
SetItemChecked(FWL_HLISTITEM hItem,FX_BOOL bChecked)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 }
ScrollToVisible(FWL_HLISTITEM hItem)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 }
DrawBkground(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)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 }
DrawItems(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)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 }
DrawItem(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,FWL_HLISTITEM hItem,int32_t Index,const CFX_RectF & rtItem,const CFX_Matrix * pMatrix)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 }
CalcSize(FX_BOOL bAutoSize)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 }
GetItemSize(CFX_SizeF & size,FWL_HLISTITEM hItem,FX_FLOAT fWidth,FX_FLOAT m_fItemHeight,FX_BOOL bAutoSize)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 }
GetMaxTextWidth()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 }
GetScrollWidth()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 }
GetItemHeigt()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 }
InitScrollBar(FX_BOOL bVert)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 }
SortItem()955 void CFWL_ListBoxImp::SortItem() {}
IsShowScrollBar(FX_BOOL bVert)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 }
ProcessSelChanged()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 }
CFWL_ListBoxImpDelegate(CFWL_ListBoxImp * pOwner)980 CFWL_ListBoxImpDelegate::CFWL_ListBoxImpDelegate(CFWL_ListBoxImp* pOwner)
981     : m_pOwner(pOwner) {}
OnProcessMessage(CFWL_Message * pMessage)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 }
OnProcessEvent(CFWL_Event * pEvent)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 }
OnDrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)1044 FWL_ERR CFWL_ListBoxImpDelegate::OnDrawWidget(CFX_Graphics* pGraphics,
1045                                               const CFX_Matrix* pMatrix) {
1046   return m_pOwner->DrawWidget(pGraphics, pMatrix);
1047 }
OnFocusChanged(CFWL_Message * pMsg,FX_BOOL bSet)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 }
OnLButtonDown(CFWL_MsgMouse * pMsg)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 }
OnLButtonUp(CFWL_MsgMouse * pMsg)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 }
OnMouseWheel(CFWL_MsgMouseWheel * pMsg)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 }
OnKeyDown(CFWL_MsgKey * pMsg)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 }
OnVK(FWL_HLISTITEM hItem,FX_BOOL bShift,FX_BOOL bCtrl)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 }
OnScroll(IFWL_ScrollBar * pScrollBar,FX_DWORD dwCode,FX_FLOAT fPos)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 }
DispatchSelChangedEv()1236 void CFWL_ListBoxImpDelegate::DispatchSelChangedEv() {
1237   CFWL_EvtLtbSelChanged ev;
1238   ev.m_pSrcTarget = m_pOwner->m_pInterface;
1239   m_pOwner->DispatchEvent(&ev);
1240 }
1241