• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "fpdfsdk/pwl/cpwl_list_box.h"
8 
9 #include <sstream>
10 #include <utility>
11 
12 #include "core/fxge/cfx_renderdevice.h"
13 #include "fpdfsdk/pwl/cpwl_edit.h"
14 #include "fpdfsdk/pwl/cpwl_edit_impl.h"
15 #include "fpdfsdk/pwl/cpwl_scroll_bar.h"
16 #include "fpdfsdk/pwl/ipwl_fillernotify.h"
17 #include "public/fpdf_fwlevent.h"
18 #include "third_party/base/numerics/safe_conversions.h"
19 
CPWL_ListBox(const CreateParams & cp,std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData)20 CPWL_ListBox::CPWL_ListBox(
21     const CreateParams& cp,
22     std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData)
23     : CPWL_Wnd(cp, std::move(pAttachedData)),
24       m_pListCtrl(std::make_unique<CPWL_ListCtrl>()) {}
25 
26 CPWL_ListBox::~CPWL_ListBox() = default;
27 
OnCreated()28 void CPWL_ListBox::OnCreated() {
29   m_pListCtrl->SetFontMap(GetFontMap());
30   m_pListCtrl->SetNotify(this);
31 
32   SetHoverSel(HasFlag(PLBS_HOVERSEL));
33   m_pListCtrl->SetMultipleSel(HasFlag(PLBS_MULTIPLESEL));
34   m_pListCtrl->SetFontSize(GetCreationParams()->fFontSize);
35 
36   m_bHoverSel = HasFlag(PLBS_HOVERSEL);
37 }
38 
OnDestroy()39 void CPWL_ListBox::OnDestroy() {
40   // Make sure the notifier is removed from the list as we are about to
41   // destroy the notifier and don't want to leave a dangling pointer.
42   m_pListCtrl->SetNotify(nullptr);
43 }
44 
DrawThisAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)45 void CPWL_ListBox::DrawThisAppearance(CFX_RenderDevice* pDevice,
46                                       const CFX_Matrix& mtUser2Device) {
47   CPWL_Wnd::DrawThisAppearance(pDevice, mtUser2Device);
48 
49   CFX_FloatRect rcPlate = m_pListCtrl->GetPlateRect();
50   CFX_FloatRect rcList = GetListRect();
51   CFX_FloatRect rcClient = GetClientRect();
52 
53   for (int32_t i = 0, sz = m_pListCtrl->GetCount(); i < sz; i++) {
54     CFX_FloatRect rcItem = m_pListCtrl->GetItemRect(i);
55     if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom)
56       continue;
57 
58     CFX_PointF ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f);
59     if (CPWL_EditImpl* pEdit = m_pListCtrl->GetItemEdit(i)) {
60       CFX_FloatRect rcContent = pEdit->GetContentRect();
61       rcItem.Intersect(rcContent.Width() > rcClient.Width() ? rcList
62                                                             : rcClient);
63     }
64 
65     IPWL_FillerNotify* pSysHandler = GetFillerNotify();
66     if (m_pListCtrl->IsItemSelected(i)) {
67       if (pSysHandler->IsSelectionImplemented()) {
68         m_pListCtrl->GetItemEdit(i)->DrawEdit(
69             pDevice, mtUser2Device, GetTextColor().ToFXColor(255), rcList,
70             ptOffset, nullptr, pSysHandler, GetAttachedData());
71         pSysHandler->OutputSelectedRect(GetAttachedData(), rcItem);
72       } else {
73         pDevice->DrawFillRect(&mtUser2Device, rcItem,
74                               ArgbEncode(255, 0, 51, 113));
75         m_pListCtrl->GetItemEdit(i)->DrawEdit(
76             pDevice, mtUser2Device, ArgbEncode(255, 255, 255, 255), rcList,
77             ptOffset, nullptr, pSysHandler, GetAttachedData());
78       }
79     } else {
80       m_pListCtrl->GetItemEdit(i)->DrawEdit(
81           pDevice, mtUser2Device, GetTextColor().ToFXColor(255), rcList,
82           ptOffset, nullptr, pSysHandler, nullptr);
83     }
84   }
85 }
86 
OnKeyDown(FWL_VKEYCODE nKeyCode,Mask<FWL_EVENTFLAG> nFlag)87 bool CPWL_ListBox::OnKeyDown(FWL_VKEYCODE nKeyCode, Mask<FWL_EVENTFLAG> nFlag) {
88   CPWL_Wnd::OnKeyDown(nKeyCode, nFlag);
89 
90   switch (nKeyCode) {
91     default:
92       return false;
93     case FWL_VKEY_Up:
94     case FWL_VKEY_Down:
95     case FWL_VKEY_Home:
96     case FWL_VKEY_Left:
97     case FWL_VKEY_End:
98     case FWL_VKEY_Right:
99       break;
100   }
101 
102   switch (nKeyCode) {
103     case FWL_VKEY_Up:
104       m_pListCtrl->OnVK_UP(IsSHIFTKeyDown(nFlag), IsCTRLKeyDown(nFlag));
105       break;
106     case FWL_VKEY_Down:
107       m_pListCtrl->OnVK_DOWN(IsSHIFTKeyDown(nFlag), IsCTRLKeyDown(nFlag));
108       break;
109     case FWL_VKEY_Home:
110       m_pListCtrl->OnVK_HOME(IsSHIFTKeyDown(nFlag), IsCTRLKeyDown(nFlag));
111       break;
112     case FWL_VKEY_Left:
113       m_pListCtrl->OnVK_LEFT(IsSHIFTKeyDown(nFlag), IsCTRLKeyDown(nFlag));
114       break;
115     case FWL_VKEY_End:
116       m_pListCtrl->OnVK_END(IsSHIFTKeyDown(nFlag), IsCTRLKeyDown(nFlag));
117       break;
118     case FWL_VKEY_Right:
119       m_pListCtrl->OnVK_RIGHT(IsSHIFTKeyDown(nFlag), IsCTRLKeyDown(nFlag));
120       break;
121     default:
122       break;
123   }
124   OnNotifySelectionChanged(true, nFlag);
125   return true;
126 }
127 
OnChar(uint16_t nChar,Mask<FWL_EVENTFLAG> nFlag)128 bool CPWL_ListBox::OnChar(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
129   CPWL_Wnd::OnChar(nChar, nFlag);
130 
131   if (!m_pListCtrl->OnChar(nChar, IsSHIFTKeyDown(nFlag), IsCTRLKeyDown(nFlag)))
132     return false;
133 
134   OnNotifySelectionChanged(true, nFlag);
135   return true;
136 }
137 
OnLButtonDown(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point)138 bool CPWL_ListBox::OnLButtonDown(Mask<FWL_EVENTFLAG> nFlag,
139                                  const CFX_PointF& point) {
140   CPWL_Wnd::OnLButtonDown(nFlag, point);
141 
142   if (ClientHitTest(point)) {
143     m_bMouseDown = true;
144     SetFocus();
145     SetCapture();
146 
147     m_pListCtrl->OnMouseDown(point, IsSHIFTKeyDown(nFlag),
148                              IsCTRLKeyDown(nFlag));
149   }
150 
151   return true;
152 }
153 
OnLButtonUp(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point)154 bool CPWL_ListBox::OnLButtonUp(Mask<FWL_EVENTFLAG> nFlag,
155                                const CFX_PointF& point) {
156   CPWL_Wnd::OnLButtonUp(nFlag, point);
157 
158   if (m_bMouseDown) {
159     ReleaseCapture();
160     m_bMouseDown = false;
161   }
162   OnNotifySelectionChanged(false, nFlag);
163   return true;
164 }
165 
SetHoverSel(bool bHoverSel)166 void CPWL_ListBox::SetHoverSel(bool bHoverSel) {
167   m_bHoverSel = bHoverSel;
168 }
169 
OnMouseMove(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point)170 bool CPWL_ListBox::OnMouseMove(Mask<FWL_EVENTFLAG> nFlag,
171                                const CFX_PointF& point) {
172   CPWL_Wnd::OnMouseMove(nFlag, point);
173 
174   if (m_bHoverSel && !IsCaptureMouse() && ClientHitTest(point))
175     m_pListCtrl->Select(m_pListCtrl->GetItemIndex(point));
176   if (m_bMouseDown)
177     m_pListCtrl->OnMouseMove(point, IsSHIFTKeyDown(nFlag),
178                              IsCTRLKeyDown(nFlag));
179 
180   return true;
181 }
182 
SetScrollInfo(const PWL_SCROLL_INFO & info)183 void CPWL_ListBox::SetScrollInfo(const PWL_SCROLL_INFO& info) {
184   if (CPWL_Wnd* pChild = GetVScrollBar())
185     pChild->SetScrollInfo(info);
186 }
187 
SetScrollPosition(float pos)188 void CPWL_ListBox::SetScrollPosition(float pos) {
189   if (CPWL_Wnd* pChild = GetVScrollBar())
190     pChild->SetScrollPosition(pos);
191 }
192 
ScrollWindowVertically(float pos)193 void CPWL_ListBox::ScrollWindowVertically(float pos) {
194   m_pListCtrl->SetScrollPos(CFX_PointF(0, pos));
195 }
196 
RePosChildWnd()197 bool CPWL_ListBox::RePosChildWnd() {
198   if (!CPWL_Wnd::RePosChildWnd())
199     return false;
200 
201   m_pListCtrl->SetPlateRect(GetListRect());
202   return true;
203 }
204 
OnNotifySelectionChanged(bool bKeyDown,Mask<FWL_EVENTFLAG> nFlag)205 bool CPWL_ListBox::OnNotifySelectionChanged(bool bKeyDown,
206                                             Mask<FWL_EVENTFLAG> nFlag) {
207   ObservedPtr<CPWL_Wnd> thisObserved(this);
208 
209   WideString swChange = GetText();
210   WideString strChangeEx;
211   int nSelStart = 0;
212   int nSelEnd = pdfium::base::checked_cast<int>(swChange.GetLength());
213   bool bRC;
214   bool bExit;
215   std::tie(bRC, bExit) = GetFillerNotify()->OnBeforeKeyStroke(
216       GetAttachedData(), swChange, strChangeEx, nSelStart, nSelEnd, bKeyDown,
217       nFlag);
218 
219   if (!thisObserved)
220     return false;
221 
222   return bExit;
223 }
224 
GetFocusRect() const225 CFX_FloatRect CPWL_ListBox::GetFocusRect() const {
226   if (m_pListCtrl->IsMultipleSel()) {
227     CFX_FloatRect rcCaret = m_pListCtrl->GetItemRect(m_pListCtrl->GetCaret());
228     rcCaret.Intersect(GetClientRect());
229     return rcCaret;
230   }
231 
232   return CPWL_Wnd::GetFocusRect();
233 }
234 
AddString(const WideString & str)235 void CPWL_ListBox::AddString(const WideString& str) {
236   m_pListCtrl->AddString(str);
237 }
238 
GetText()239 WideString CPWL_ListBox::GetText() {
240   return m_pListCtrl->GetText();
241 }
242 
SetFontSize(float fFontSize)243 void CPWL_ListBox::SetFontSize(float fFontSize) {
244   m_pListCtrl->SetFontSize(fFontSize);
245 }
246 
GetFontSize() const247 float CPWL_ListBox::GetFontSize() const {
248   return m_pListCtrl->GetFontSize();
249 }
250 
OnSetScrollInfoY(float fPlateMin,float fPlateMax,float fContentMin,float fContentMax,float fSmallStep,float fBigStep)251 void CPWL_ListBox::OnSetScrollInfoY(float fPlateMin,
252                                     float fPlateMax,
253                                     float fContentMin,
254                                     float fContentMax,
255                                     float fSmallStep,
256                                     float fBigStep) {
257   PWL_SCROLL_INFO Info;
258   Info.fPlateWidth = fPlateMax - fPlateMin;
259   Info.fContentMin = fContentMin;
260   Info.fContentMax = fContentMax;
261   Info.fSmallStep = fSmallStep;
262   Info.fBigStep = fBigStep;
263   SetScrollInfo(Info);
264 
265   CPWL_ScrollBar* pScroll = GetVScrollBar();
266   if (!pScroll)
267     return;
268 
269   if (FXSYS_IsFloatBigger(Info.fPlateWidth,
270                           Info.fContentMax - Info.fContentMin) ||
271       FXSYS_IsFloatEqual(Info.fPlateWidth,
272                          Info.fContentMax - Info.fContentMin)) {
273     if (pScroll->IsVisible()) {
274       pScroll->SetVisible(false);
275       RePosChildWnd();
276     }
277   } else {
278     if (!pScroll->IsVisible()) {
279       pScroll->SetVisible(true);
280       RePosChildWnd();
281     }
282   }
283 }
284 
OnSetScrollPosY(float fy)285 void CPWL_ListBox::OnSetScrollPosY(float fy) {
286   SetScrollPosition(fy);
287 }
288 
OnInvalidateRect(const CFX_FloatRect & rect)289 void CPWL_ListBox::OnInvalidateRect(const CFX_FloatRect& rect) {
290   InvalidateRect(&rect);
291 }
292 
Select(int32_t nItemIndex)293 void CPWL_ListBox::Select(int32_t nItemIndex) {
294   m_pListCtrl->Select(nItemIndex);
295 }
296 
Deselect(int32_t nItemIndex)297 void CPWL_ListBox::Deselect(int32_t nItemIndex) {
298   m_pListCtrl->Deselect(nItemIndex);
299 }
300 
SetCaret(int32_t nItemIndex)301 void CPWL_ListBox::SetCaret(int32_t nItemIndex) {
302   m_pListCtrl->SetCaret(nItemIndex);
303 }
304 
SetTopVisibleIndex(int32_t nItemIndex)305 void CPWL_ListBox::SetTopVisibleIndex(int32_t nItemIndex) {
306   m_pListCtrl->SetTopItem(nItemIndex);
307 }
308 
ScrollToListItem(int32_t nItemIndex)309 void CPWL_ListBox::ScrollToListItem(int32_t nItemIndex) {
310   m_pListCtrl->ScrollToListItem(nItemIndex);
311 }
312 
IsMultipleSel() const313 bool CPWL_ListBox::IsMultipleSel() const {
314   return m_pListCtrl->IsMultipleSel();
315 }
316 
GetCaretIndex() const317 int32_t CPWL_ListBox::GetCaretIndex() const {
318   return m_pListCtrl->GetCaret();
319 }
320 
GetCurSel() const321 int32_t CPWL_ListBox::GetCurSel() const {
322   return m_pListCtrl->GetSelect();
323 }
324 
IsItemSelected(int32_t nItemIndex) const325 bool CPWL_ListBox::IsItemSelected(int32_t nItemIndex) const {
326   return m_pListCtrl->IsItemSelected(nItemIndex);
327 }
328 
GetTopVisibleIndex() const329 int32_t CPWL_ListBox::GetTopVisibleIndex() const {
330   m_pListCtrl->ScrollToListItem(m_pListCtrl->GetFirstSelected());
331   return m_pListCtrl->GetTopItem();
332 }
333 
GetCount() const334 int32_t CPWL_ListBox::GetCount() const {
335   return m_pListCtrl->GetCount();
336 }
337 
GetContentRect() const338 CFX_FloatRect CPWL_ListBox::GetContentRect() const {
339   return m_pListCtrl->GetContentRect();
340 }
341 
GetFirstHeight() const342 float CPWL_ListBox::GetFirstHeight() const {
343   return m_pListCtrl->GetFirstHeight();
344 }
345 
GetListRect() const346 CFX_FloatRect CPWL_ListBox::GetListRect() const {
347   float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
348   return GetWindowRect().GetDeflated(width, width);
349 }
350 
OnMouseWheel(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point,const CFX_Vector & delta)351 bool CPWL_ListBox::OnMouseWheel(Mask<FWL_EVENTFLAG> nFlag,
352                                 const CFX_PointF& point,
353                                 const CFX_Vector& delta) {
354   if (delta.y < 0)
355     m_pListCtrl->OnVK_DOWN(IsSHIFTKeyDown(nFlag), IsCTRLKeyDown(nFlag));
356   else
357     m_pListCtrl->OnVK_UP(IsSHIFTKeyDown(nFlag), IsCTRLKeyDown(nFlag));
358 
359   OnNotifySelectionChanged(false, nFlag);
360   return true;
361 }
362