• 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/pdfwindow/PWL_ListBox.h"
8 
9 #include "fpdfsdk/fxedit/fxet_edit.h"
10 #include "fpdfsdk/fxedit/fxet_list.h"
11 #include "fpdfsdk/pdfwindow/PWL_Edit.h"
12 #include "fpdfsdk/pdfwindow/PWL_EditCtrl.h"
13 #include "fpdfsdk/pdfwindow/PWL_ScrollBar.h"
14 #include "fpdfsdk/pdfwindow/PWL_Utils.h"
15 #include "fpdfsdk/pdfwindow/PWL_Wnd.h"
16 #include "public/fpdf_fwlevent.h"
17 #include "third_party/base/ptr_util.h"
18 
CPWL_List_Notify(CPWL_ListBox * pList)19 CPWL_List_Notify::CPWL_List_Notify(CPWL_ListBox* pList) : m_pList(pList) {
20   ASSERT(m_pList);
21 }
22 
~CPWL_List_Notify()23 CPWL_List_Notify::~CPWL_List_Notify() {}
24 
IOnSetScrollInfoY(FX_FLOAT fPlateMin,FX_FLOAT fPlateMax,FX_FLOAT fContentMin,FX_FLOAT fContentMax,FX_FLOAT fSmallStep,FX_FLOAT fBigStep)25 void CPWL_List_Notify::IOnSetScrollInfoY(FX_FLOAT fPlateMin,
26                                          FX_FLOAT fPlateMax,
27                                          FX_FLOAT fContentMin,
28                                          FX_FLOAT fContentMax,
29                                          FX_FLOAT fSmallStep,
30                                          FX_FLOAT fBigStep) {
31   PWL_SCROLL_INFO Info;
32 
33   Info.fPlateWidth = fPlateMax - fPlateMin;
34   Info.fContentMin = fContentMin;
35   Info.fContentMax = fContentMax;
36   Info.fSmallStep = fSmallStep;
37   Info.fBigStep = fBigStep;
38 
39   m_pList->OnNotify(m_pList, PNM_SETSCROLLINFO, SBT_VSCROLL, (intptr_t)&Info);
40 
41   if (CPWL_ScrollBar* pScroll = m_pList->GetVScrollBar()) {
42     if (IsFloatBigger(Info.fPlateWidth, Info.fContentMax - Info.fContentMin) ||
43         IsFloatEqual(Info.fPlateWidth, Info.fContentMax - Info.fContentMin)) {
44       if (pScroll->IsVisible()) {
45         pScroll->SetVisible(false);
46         m_pList->RePosChildWnd();
47       }
48     } else {
49       if (!pScroll->IsVisible()) {
50         pScroll->SetVisible(true);
51         m_pList->RePosChildWnd();
52       }
53     }
54   }
55 }
56 
IOnSetScrollPosY(FX_FLOAT fy)57 void CPWL_List_Notify::IOnSetScrollPosY(FX_FLOAT fy) {
58   m_pList->OnNotify(m_pList, PNM_SETSCROLLPOS, SBT_VSCROLL, (intptr_t)&fy);
59 }
60 
IOnInvalidateRect(CFX_FloatRect * pRect)61 void CPWL_List_Notify::IOnInvalidateRect(CFX_FloatRect* pRect) {
62   m_pList->InvalidateRect(pRect);
63 }
64 
CPWL_ListBox()65 CPWL_ListBox::CPWL_ListBox()
66     : m_pList(new CFX_ListCtrl),
67       m_bMouseDown(false),
68       m_bHoverSel(false),
69       m_pFillerNotify(nullptr) {}
70 
~CPWL_ListBox()71 CPWL_ListBox::~CPWL_ListBox() {
72 }
73 
GetClassName() const74 CFX_ByteString CPWL_ListBox::GetClassName() const {
75   return "CPWL_ListBox";
76 }
77 
OnCreated()78 void CPWL_ListBox::OnCreated() {
79   m_pList->SetFontMap(GetFontMap());
80   m_pListNotify = pdfium::MakeUnique<CPWL_List_Notify>(this);
81   m_pList->SetNotify(m_pListNotify.get());
82 
83   SetHoverSel(HasFlag(PLBS_HOVERSEL));
84   m_pList->SetMultipleSel(HasFlag(PLBS_MULTIPLESEL));
85   m_pList->SetFontSize(GetCreationParam().fFontSize);
86 
87   m_bHoverSel = HasFlag(PLBS_HOVERSEL);
88 }
89 
OnDestroy()90 void CPWL_ListBox::OnDestroy() {
91   // Make sure the notifier is removed from the list as we are about to
92   // destroy the notifier and don't want to leave a dangling pointer.
93   m_pList->SetNotify(nullptr);
94   m_pListNotify.reset();
95 }
96 
GetThisAppearanceStream(CFX_ByteTextBuf & sAppStream)97 void CPWL_ListBox::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) {
98   CPWL_Wnd::GetThisAppearanceStream(sAppStream);
99 
100   CFX_ByteTextBuf sListItems;
101 
102   CFX_FloatRect rcPlate = m_pList->GetPlateRect();
103   for (int32_t i = 0, sz = m_pList->GetCount(); i < sz; i++) {
104     CFX_FloatRect rcItem = m_pList->GetItemRect(i);
105 
106     if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom)
107       continue;
108 
109     CFX_PointF ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f);
110     if (m_pList->IsItemSelected(i)) {
111       sListItems << CPWL_Utils::GetRectFillAppStream(rcItem,
112                                                      PWL_DEFAULT_SELBACKCOLOR)
113                         .AsStringC();
114       CFX_ByteString sItem =
115           CPWL_Utils::GetEditAppStream(m_pList->GetItemEdit(i), ptOffset);
116       if (sItem.GetLength() > 0) {
117         sListItems << "BT\n"
118                    << CPWL_Utils::GetColorAppStream(PWL_DEFAULT_SELTEXTCOLOR)
119                           .AsStringC()
120                    << sItem.AsStringC() << "ET\n";
121       }
122     } else {
123       CFX_ByteString sItem =
124           CPWL_Utils::GetEditAppStream(m_pList->GetItemEdit(i), ptOffset);
125       if (sItem.GetLength() > 0) {
126         sListItems << "BT\n"
127                    << CPWL_Utils::GetColorAppStream(GetTextColor()).AsStringC()
128                    << sItem.AsStringC() << "ET\n";
129       }
130     }
131   }
132 
133   if (sListItems.GetLength() > 0) {
134     CFX_ByteTextBuf sClip;
135     CFX_FloatRect rcClient = GetClientRect();
136 
137     sClip << "q\n";
138     sClip << rcClient.left << " " << rcClient.bottom << " "
139           << rcClient.right - rcClient.left << " "
140           << rcClient.top - rcClient.bottom << " re W n\n";
141 
142     sClip << sListItems << "Q\n";
143 
144     sAppStream << "/Tx BMC\n" << sClip << "EMC\n";
145   }
146 }
147 
DrawThisAppearance(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device)148 void CPWL_ListBox::DrawThisAppearance(CFX_RenderDevice* pDevice,
149                                       CFX_Matrix* pUser2Device) {
150   CPWL_Wnd::DrawThisAppearance(pDevice, pUser2Device);
151 
152   CFX_FloatRect rcPlate = m_pList->GetPlateRect();
153   CFX_FloatRect rcList = GetListRect();
154   CFX_FloatRect rcClient = GetClientRect();
155 
156   for (int32_t i = 0, sz = m_pList->GetCount(); i < sz; i++) {
157     CFX_FloatRect rcItem = m_pList->GetItemRect(i);
158     if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom)
159       continue;
160 
161     CFX_PointF ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f);
162     if (CFX_Edit* pEdit = m_pList->GetItemEdit(i)) {
163       CFX_FloatRect rcContent = pEdit->GetContentRect();
164       if (rcContent.Width() > rcClient.Width())
165         rcItem.Intersect(rcList);
166       else
167         rcItem.Intersect(rcClient);
168     }
169 
170     if (m_pList->IsItemSelected(i)) {
171       CFX_SystemHandler* pSysHandler = GetSystemHandler();
172       if (pSysHandler && pSysHandler->IsSelectionImplemented()) {
173         CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i),
174                            GetTextColor().ToFXColor(255), rcList, ptOffset,
175                            nullptr, pSysHandler, m_pFormFiller);
176         pSysHandler->OutputSelectedRect(m_pFormFiller, rcItem);
177       } else {
178         CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcItem,
179                                  ArgbEncode(255, 0, 51, 113));
180         CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i),
181                            ArgbEncode(255, 255, 255, 255), rcList, ptOffset,
182                            nullptr, pSysHandler, m_pFormFiller);
183       }
184     } else {
185       CFX_SystemHandler* pSysHandler = GetSystemHandler();
186       CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i),
187                          GetTextColor().ToFXColor(255), rcList, ptOffset,
188                          nullptr, pSysHandler, nullptr);
189     }
190   }
191 }
192 
OnKeyDown(uint16_t nChar,uint32_t nFlag)193 bool CPWL_ListBox::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
194   CPWL_Wnd::OnKeyDown(nChar, nFlag);
195 
196   switch (nChar) {
197     default:
198       return false;
199     case FWL_VKEY_Up:
200     case FWL_VKEY_Down:
201     case FWL_VKEY_Home:
202     case FWL_VKEY_Left:
203     case FWL_VKEY_End:
204     case FWL_VKEY_Right:
205       break;
206   }
207 
208   switch (nChar) {
209     case FWL_VKEY_Up:
210       m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
211       break;
212     case FWL_VKEY_Down:
213       m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
214       break;
215     case FWL_VKEY_Home:
216       m_pList->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
217       break;
218     case FWL_VKEY_Left:
219       m_pList->OnVK_LEFT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
220       break;
221     case FWL_VKEY_End:
222       m_pList->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
223       break;
224     case FWL_VKEY_Right:
225       m_pList->OnVK_RIGHT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
226       break;
227     case FWL_VKEY_Delete:
228       break;
229   }
230 
231   bool bExit = false;
232   OnNotifySelChanged(true, bExit, nFlag);
233 
234   return true;
235 }
236 
OnChar(uint16_t nChar,uint32_t nFlag)237 bool CPWL_ListBox::OnChar(uint16_t nChar, uint32_t nFlag) {
238   CPWL_Wnd::OnChar(nChar, nFlag);
239 
240   if (!m_pList->OnChar(nChar, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)))
241     return false;
242 
243   bool bExit = false;
244   OnNotifySelChanged(true, bExit, nFlag);
245 
246   return true;
247 }
248 
OnLButtonDown(const CFX_PointF & point,uint32_t nFlag)249 bool CPWL_ListBox::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
250   CPWL_Wnd::OnLButtonDown(point, nFlag);
251 
252   if (ClientHitTest(point)) {
253     m_bMouseDown = true;
254     SetFocus();
255     SetCapture();
256 
257     m_pList->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
258   }
259 
260   return true;
261 }
262 
OnLButtonUp(const CFX_PointF & point,uint32_t nFlag)263 bool CPWL_ListBox::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
264   CPWL_Wnd::OnLButtonUp(point, nFlag);
265 
266   if (m_bMouseDown) {
267     ReleaseCapture();
268     m_bMouseDown = false;
269   }
270 
271   bool bExit = false;
272   OnNotifySelChanged(false, bExit, nFlag);
273 
274   return true;
275 }
276 
SetHoverSel(bool bHoverSel)277 void CPWL_ListBox::SetHoverSel(bool bHoverSel) {
278   m_bHoverSel = bHoverSel;
279 }
280 
OnMouseMove(const CFX_PointF & point,uint32_t nFlag)281 bool CPWL_ListBox::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
282   CPWL_Wnd::OnMouseMove(point, nFlag);
283 
284   if (m_bHoverSel && !IsCaptureMouse() && ClientHitTest(point))
285     m_pList->Select(m_pList->GetItemIndex(point));
286   if (m_bMouseDown)
287     m_pList->OnMouseMove(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
288 
289   return true;
290 }
291 
OnNotify(CPWL_Wnd * pWnd,uint32_t msg,intptr_t wParam,intptr_t lParam)292 void CPWL_ListBox::OnNotify(CPWL_Wnd* pWnd,
293                             uint32_t msg,
294                             intptr_t wParam,
295                             intptr_t lParam) {
296   CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam);
297 
298   FX_FLOAT fPos;
299 
300   switch (msg) {
301     case PNM_SETSCROLLINFO:
302       switch (wParam) {
303         case SBT_VSCROLL:
304           if (CPWL_Wnd* pChild = GetVScrollBar()) {
305             pChild->OnNotify(pWnd, PNM_SETSCROLLINFO, wParam, lParam);
306           }
307           break;
308       }
309       break;
310     case PNM_SETSCROLLPOS:
311       switch (wParam) {
312         case SBT_VSCROLL:
313           if (CPWL_Wnd* pChild = GetVScrollBar()) {
314             pChild->OnNotify(pWnd, PNM_SETSCROLLPOS, wParam, lParam);
315           }
316           break;
317       }
318       break;
319     case PNM_SCROLLWINDOW:
320       fPos = *(FX_FLOAT*)lParam;
321       switch (wParam) {
322         case SBT_VSCROLL:
323           m_pList->SetScrollPos(CFX_PointF(0, fPos));
324           break;
325       }
326       break;
327   }
328 }
329 
KillFocus()330 void CPWL_ListBox::KillFocus() {
331   CPWL_Wnd::KillFocus();
332 }
333 
RePosChildWnd()334 void CPWL_ListBox::RePosChildWnd() {
335   CPWL_Wnd::RePosChildWnd();
336 
337   m_pList->SetPlateRect(GetListRect());
338 }
339 
OnNotifySelChanged(bool bKeyDown,bool & bExit,uint32_t nFlag)340 void CPWL_ListBox::OnNotifySelChanged(bool bKeyDown,
341                                       bool& bExit,
342                                       uint32_t nFlag) {
343   if (!m_pFillerNotify)
344     return;
345 
346   bool bRC = true;
347   CFX_WideString swChange = GetText();
348   CFX_WideString strChangeEx;
349   int nSelStart = 0;
350   int nSelEnd = swChange.GetLength();
351   m_pFillerNotify->OnBeforeKeyStroke(GetAttachedData(), swChange, strChangeEx,
352                                      nSelStart, nSelEnd, bKeyDown, bRC, bExit,
353                                      nFlag);
354 }
355 
GetFocusRect() const356 CFX_FloatRect CPWL_ListBox::GetFocusRect() const {
357   if (m_pList->IsMultipleSel()) {
358     CFX_FloatRect rcCaret = m_pList->GetItemRect(m_pList->GetCaret());
359     rcCaret.Intersect(GetClientRect());
360     return rcCaret;
361   }
362 
363   return CPWL_Wnd::GetFocusRect();
364 }
365 
AddString(const CFX_WideString & str)366 void CPWL_ListBox::AddString(const CFX_WideString& str) {
367   m_pList->AddString(str);
368 }
369 
GetText() const370 CFX_WideString CPWL_ListBox::GetText() const {
371   return m_pList->GetText();
372 }
373 
SetFontSize(FX_FLOAT fFontSize)374 void CPWL_ListBox::SetFontSize(FX_FLOAT fFontSize) {
375   m_pList->SetFontSize(fFontSize);
376 }
377 
GetFontSize() const378 FX_FLOAT CPWL_ListBox::GetFontSize() const {
379   return m_pList->GetFontSize();
380 }
381 
Select(int32_t nItemIndex)382 void CPWL_ListBox::Select(int32_t nItemIndex) {
383   m_pList->Select(nItemIndex);
384 }
385 
SetCaret(int32_t nItemIndex)386 void CPWL_ListBox::SetCaret(int32_t nItemIndex) {
387   m_pList->SetCaret(nItemIndex);
388 }
389 
SetTopVisibleIndex(int32_t nItemIndex)390 void CPWL_ListBox::SetTopVisibleIndex(int32_t nItemIndex) {
391   m_pList->SetTopItem(nItemIndex);
392 }
393 
ScrollToListItem(int32_t nItemIndex)394 void CPWL_ListBox::ScrollToListItem(int32_t nItemIndex) {
395   m_pList->ScrollToListItem(nItemIndex);
396 }
397 
ResetContent()398 void CPWL_ListBox::ResetContent() {
399   m_pList->Empty();
400 }
401 
Reset()402 void CPWL_ListBox::Reset() {
403   m_pList->Cancel();
404 }
405 
IsMultipleSel() const406 bool CPWL_ListBox::IsMultipleSel() const {
407   return m_pList->IsMultipleSel();
408 }
409 
GetCaretIndex() const410 int32_t CPWL_ListBox::GetCaretIndex() const {
411   return m_pList->GetCaret();
412 }
413 
GetCurSel() const414 int32_t CPWL_ListBox::GetCurSel() const {
415   return m_pList->GetSelect();
416 }
417 
IsItemSelected(int32_t nItemIndex) const418 bool CPWL_ListBox::IsItemSelected(int32_t nItemIndex) const {
419   return m_pList->IsItemSelected(nItemIndex);
420 }
421 
GetTopVisibleIndex() const422 int32_t CPWL_ListBox::GetTopVisibleIndex() const {
423   m_pList->ScrollToListItem(m_pList->GetFirstSelected());
424   return m_pList->GetTopItem();
425 }
426 
GetCount() const427 int32_t CPWL_ListBox::GetCount() const {
428   return m_pList->GetCount();
429 }
430 
FindNext(int32_t nIndex,FX_WCHAR nChar) const431 int32_t CPWL_ListBox::FindNext(int32_t nIndex, FX_WCHAR nChar) const {
432   return m_pList->FindNext(nIndex, nChar);
433 }
434 
GetContentRect() const435 CFX_FloatRect CPWL_ListBox::GetContentRect() const {
436   return m_pList->GetContentRect();
437 }
438 
GetFirstHeight() const439 FX_FLOAT CPWL_ListBox::GetFirstHeight() const {
440   return m_pList->GetFirstHeight();
441 }
442 
GetListRect() const443 CFX_FloatRect CPWL_ListBox::GetListRect() const {
444   return CPWL_Utils::DeflateRect(
445       GetWindowRect(), (FX_FLOAT)(GetBorderWidth() + GetInnerBorderWidth()));
446 }
447 
OnMouseWheel(short zDelta,const CFX_PointF & point,uint32_t nFlag)448 bool CPWL_ListBox::OnMouseWheel(short zDelta,
449                                 const CFX_PointF& point,
450                                 uint32_t nFlag) {
451   if (zDelta < 0)
452     m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
453   else
454     m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
455 
456   bool bExit = false;
457   OnNotifySelChanged(false, bExit, nFlag);
458   return true;
459 }
460