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