• 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 "fpdfsdk/pwl/cpwl_list_box.h"
8 
9 #include <sstream>
10 
11 #include "core/fxge/cfx_renderdevice.h"
12 #include "fpdfsdk/pwl/cpwl_edit.h"
13 #include "fpdfsdk/pwl/cpwl_edit_ctrl.h"
14 #include "fpdfsdk/pwl/cpwl_edit_impl.h"
15 #include "fpdfsdk/pwl/cpwl_list_impl.h"
16 #include "fpdfsdk/pwl/cpwl_scroll_bar.h"
17 #include "fpdfsdk/pwl/cpwl_wnd.h"
18 #include "public/fpdf_fwlevent.h"
19 #include "third_party/base/ptr_util.h"
20 
CPWL_List_Notify(CPWL_ListBox * pList)21 CPWL_List_Notify::CPWL_List_Notify(CPWL_ListBox* pList) : m_pList(pList) {
22   ASSERT(m_pList);
23 }
24 
~CPWL_List_Notify()25 CPWL_List_Notify::~CPWL_List_Notify() {}
26 
IOnSetScrollInfoY(float fPlateMin,float fPlateMax,float fContentMin,float fContentMax,float fSmallStep,float fBigStep)27 void CPWL_List_Notify::IOnSetScrollInfoY(float fPlateMin,
28                                          float fPlateMax,
29                                          float fContentMin,
30                                          float fContentMax,
31                                          float fSmallStep,
32                                          float fBigStep) {
33   PWL_SCROLL_INFO Info;
34   Info.fPlateWidth = fPlateMax - fPlateMin;
35   Info.fContentMin = fContentMin;
36   Info.fContentMax = fContentMax;
37   Info.fSmallStep = fSmallStep;
38   Info.fBigStep = fBigStep;
39   m_pList->SetScrollInfo(Info);
40 
41   CPWL_ScrollBar* pScroll = m_pList->GetVScrollBar();
42   if (!pScroll)
43     return;
44 
45   if (IsFloatBigger(Info.fPlateWidth, Info.fContentMax - Info.fContentMin) ||
46       IsFloatEqual(Info.fPlateWidth, Info.fContentMax - Info.fContentMin)) {
47     if (pScroll->IsVisible()) {
48       pScroll->SetVisible(false);
49       m_pList->RePosChildWnd();
50     }
51   } else {
52     if (!pScroll->IsVisible()) {
53       pScroll->SetVisible(true);
54       m_pList->RePosChildWnd();
55     }
56   }
57 }
58 
IOnSetScrollPosY(float fy)59 void CPWL_List_Notify::IOnSetScrollPosY(float fy) {
60   m_pList->SetScrollPosition(fy);
61 }
62 
IOnInvalidateRect(CFX_FloatRect * pRect)63 void CPWL_List_Notify::IOnInvalidateRect(CFX_FloatRect* pRect) {
64   m_pList->InvalidateRect(pRect);
65 }
66 
CPWL_ListBox()67 CPWL_ListBox::CPWL_ListBox()
68     : m_pList(new CPWL_ListCtrl),
69       m_bMouseDown(false),
70       m_bHoverSel(false),
71       m_pFillerNotify(nullptr) {}
72 
~CPWL_ListBox()73 CPWL_ListBox::~CPWL_ListBox() {}
74 
GetClassName() const75 ByteString CPWL_ListBox::GetClassName() const {
76   return "CPWL_ListBox";
77 }
78 
OnCreated()79 void CPWL_ListBox::OnCreated() {
80   m_pList->SetFontMap(GetFontMap());
81   m_pListNotify = pdfium::MakeUnique<CPWL_List_Notify>(this);
82   m_pList->SetNotify(m_pListNotify.get());
83 
84   SetHoverSel(HasFlag(PLBS_HOVERSEL));
85   m_pList->SetMultipleSel(HasFlag(PLBS_MULTIPLESEL));
86   m_pList->SetFontSize(GetCreationParams().fFontSize);
87 
88   m_bHoverSel = HasFlag(PLBS_HOVERSEL);
89 }
90 
OnDestroy()91 void CPWL_ListBox::OnDestroy() {
92   // Make sure the notifier is removed from the list as we are about to
93   // destroy the notifier and don't want to leave a dangling pointer.
94   m_pList->SetNotify(nullptr);
95   m_pListNotify.reset();
96 }
97 
DrawThisAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)98 void CPWL_ListBox::DrawThisAppearance(CFX_RenderDevice* pDevice,
99                                       const CFX_Matrix& mtUser2Device) {
100   CPWL_Wnd::DrawThisAppearance(pDevice, mtUser2Device);
101 
102   CFX_FloatRect rcPlate = m_pList->GetPlateRect();
103   CFX_FloatRect rcList = GetListRect();
104   CFX_FloatRect rcClient = GetClientRect();
105 
106   for (int32_t i = 0, sz = m_pList->GetCount(); i < sz; i++) {
107     CFX_FloatRect rcItem = m_pList->GetItemRect(i);
108     if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom)
109       continue;
110 
111     CFX_PointF ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f);
112     if (CPWL_EditImpl* pEdit = m_pList->GetItemEdit(i)) {
113       CFX_FloatRect rcContent = pEdit->GetContentRect();
114       if (rcContent.Width() > rcClient.Width())
115         rcItem.Intersect(rcList);
116       else
117         rcItem.Intersect(rcClient);
118     }
119 
120     if (m_pList->IsItemSelected(i)) {
121       CFX_SystemHandler* pSysHandler = GetSystemHandler();
122       if (pSysHandler && pSysHandler->IsSelectionImplemented()) {
123         CPWL_EditImpl::DrawEdit(pDevice, mtUser2Device, m_pList->GetItemEdit(i),
124                                 GetTextColor().ToFXColor(255), rcList, ptOffset,
125                                 nullptr, pSysHandler, m_pFormFiller.Get());
126         pSysHandler->OutputSelectedRect(m_pFormFiller.Get(), rcItem);
127       } else {
128         pDevice->DrawFillRect(&mtUser2Device, rcItem,
129                               ArgbEncode(255, 0, 51, 113));
130         CPWL_EditImpl::DrawEdit(pDevice, mtUser2Device, m_pList->GetItemEdit(i),
131                                 ArgbEncode(255, 255, 255, 255), rcList,
132                                 ptOffset, nullptr, pSysHandler,
133                                 m_pFormFiller.Get());
134       }
135     } else {
136       CFX_SystemHandler* pSysHandler = GetSystemHandler();
137       CPWL_EditImpl::DrawEdit(pDevice, mtUser2Device, m_pList->GetItemEdit(i),
138                               GetTextColor().ToFXColor(255), rcList, ptOffset,
139                               nullptr, pSysHandler, nullptr);
140     }
141   }
142 }
143 
OnKeyDown(uint16_t nChar,uint32_t nFlag)144 bool CPWL_ListBox::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
145   CPWL_Wnd::OnKeyDown(nChar, nFlag);
146 
147   switch (nChar) {
148     default:
149       return false;
150     case FWL_VKEY_Up:
151     case FWL_VKEY_Down:
152     case FWL_VKEY_Home:
153     case FWL_VKEY_Left:
154     case FWL_VKEY_End:
155     case FWL_VKEY_Right:
156       break;
157   }
158 
159   switch (nChar) {
160     case FWL_VKEY_Up:
161       m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
162       break;
163     case FWL_VKEY_Down:
164       m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
165       break;
166     case FWL_VKEY_Home:
167       m_pList->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
168       break;
169     case FWL_VKEY_Left:
170       m_pList->OnVK_LEFT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
171       break;
172     case FWL_VKEY_End:
173       m_pList->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
174       break;
175     case FWL_VKEY_Right:
176       m_pList->OnVK_RIGHT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
177       break;
178     case FWL_VKEY_Delete:
179       break;
180   }
181   OnNotifySelectionChanged(true, nFlag);
182   return true;
183 }
184 
OnChar(uint16_t nChar,uint32_t nFlag)185 bool CPWL_ListBox::OnChar(uint16_t nChar, uint32_t nFlag) {
186   CPWL_Wnd::OnChar(nChar, nFlag);
187 
188   if (!m_pList->OnChar(nChar, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)))
189     return false;
190 
191   OnNotifySelectionChanged(true, nFlag);
192   return true;
193 }
194 
OnLButtonDown(const CFX_PointF & point,uint32_t nFlag)195 bool CPWL_ListBox::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
196   CPWL_Wnd::OnLButtonDown(point, nFlag);
197 
198   if (ClientHitTest(point)) {
199     m_bMouseDown = true;
200     SetFocus();
201     SetCapture();
202 
203     m_pList->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
204   }
205 
206   return true;
207 }
208 
OnLButtonUp(const CFX_PointF & point,uint32_t nFlag)209 bool CPWL_ListBox::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
210   CPWL_Wnd::OnLButtonUp(point, nFlag);
211 
212   if (m_bMouseDown) {
213     ReleaseCapture();
214     m_bMouseDown = false;
215   }
216   OnNotifySelectionChanged(false, nFlag);
217   return true;
218 }
219 
SetHoverSel(bool bHoverSel)220 void CPWL_ListBox::SetHoverSel(bool bHoverSel) {
221   m_bHoverSel = bHoverSel;
222 }
223 
OnMouseMove(const CFX_PointF & point,uint32_t nFlag)224 bool CPWL_ListBox::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
225   CPWL_Wnd::OnMouseMove(point, nFlag);
226 
227   if (m_bHoverSel && !IsCaptureMouse() && ClientHitTest(point))
228     m_pList->Select(m_pList->GetItemIndex(point));
229   if (m_bMouseDown)
230     m_pList->OnMouseMove(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
231 
232   return true;
233 }
234 
SetScrollInfo(const PWL_SCROLL_INFO & info)235 void CPWL_ListBox::SetScrollInfo(const PWL_SCROLL_INFO& info) {
236   if (CPWL_Wnd* pChild = GetVScrollBar())
237     pChild->SetScrollInfo(info);
238 }
239 
SetScrollPosition(float pos)240 void CPWL_ListBox::SetScrollPosition(float pos) {
241   if (CPWL_Wnd* pChild = GetVScrollBar())
242     pChild->SetScrollPosition(pos);
243 }
244 
ScrollWindowVertically(float pos)245 void CPWL_ListBox::ScrollWindowVertically(float pos) {
246   m_pList->SetScrollPos(CFX_PointF(0, pos));
247 }
248 
KillFocus()249 void CPWL_ListBox::KillFocus() {
250   CPWL_Wnd::KillFocus();
251 }
252 
RePosChildWnd()253 bool CPWL_ListBox::RePosChildWnd() {
254   if (!CPWL_Wnd::RePosChildWnd())
255     return false;
256 
257   m_pList->SetPlateRect(GetListRect());
258   return true;
259 }
260 
OnNotifySelectionChanged(bool bKeyDown,uint32_t nFlag)261 bool CPWL_ListBox::OnNotifySelectionChanged(bool bKeyDown, uint32_t nFlag) {
262   if (!m_pFillerNotify)
263     return false;
264 
265   CPWL_Wnd::ObservedPtr thisObserved(this);
266 
267   WideString swChange = GetText();
268   WideString strChangeEx;
269   int nSelStart = 0;
270   int nSelEnd = swChange.GetLength();
271   bool bRC;
272   bool bExit;
273   std::tie(bRC, bExit) = m_pFillerNotify->OnBeforeKeyStroke(
274       GetAttachedData(), swChange, strChangeEx, nSelStart, nSelEnd, bKeyDown,
275       nFlag);
276 
277   if (!thisObserved)
278     return false;
279 
280   return bExit;
281 }
282 
GetFocusRect() const283 CFX_FloatRect CPWL_ListBox::GetFocusRect() const {
284   if (m_pList->IsMultipleSel()) {
285     CFX_FloatRect rcCaret = m_pList->GetItemRect(m_pList->GetCaret());
286     rcCaret.Intersect(GetClientRect());
287     return rcCaret;
288   }
289 
290   return CPWL_Wnd::GetFocusRect();
291 }
292 
AddString(const WideString & str)293 void CPWL_ListBox::AddString(const WideString& str) {
294   m_pList->AddString(str);
295 }
296 
GetText() const297 WideString CPWL_ListBox::GetText() const {
298   return m_pList->GetText();
299 }
300 
SetFontSize(float fFontSize)301 void CPWL_ListBox::SetFontSize(float fFontSize) {
302   m_pList->SetFontSize(fFontSize);
303 }
304 
GetFontSize() const305 float CPWL_ListBox::GetFontSize() const {
306   return m_pList->GetFontSize();
307 }
308 
Select(int32_t nItemIndex)309 void CPWL_ListBox::Select(int32_t nItemIndex) {
310   m_pList->Select(nItemIndex);
311 }
312 
SetCaret(int32_t nItemIndex)313 void CPWL_ListBox::SetCaret(int32_t nItemIndex) {
314   m_pList->SetCaret(nItemIndex);
315 }
316 
SetTopVisibleIndex(int32_t nItemIndex)317 void CPWL_ListBox::SetTopVisibleIndex(int32_t nItemIndex) {
318   m_pList->SetTopItem(nItemIndex);
319 }
320 
ScrollToListItem(int32_t nItemIndex)321 void CPWL_ListBox::ScrollToListItem(int32_t nItemIndex) {
322   m_pList->ScrollToListItem(nItemIndex);
323 }
324 
ResetContent()325 void CPWL_ListBox::ResetContent() {
326   m_pList->Empty();
327 }
328 
Reset()329 void CPWL_ListBox::Reset() {
330   m_pList->Cancel();
331 }
332 
IsMultipleSel() const333 bool CPWL_ListBox::IsMultipleSel() const {
334   return m_pList->IsMultipleSel();
335 }
336 
GetCaretIndex() const337 int32_t CPWL_ListBox::GetCaretIndex() const {
338   return m_pList->GetCaret();
339 }
340 
GetCurSel() const341 int32_t CPWL_ListBox::GetCurSel() const {
342   return m_pList->GetSelect();
343 }
344 
IsItemSelected(int32_t nItemIndex) const345 bool CPWL_ListBox::IsItemSelected(int32_t nItemIndex) const {
346   return m_pList->IsItemSelected(nItemIndex);
347 }
348 
GetTopVisibleIndex() const349 int32_t CPWL_ListBox::GetTopVisibleIndex() const {
350   m_pList->ScrollToListItem(m_pList->GetFirstSelected());
351   return m_pList->GetTopItem();
352 }
353 
GetCount() const354 int32_t CPWL_ListBox::GetCount() const {
355   return m_pList->GetCount();
356 }
357 
FindNext(int32_t nIndex,wchar_t nChar) const358 int32_t CPWL_ListBox::FindNext(int32_t nIndex, wchar_t nChar) const {
359   return m_pList->FindNext(nIndex, nChar);
360 }
361 
GetContentRect() const362 CFX_FloatRect CPWL_ListBox::GetContentRect() const {
363   return m_pList->GetContentRect();
364 }
365 
GetFirstHeight() const366 float CPWL_ListBox::GetFirstHeight() const {
367   return m_pList->GetFirstHeight();
368 }
369 
GetListRect() const370 CFX_FloatRect CPWL_ListBox::GetListRect() const {
371   float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
372   return GetWindowRect().GetDeflated(width, width);
373 }
374 
OnMouseWheel(short zDelta,const CFX_PointF & point,uint32_t nFlag)375 bool CPWL_ListBox::OnMouseWheel(short zDelta,
376                                 const CFX_PointF& point,
377                                 uint32_t nFlag) {
378   if (zDelta < 0)
379     m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
380   else
381     m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
382 
383   OnNotifySelectionChanged(false, nFlag);
384   return true;
385 }
386