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 #include <utility>
11
12 #include "core/fxge/cfx_renderdevice.h"
13 #include "fpdfsdk/pwl/cpwl_edit.h"
14 #include "fpdfsdk/pwl/cpwl_edit_ctrl.h"
15 #include "fpdfsdk/pwl/cpwl_edit_impl.h"
16 #include "fpdfsdk/pwl/cpwl_scroll_bar.h"
17 #include "fpdfsdk/pwl/ipwl_fillernotify.h"
18 #include "public/fpdf_fwlevent.h"
19
CPWL_ListBox(const CreateParams & cp,std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)20 CPWL_ListBox::CPWL_ListBox(
21 const CreateParams& cp,
22 std::unique_ptr<IPWL_SystemHandler::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_SystemHandler* pSysHandler = GetSystemHandler();
66 if (m_pListCtrl->IsItemSelected(i)) {
67 if (pSysHandler->IsSelectionImplemented()) {
68 CPWL_EditImpl::DrawEdit(pDevice, mtUser2Device,
69 m_pListCtrl->GetItemEdit(i),
70 GetTextColor().ToFXColor(255), rcList, ptOffset,
71 nullptr, pSysHandler, m_pFormFiller.Get());
72 pSysHandler->OutputSelectedRect(m_pFormFiller.Get(), rcItem);
73 } else {
74 pDevice->DrawFillRect(&mtUser2Device, rcItem,
75 ArgbEncode(255, 0, 51, 113));
76 CPWL_EditImpl::DrawEdit(
77 pDevice, mtUser2Device, m_pListCtrl->GetItemEdit(i),
78 ArgbEncode(255, 255, 255, 255), rcList, ptOffset, nullptr,
79 pSysHandler, m_pFormFiller.Get());
80 }
81 } else {
82 CPWL_EditImpl::DrawEdit(pDevice, mtUser2Device,
83 m_pListCtrl->GetItemEdit(i),
84 GetTextColor().ToFXColor(255), rcList, ptOffset,
85 nullptr, pSysHandler, nullptr);
86 }
87 }
88 }
89
OnKeyDown(uint16_t nChar,uint32_t nFlag)90 bool CPWL_ListBox::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
91 CPWL_Wnd::OnKeyDown(nChar, nFlag);
92
93 switch (nChar) {
94 default:
95 return false;
96 case FWL_VKEY_Up:
97 case FWL_VKEY_Down:
98 case FWL_VKEY_Home:
99 case FWL_VKEY_Left:
100 case FWL_VKEY_End:
101 case FWL_VKEY_Right:
102 break;
103 }
104
105 switch (nChar) {
106 case FWL_VKEY_Up:
107 m_pListCtrl->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
108 break;
109 case FWL_VKEY_Down:
110 m_pListCtrl->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
111 break;
112 case FWL_VKEY_Home:
113 m_pListCtrl->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
114 break;
115 case FWL_VKEY_Left:
116 m_pListCtrl->OnVK_LEFT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
117 break;
118 case FWL_VKEY_End:
119 m_pListCtrl->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
120 break;
121 case FWL_VKEY_Right:
122 m_pListCtrl->OnVK_RIGHT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
123 break;
124 case FWL_VKEY_Delete:
125 break;
126 }
127 OnNotifySelectionChanged(true, nFlag);
128 return true;
129 }
130
OnChar(uint16_t nChar,uint32_t nFlag)131 bool CPWL_ListBox::OnChar(uint16_t nChar, uint32_t nFlag) {
132 CPWL_Wnd::OnChar(nChar, nFlag);
133
134 if (!m_pListCtrl->OnChar(nChar, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)))
135 return false;
136
137 OnNotifySelectionChanged(true, nFlag);
138 return true;
139 }
140
OnLButtonDown(uint32_t nFlag,const CFX_PointF & point)141 bool CPWL_ListBox::OnLButtonDown(uint32_t nFlag, const CFX_PointF& point) {
142 CPWL_Wnd::OnLButtonDown(nFlag, point);
143
144 if (ClientHitTest(point)) {
145 m_bMouseDown = true;
146 SetFocus();
147 SetCapture();
148
149 m_pListCtrl->OnMouseDown(point, IsSHIFTpressed(nFlag),
150 IsCTRLpressed(nFlag));
151 }
152
153 return true;
154 }
155
OnLButtonUp(uint32_t nFlag,const CFX_PointF & point)156 bool CPWL_ListBox::OnLButtonUp(uint32_t nFlag, const CFX_PointF& point) {
157 CPWL_Wnd::OnLButtonUp(nFlag, point);
158
159 if (m_bMouseDown) {
160 ReleaseCapture();
161 m_bMouseDown = false;
162 }
163 OnNotifySelectionChanged(false, nFlag);
164 return true;
165 }
166
SetHoverSel(bool bHoverSel)167 void CPWL_ListBox::SetHoverSel(bool bHoverSel) {
168 m_bHoverSel = bHoverSel;
169 }
170
OnMouseMove(uint32_t nFlag,const CFX_PointF & point)171 bool CPWL_ListBox::OnMouseMove(uint32_t nFlag, 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, IsSHIFTpressed(nFlag),
178 IsCTRLpressed(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,uint32_t nFlag)205 bool CPWL_ListBox::OnNotifySelectionChanged(bool bKeyDown, uint32_t nFlag) {
206 if (!m_pFillerNotify)
207 return false;
208
209 ObservedPtr<CPWL_Wnd> thisObserved(this);
210
211 WideString swChange = GetText();
212 WideString strChangeEx;
213 int nSelStart = 0;
214 int nSelEnd = swChange.GetLength();
215 bool bRC;
216 bool bExit;
217 std::tie(bRC, bExit) = m_pFillerNotify->OnBeforeKeyStroke(
218 GetAttachedData(), swChange, strChangeEx, nSelStart, nSelEnd, bKeyDown,
219 nFlag);
220
221 if (!thisObserved)
222 return false;
223
224 return bExit;
225 }
226
GetFocusRect() const227 CFX_FloatRect CPWL_ListBox::GetFocusRect() const {
228 if (m_pListCtrl->IsMultipleSel()) {
229 CFX_FloatRect rcCaret = m_pListCtrl->GetItemRect(m_pListCtrl->GetCaret());
230 rcCaret.Intersect(GetClientRect());
231 return rcCaret;
232 }
233
234 return CPWL_Wnd::GetFocusRect();
235 }
236
AddString(const WideString & str)237 void CPWL_ListBox::AddString(const WideString& str) {
238 m_pListCtrl->AddString(str);
239 }
240
GetText()241 WideString CPWL_ListBox::GetText() {
242 return m_pListCtrl->GetText();
243 }
244
SetFontSize(float fFontSize)245 void CPWL_ListBox::SetFontSize(float fFontSize) {
246 m_pListCtrl->SetFontSize(fFontSize);
247 }
248
GetFontSize() const249 float CPWL_ListBox::GetFontSize() const {
250 return m_pListCtrl->GetFontSize();
251 }
252
OnSetScrollInfoY(float fPlateMin,float fPlateMax,float fContentMin,float fContentMax,float fSmallStep,float fBigStep)253 void CPWL_ListBox::OnSetScrollInfoY(float fPlateMin,
254 float fPlateMax,
255 float fContentMin,
256 float fContentMax,
257 float fSmallStep,
258 float fBigStep) {
259 PWL_SCROLL_INFO Info;
260 Info.fPlateWidth = fPlateMax - fPlateMin;
261 Info.fContentMin = fContentMin;
262 Info.fContentMax = fContentMax;
263 Info.fSmallStep = fSmallStep;
264 Info.fBigStep = fBigStep;
265 SetScrollInfo(Info);
266
267 CPWL_ScrollBar* pScroll = GetVScrollBar();
268 if (!pScroll)
269 return;
270
271 if (IsFloatBigger(Info.fPlateWidth, Info.fContentMax - Info.fContentMin) ||
272 IsFloatEqual(Info.fPlateWidth, 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
ResetContent()313 void CPWL_ListBox::ResetContent() {
314 m_pListCtrl->Clear();
315 }
316
Reset()317 void CPWL_ListBox::Reset() {
318 m_pListCtrl->Cancel();
319 }
320
IsMultipleSel() const321 bool CPWL_ListBox::IsMultipleSel() const {
322 return m_pListCtrl->IsMultipleSel();
323 }
324
GetCaretIndex() const325 int32_t CPWL_ListBox::GetCaretIndex() const {
326 return m_pListCtrl->GetCaret();
327 }
328
GetCurSel() const329 int32_t CPWL_ListBox::GetCurSel() const {
330 return m_pListCtrl->GetSelect();
331 }
332
IsItemSelected(int32_t nItemIndex) const333 bool CPWL_ListBox::IsItemSelected(int32_t nItemIndex) const {
334 return m_pListCtrl->IsItemSelected(nItemIndex);
335 }
336
GetTopVisibleIndex() const337 int32_t CPWL_ListBox::GetTopVisibleIndex() const {
338 m_pListCtrl->ScrollToListItem(m_pListCtrl->GetFirstSelected());
339 return m_pListCtrl->GetTopItem();
340 }
341
GetCount() const342 int32_t CPWL_ListBox::GetCount() const {
343 return m_pListCtrl->GetCount();
344 }
345
FindNext(int32_t nIndex,wchar_t nChar) const346 int32_t CPWL_ListBox::FindNext(int32_t nIndex, wchar_t nChar) const {
347 return m_pListCtrl->FindNext(nIndex, nChar);
348 }
349
GetContentRect() const350 CFX_FloatRect CPWL_ListBox::GetContentRect() const {
351 return m_pListCtrl->GetContentRect();
352 }
353
GetFirstHeight() const354 float CPWL_ListBox::GetFirstHeight() const {
355 return m_pListCtrl->GetFirstHeight();
356 }
357
GetListRect() const358 CFX_FloatRect CPWL_ListBox::GetListRect() const {
359 float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
360 return GetWindowRect().GetDeflated(width, width);
361 }
362
OnMouseWheel(uint32_t nFlag,const CFX_PointF & point,const CFX_Vector & delta)363 bool CPWL_ListBox::OnMouseWheel(uint32_t nFlag,
364 const CFX_PointF& point,
365 const CFX_Vector& delta) {
366 if (delta.y < 0)
367 m_pListCtrl->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
368 else
369 m_pListCtrl->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
370
371 OnNotifySelectionChanged(false, nFlag);
372 return true;
373 }
374