OLD | NEW |
| (Empty) |
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/include/pdfwindow/PWL_ListBox.h" | |
8 | |
9 #include "fpdfsdk/include/pdfwindow/PWL_Edit.h" | |
10 #include "fpdfsdk/include/pdfwindow/PWL_EditCtrl.h" | |
11 #include "fpdfsdk/include/pdfwindow/PWL_ScrollBar.h" | |
12 #include "fpdfsdk/include/pdfwindow/PWL_Utils.h" | |
13 #include "fpdfsdk/include/pdfwindow/PWL_Wnd.h" | |
14 #include "public/fpdf_fwlevent.h" | |
15 | |
16 #define IsFloatZero(f) ((f) < 0.0001 && (f) > -0.0001) | |
17 #define IsFloatBigger(fa, fb) ((fa) > (fb) && !IsFloatZero((fa) - (fb))) | |
18 #define IsFloatSmaller(fa, fb) ((fa) < (fb) && !IsFloatZero((fa) - (fb))) | |
19 #define IsFloatEqual(fa, fb) IsFloatZero((fa) - (fb)) | |
20 | |
21 CPWL_List_Notify::CPWL_List_Notify(CPWL_ListBox* pList) : m_pList(pList) { | |
22 ASSERT(m_pList); | |
23 } | |
24 | |
25 CPWL_List_Notify::~CPWL_List_Notify() {} | |
26 | |
27 void CPWL_List_Notify::IOnSetScrollInfoY(FX_FLOAT fPlateMin, | |
28 FX_FLOAT fPlateMax, | |
29 FX_FLOAT fContentMin, | |
30 FX_FLOAT fContentMax, | |
31 FX_FLOAT fSmallStep, | |
32 FX_FLOAT fBigStep) { | |
33 PWL_SCROLL_INFO Info; | |
34 | |
35 Info.fPlateWidth = fPlateMax - fPlateMin; | |
36 Info.fContentMin = fContentMin; | |
37 Info.fContentMax = fContentMax; | |
38 Info.fSmallStep = fSmallStep; | |
39 Info.fBigStep = fBigStep; | |
40 | |
41 m_pList->OnNotify(m_pList, PNM_SETSCROLLINFO, SBT_VSCROLL, (intptr_t)&Info); | |
42 | |
43 if (CPWL_ScrollBar* pScroll = m_pList->GetVScrollBar()) { | |
44 if (IsFloatBigger(Info.fPlateWidth, Info.fContentMax - Info.fContentMin) || | |
45 IsFloatEqual(Info.fPlateWidth, Info.fContentMax - Info.fContentMin)) { | |
46 if (pScroll->IsVisible()) { | |
47 pScroll->SetVisible(FALSE); | |
48 m_pList->RePosChildWnd(); | |
49 } | |
50 } else { | |
51 if (!pScroll->IsVisible()) { | |
52 pScroll->SetVisible(TRUE); | |
53 m_pList->RePosChildWnd(); | |
54 } | |
55 } | |
56 } | |
57 } | |
58 | |
59 void CPWL_List_Notify::IOnSetScrollPosY(FX_FLOAT fy) { | |
60 m_pList->OnNotify(m_pList, PNM_SETSCROLLPOS, SBT_VSCROLL, (intptr_t)&fy); | |
61 } | |
62 | |
63 void CPWL_List_Notify::IOnInvalidateRect(CFX_FloatRect* pRect) { | |
64 m_pList->InvalidateRect(pRect); | |
65 } | |
66 | |
67 CPWL_ListBox::CPWL_ListBox() | |
68 : m_pList(NULL), | |
69 m_pListNotify(NULL), | |
70 m_bMouseDown(FALSE), | |
71 m_bHoverSel(FALSE), | |
72 m_pFillerNotify(NULL) { | |
73 m_pList = IFX_List::NewList(); | |
74 } | |
75 | |
76 CPWL_ListBox::~CPWL_ListBox() { | |
77 IFX_List::DelList(m_pList); | |
78 delete m_pListNotify; | |
79 m_pListNotify = NULL; | |
80 } | |
81 | |
82 CFX_ByteString CPWL_ListBox::GetClassName() const { | |
83 return "CPWL_ListBox"; | |
84 } | |
85 | |
86 void CPWL_ListBox::OnCreated() { | |
87 if (m_pList) { | |
88 delete m_pListNotify; | |
89 | |
90 m_pList->SetFontMap(GetFontMap()); | |
91 m_pList->SetNotify(m_pListNotify = new CPWL_List_Notify(this)); | |
92 | |
93 SetHoverSel(HasFlag(PLBS_HOVERSEL)); | |
94 m_pList->SetMultipleSel(HasFlag(PLBS_MULTIPLESEL)); | |
95 m_pList->SetFontSize(GetCreationParam().fFontSize); | |
96 | |
97 m_bHoverSel = HasFlag(PLBS_HOVERSEL); | |
98 } | |
99 } | |
100 | |
101 void CPWL_ListBox::OnDestroy() { | |
102 delete m_pListNotify; | |
103 m_pListNotify = NULL; | |
104 } | |
105 | |
106 void CPWL_ListBox::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) { | |
107 CPWL_Wnd::GetThisAppearanceStream(sAppStream); | |
108 | |
109 CFX_ByteTextBuf sListItems; | |
110 | |
111 if (m_pList) { | |
112 CFX_FloatRect rcPlate = m_pList->GetPlateRect(); | |
113 for (int32_t i = 0, sz = m_pList->GetCount(); i < sz; i++) { | |
114 CFX_FloatRect rcItem = m_pList->GetItemRect(i); | |
115 | |
116 if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom) | |
117 continue; | |
118 | |
119 CFX_FloatPoint ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f); | |
120 if (m_pList->IsItemSelected(i)) { | |
121 sListItems << CPWL_Utils::GetRectFillAppStream( | |
122 rcItem, PWL_DEFAULT_SELBACKCOLOR); | |
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(PWL_DEFAULT_SELTEXTCOLOR) | |
128 << sItem << "ET\n"; | |
129 } | |
130 } else { | |
131 CFX_ByteString sItem = | |
132 CPWL_Utils::GetEditAppStream(m_pList->GetItemEdit(i), ptOffset); | |
133 if (sItem.GetLength() > 0) { | |
134 sListItems << "BT\n" << CPWL_Utils::GetColorAppStream(GetTextColor()) | |
135 << sItem << "ET\n"; | |
136 } | |
137 } | |
138 } | |
139 } | |
140 | |
141 if (sListItems.GetLength() > 0) { | |
142 CFX_ByteTextBuf sClip; | |
143 CFX_FloatRect rcClient = GetClientRect(); | |
144 | |
145 sClip << "q\n"; | |
146 sClip << rcClient.left << " " << rcClient.bottom << " " | |
147 << rcClient.right - rcClient.left << " " | |
148 << rcClient.top - rcClient.bottom << " re W n\n"; | |
149 | |
150 sClip << sListItems << "Q\n"; | |
151 | |
152 sAppStream << "/Tx BMC\n" << sClip << "EMC\n"; | |
153 } | |
154 } | |
155 | |
156 void CPWL_ListBox::DrawThisAppearance(CFX_RenderDevice* pDevice, | |
157 CFX_Matrix* pUser2Device) { | |
158 CPWL_Wnd::DrawThisAppearance(pDevice, pUser2Device); | |
159 | |
160 if (m_pList) { | |
161 CFX_FloatRect rcPlate = m_pList->GetPlateRect(); | |
162 CFX_FloatRect rcList = GetListRect(); | |
163 CFX_FloatRect rcClient = GetClientRect(); | |
164 | |
165 for (int32_t i = 0, sz = m_pList->GetCount(); i < sz; i++) { | |
166 CFX_FloatRect rcItem = m_pList->GetItemRect(i); | |
167 if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom) | |
168 continue; | |
169 | |
170 CFX_FloatPoint ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f); | |
171 if (IFX_Edit* pEdit = m_pList->GetItemEdit(i)) { | |
172 CFX_FloatRect rcContent = pEdit->GetContentRect(); | |
173 if (rcContent.Width() > rcClient.Width()) | |
174 rcItem.Intersect(rcList); | |
175 else | |
176 rcItem.Intersect(rcClient); | |
177 } | |
178 | |
179 if (m_pList->IsItemSelected(i)) { | |
180 IFX_SystemHandler* pSysHandler = GetSystemHandler(); | |
181 if (pSysHandler && pSysHandler->IsSelectionImplemented()) { | |
182 IFX_Edit::DrawEdit( | |
183 pDevice, pUser2Device, m_pList->GetItemEdit(i), | |
184 CPWL_Utils::PWLColorToFXColor(GetTextColor()), | |
185 CPWL_Utils::PWLColorToFXColor(GetTextStrokeColor()), rcList, | |
186 ptOffset, NULL, pSysHandler, m_pFormFiller); | |
187 pSysHandler->OutputSelectedRect(m_pFormFiller, rcItem); | |
188 } else { | |
189 CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcItem, | |
190 ArgbEncode(255, 0, 51, 113)); | |
191 IFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i), | |
192 ArgbEncode(255, 255, 255, 255), 0, rcList, | |
193 ptOffset, NULL, pSysHandler, m_pFormFiller); | |
194 } | |
195 } else { | |
196 IFX_SystemHandler* pSysHandler = GetSystemHandler(); | |
197 IFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i), | |
198 CPWL_Utils::PWLColorToFXColor(GetTextColor()), | |
199 CPWL_Utils::PWLColorToFXColor(GetTextStrokeColor()), | |
200 rcList, ptOffset, NULL, pSysHandler, NULL); | |
201 } | |
202 } | |
203 } | |
204 } | |
205 | |
206 FX_BOOL CPWL_ListBox::OnKeyDown(FX_WORD nChar, FX_DWORD nFlag) { | |
207 CPWL_Wnd::OnKeyDown(nChar, nFlag); | |
208 | |
209 if (!m_pList) | |
210 return FALSE; | |
211 | |
212 switch (nChar) { | |
213 default: | |
214 return FALSE; | |
215 case FWL_VKEY_Up: | |
216 case FWL_VKEY_Down: | |
217 case FWL_VKEY_Home: | |
218 case FWL_VKEY_Left: | |
219 case FWL_VKEY_End: | |
220 case FWL_VKEY_Right: | |
221 break; | |
222 } | |
223 | |
224 switch (nChar) { | |
225 case FWL_VKEY_Up: | |
226 m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); | |
227 break; | |
228 case FWL_VKEY_Down: | |
229 m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); | |
230 break; | |
231 case FWL_VKEY_Home: | |
232 m_pList->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); | |
233 break; | |
234 case FWL_VKEY_Left: | |
235 m_pList->OnVK_LEFT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); | |
236 break; | |
237 case FWL_VKEY_End: | |
238 m_pList->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); | |
239 break; | |
240 case FWL_VKEY_Right: | |
241 m_pList->OnVK_RIGHT(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); | |
242 break; | |
243 case FWL_VKEY_Delete: | |
244 break; | |
245 } | |
246 | |
247 FX_BOOL bExit = FALSE; | |
248 OnNotifySelChanged(TRUE, bExit, nFlag); | |
249 | |
250 return TRUE; | |
251 } | |
252 | |
253 FX_BOOL CPWL_ListBox::OnChar(FX_WORD nChar, FX_DWORD nFlag) { | |
254 CPWL_Wnd::OnChar(nChar, nFlag); | |
255 | |
256 if (!m_pList) | |
257 return FALSE; | |
258 | |
259 if (!m_pList->OnChar(nChar, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag))) | |
260 return FALSE; | |
261 | |
262 FX_BOOL bExit = FALSE; | |
263 OnNotifySelChanged(TRUE, bExit, nFlag); | |
264 | |
265 return TRUE; | |
266 } | |
267 | |
268 FX_BOOL CPWL_ListBox::OnLButtonDown(const CFX_FloatPoint& point, | |
269 FX_DWORD nFlag) { | |
270 CPWL_Wnd::OnLButtonDown(point, nFlag); | |
271 | |
272 if (ClientHitTest(point)) { | |
273 m_bMouseDown = TRUE; | |
274 SetFocus(); | |
275 SetCapture(); | |
276 | |
277 if (m_pList) | |
278 m_pList->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); | |
279 } | |
280 | |
281 return TRUE; | |
282 } | |
283 | |
284 FX_BOOL CPWL_ListBox::OnLButtonUp(const CFX_FloatPoint& point, FX_DWORD nFlag) { | |
285 CPWL_Wnd::OnLButtonUp(point, nFlag); | |
286 | |
287 if (m_bMouseDown) { | |
288 ReleaseCapture(); | |
289 m_bMouseDown = FALSE; | |
290 } | |
291 | |
292 FX_BOOL bExit = FALSE; | |
293 OnNotifySelChanged(FALSE, bExit, nFlag); | |
294 | |
295 return TRUE; | |
296 } | |
297 | |
298 void CPWL_ListBox::SetHoverSel(FX_BOOL bHoverSel) { | |
299 m_bHoverSel = bHoverSel; | |
300 } | |
301 | |
302 FX_BOOL CPWL_ListBox::OnMouseMove(const CFX_FloatPoint& point, FX_DWORD nFlag) { | |
303 CPWL_Wnd::OnMouseMove(point, nFlag); | |
304 | |
305 if (m_bHoverSel && !IsCaptureMouse() && ClientHitTest(point)) { | |
306 if (m_pList) | |
307 m_pList->Select(m_pList->GetItemIndex(point)); | |
308 } | |
309 | |
310 if (m_bMouseDown) { | |
311 if (m_pList) | |
312 m_pList->OnMouseMove(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); | |
313 } | |
314 | |
315 return TRUE; | |
316 } | |
317 | |
318 void CPWL_ListBox::OnNotify(CPWL_Wnd* pWnd, | |
319 FX_DWORD msg, | |
320 intptr_t wParam, | |
321 intptr_t lParam) { | |
322 CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam); | |
323 | |
324 FX_FLOAT fPos; | |
325 | |
326 switch (msg) { | |
327 case PNM_SETSCROLLINFO: | |
328 switch (wParam) { | |
329 case SBT_VSCROLL: | |
330 if (CPWL_Wnd* pChild = GetVScrollBar()) { | |
331 pChild->OnNotify(pWnd, PNM_SETSCROLLINFO, wParam, lParam); | |
332 } | |
333 break; | |
334 } | |
335 break; | |
336 case PNM_SETSCROLLPOS: | |
337 switch (wParam) { | |
338 case SBT_VSCROLL: | |
339 if (CPWL_Wnd* pChild = GetVScrollBar()) { | |
340 pChild->OnNotify(pWnd, PNM_SETSCROLLPOS, wParam, lParam); | |
341 } | |
342 break; | |
343 } | |
344 break; | |
345 case PNM_SCROLLWINDOW: | |
346 fPos = *(FX_FLOAT*)lParam; | |
347 switch (wParam) { | |
348 case SBT_VSCROLL: | |
349 if (m_pList) | |
350 m_pList->SetScrollPos(CFX_FloatPoint(0, fPos)); | |
351 break; | |
352 } | |
353 break; | |
354 } | |
355 } | |
356 | |
357 void CPWL_ListBox::KillFocus() { | |
358 CPWL_Wnd::KillFocus(); | |
359 } | |
360 | |
361 void CPWL_ListBox::RePosChildWnd() { | |
362 CPWL_Wnd::RePosChildWnd(); | |
363 | |
364 if (m_pList) | |
365 m_pList->SetPlateRect(GetListRect()); | |
366 } | |
367 | |
368 void CPWL_ListBox::OnNotifySelChanged(FX_BOOL bKeyDown, | |
369 FX_BOOL& bExit, | |
370 FX_DWORD nFlag) { | |
371 if (!m_pFillerNotify) | |
372 return; | |
373 | |
374 FX_BOOL bRC = TRUE; | |
375 CFX_WideString swChange = GetText(); | |
376 CFX_WideString strChangeEx; | |
377 int nSelStart = 0; | |
378 int nSelEnd = swChange.GetLength(); | |
379 m_pFillerNotify->OnBeforeKeyStroke(GetAttachedData(), swChange, strChangeEx, | |
380 nSelStart, nSelEnd, bKeyDown, bRC, bExit, | |
381 nFlag); | |
382 } | |
383 | |
384 CFX_FloatRect CPWL_ListBox::GetFocusRect() const { | |
385 if (m_pList && m_pList->IsMultipleSel()) { | |
386 CFX_FloatRect rcCaret = m_pList->GetItemRect(m_pList->GetCaret()); | |
387 rcCaret.Intersect(GetClientRect()); | |
388 return rcCaret; | |
389 } | |
390 | |
391 return CPWL_Wnd::GetFocusRect(); | |
392 } | |
393 | |
394 void CPWL_ListBox::AddString(const FX_WCHAR* str) { | |
395 if (m_pList) { | |
396 m_pList->AddString(str); | |
397 } | |
398 } | |
399 | |
400 CFX_WideString CPWL_ListBox::GetText() const { | |
401 if (m_pList) | |
402 return m_pList->GetText(); | |
403 | |
404 return L""; | |
405 } | |
406 | |
407 void CPWL_ListBox::SetFontSize(FX_FLOAT fFontSize) { | |
408 if (m_pList) | |
409 m_pList->SetFontSize(fFontSize); | |
410 } | |
411 | |
412 FX_FLOAT CPWL_ListBox::GetFontSize() const { | |
413 if (m_pList) | |
414 return m_pList->GetFontSize(); | |
415 return 0.0f; | |
416 } | |
417 | |
418 void CPWL_ListBox::Select(int32_t nItemIndex) { | |
419 if (m_pList) | |
420 m_pList->Select(nItemIndex); | |
421 } | |
422 | |
423 void CPWL_ListBox::SetCaret(int32_t nItemIndex) { | |
424 if (m_pList) | |
425 m_pList->SetCaret(nItemIndex); | |
426 } | |
427 | |
428 void CPWL_ListBox::SetTopVisibleIndex(int32_t nItemIndex) { | |
429 if (m_pList) | |
430 m_pList->SetTopItem(nItemIndex); | |
431 } | |
432 | |
433 void CPWL_ListBox::ScrollToListItem(int32_t nItemIndex) { | |
434 if (m_pList) | |
435 m_pList->ScrollToListItem(nItemIndex); | |
436 } | |
437 | |
438 void CPWL_ListBox::ResetContent() { | |
439 if (m_pList) | |
440 m_pList->Empty(); | |
441 } | |
442 | |
443 void CPWL_ListBox::Reset() { | |
444 if (m_pList) | |
445 m_pList->Cancel(); | |
446 } | |
447 | |
448 FX_BOOL CPWL_ListBox::IsMultipleSel() const { | |
449 if (m_pList) | |
450 return m_pList->IsMultipleSel(); | |
451 | |
452 return FALSE; | |
453 } | |
454 | |
455 int32_t CPWL_ListBox::GetCaretIndex() const { | |
456 if (m_pList) | |
457 return m_pList->GetCaret(); | |
458 | |
459 return -1; | |
460 } | |
461 | |
462 int32_t CPWL_ListBox::GetCurSel() const { | |
463 if (m_pList) | |
464 return m_pList->GetSelect(); | |
465 | |
466 return -1; | |
467 } | |
468 | |
469 FX_BOOL CPWL_ListBox::IsItemSelected(int32_t nItemIndex) const { | |
470 if (m_pList) | |
471 return m_pList->IsItemSelected(nItemIndex); | |
472 | |
473 return FALSE; | |
474 } | |
475 | |
476 int32_t CPWL_ListBox::GetTopVisibleIndex() const { | |
477 if (m_pList) { | |
478 m_pList->ScrollToListItem(m_pList->GetFirstSelected()); | |
479 return m_pList->GetTopItem(); | |
480 } | |
481 | |
482 return -1; | |
483 } | |
484 | |
485 int32_t CPWL_ListBox::GetCount() const { | |
486 if (m_pList) | |
487 return m_pList->GetCount(); | |
488 | |
489 return 0; | |
490 } | |
491 | |
492 int32_t CPWL_ListBox::FindNext(int32_t nIndex, FX_WCHAR nChar) const { | |
493 if (m_pList) | |
494 return m_pList->FindNext(nIndex, nChar); | |
495 | |
496 return nIndex; | |
497 } | |
498 | |
499 CFX_FloatRect CPWL_ListBox::GetContentRect() const { | |
500 if (m_pList) | |
501 return m_pList->GetContentRect(); | |
502 | |
503 return CFX_FloatRect(); | |
504 } | |
505 | |
506 FX_FLOAT CPWL_ListBox::GetFirstHeight() const { | |
507 if (m_pList) | |
508 return m_pList->GetFirstHeight(); | |
509 | |
510 return 0.0f; | |
511 } | |
512 | |
513 CFX_FloatRect CPWL_ListBox::GetListRect() const { | |
514 return CPWL_Utils::DeflateRect( | |
515 GetWindowRect(), (FX_FLOAT)(GetBorderWidth() + GetInnerBorderWidth())); | |
516 } | |
517 | |
518 FX_BOOL CPWL_ListBox::OnMouseWheel(short zDelta, | |
519 const CFX_FloatPoint& point, | |
520 FX_DWORD nFlag) { | |
521 if (!m_pList) | |
522 return FALSE; | |
523 | |
524 if (zDelta < 0) { | |
525 m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); | |
526 } else { | |
527 m_pList->OnVK_UP(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); | |
528 } | |
529 | |
530 FX_BOOL bExit = FALSE; | |
531 OnNotifySelChanged(FALSE, bExit, nFlag); | |
532 return TRUE; | |
533 } | |
OLD | NEW |