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_IconList.h"
8 
9 #include "fpdfsdk/include/pdfwindow/PWL_Label.h"
10 #include "fpdfsdk/include/pdfwindow/PWL_ListCtrl.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 PWL_IconList_ITEM_ICON_LEFTMARGIN 10.0f
17 #define PWL_IconList_ITEM_WIDTH 20.0f
18 #define PWL_IconList_ITEM_HEIGHT 20.0f
19 #define PWL_IconList_ITEM_SPACE 4.0f
20 
CPWL_IconList_Item()21 CPWL_IconList_Item::CPWL_IconList_Item()
22     : m_nIconIndex(-1), m_pData(NULL), m_bSelected(FALSE), m_pText(NULL) {}
23 
~CPWL_IconList_Item()24 CPWL_IconList_Item::~CPWL_IconList_Item() {}
25 
GetClassName() const26 CFX_ByteString CPWL_IconList_Item::GetClassName() const {
27   return "CPWL_IconList_Item";
28 }
29 
GetItemHeight(FX_FLOAT fLimitWidth)30 FX_FLOAT CPWL_IconList_Item::GetItemHeight(FX_FLOAT fLimitWidth) {
31   return PWL_IconList_ITEM_HEIGHT;
32 }
33 
DrawThisAppearance(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device)34 void CPWL_IconList_Item::DrawThisAppearance(CFX_RenderDevice* pDevice,
35                                             CFX_Matrix* pUser2Device) {
36   CPDF_Rect rcClient = GetClientRect();
37 
38   if (m_bSelected) {
39     if (IsEnabled()) {
40       CPWL_Utils::DrawFillRect(
41           pDevice, pUser2Device, rcClient,
42           CPWL_Utils::PWLColorToFXColor(PWL_DEFAULT_SELBACKCOLOR,
43                                         GetTransparency()));
44     } else {
45       CPWL_Utils::DrawFillRect(
46           pDevice, pUser2Device, rcClient,
47           CPWL_Utils::PWLColorToFXColor(PWL_DEFAULT_LIGHTGRAYCOLOR,
48                                         GetTransparency()));
49     }
50   }
51 
52   CPDF_Rect rcIcon = rcClient;
53   rcIcon.left += PWL_IconList_ITEM_ICON_LEFTMARGIN;
54   rcIcon.right = rcIcon.left + PWL_IconList_ITEM_WIDTH;
55 
56   CPWL_Utils::DrawIconAppStream(pDevice, pUser2Device, m_nIconIndex, rcIcon,
57                                 m_crIcon, m_pText->GetTextColor(),
58                                 GetTransparency());
59 }
60 
SetSelect(FX_BOOL bSelected)61 void CPWL_IconList_Item::SetSelect(FX_BOOL bSelected) {
62   m_bSelected = bSelected;
63 
64   if (bSelected)
65     m_pText->SetTextColor(PWL_DEFAULT_WHITECOLOR);
66   else
67     m_pText->SetTextColor(PWL_DEFAULT_BLACKCOLOR);
68 }
69 
IsSelected() const70 FX_BOOL CPWL_IconList_Item::IsSelected() const {
71   return m_bSelected;
72 }
73 
CreateChildWnd(const PWL_CREATEPARAM & cp)74 void CPWL_IconList_Item::CreateChildWnd(const PWL_CREATEPARAM& cp) {
75   m_pText = new CPWL_Label;
76 
77   PWL_CREATEPARAM lcp = cp;
78   lcp.pParentWnd = this;
79   lcp.dwFlags = PWS_CHILD | PWS_VISIBLE | PES_LEFT | PES_CENTER;
80   lcp.sTextColor = PWL_DEFAULT_BLACKCOLOR;
81   lcp.fFontSize = 12;
82   m_pText->Create(lcp);
83 }
84 
SetData(void * pData)85 void CPWL_IconList_Item::SetData(void* pData) {
86   m_pData = pData;
87 }
88 
SetIcon(int32_t nIconIndex)89 void CPWL_IconList_Item::SetIcon(int32_t nIconIndex) {
90   m_nIconIndex = nIconIndex;
91 }
92 
SetText(const CFX_WideString & str)93 void CPWL_IconList_Item::SetText(const CFX_WideString& str) {
94   m_pText->SetText(str.c_str());
95 }
96 
GetText() const97 CFX_WideString CPWL_IconList_Item::GetText() const {
98   return m_pText->GetText();
99 }
100 
RePosChildWnd()101 void CPWL_IconList_Item::RePosChildWnd() {
102   CPDF_Rect rcClient = GetClientRect();
103 
104   rcClient.left +=
105       (PWL_IconList_ITEM_ICON_LEFTMARGIN + PWL_IconList_ITEM_WIDTH +
106        PWL_IconList_ITEM_ICON_LEFTMARGIN);
107 
108   m_pText->Move(rcClient, TRUE, FALSE);
109 }
110 
SetIconFillColor(const CPWL_Color & color)111 void CPWL_IconList_Item::SetIconFillColor(const CPWL_Color& color) {
112   m_crIcon = color;
113 }
114 
OnEnabled()115 void CPWL_IconList_Item::OnEnabled() {
116   if (m_bSelected)
117     m_pText->SetTextColor(PWL_DEFAULT_WHITECOLOR);
118   else
119     m_pText->SetTextColor(PWL_DEFAULT_BLACKCOLOR);
120 
121   InvalidateRect();
122 }
123 
OnDisabled()124 void CPWL_IconList_Item::OnDisabled() {
125   m_pText->SetTextColor(PWL_DEFAULT_HEAVYGRAYCOLOR);
126 
127   InvalidateRect();
128 }
129 
CPWL_IconList_Content(int32_t nListCount)130 CPWL_IconList_Content::CPWL_IconList_Content(int32_t nListCount)
131     : m_nSelectIndex(-1),
132       m_pNotify(NULL),
133       m_bEnableNotify(TRUE),
134       m_bMouseDown(FALSE),
135       m_nListCount(nListCount) {}
136 
~CPWL_IconList_Content()137 CPWL_IconList_Content::~CPWL_IconList_Content() {}
138 
CreateChildWnd(const PWL_CREATEPARAM & cp)139 void CPWL_IconList_Content::CreateChildWnd(const PWL_CREATEPARAM& cp) {
140   for (int32_t i = 0; i < m_nListCount; i++) {
141     CPWL_IconList_Item* pNewItem = new CPWL_IconList_Item();
142 
143     PWL_CREATEPARAM icp = cp;
144     icp.pParentWnd = this;
145     icp.dwFlags = PWS_CHILD | PWS_VISIBLE | PWS_NOREFRESHCLIP;
146     pNewItem->Create(icp);
147   }
148 
149   SetItemSpace(PWL_IconList_ITEM_SPACE);
150   ResetContent(0);
151 
152   if (CPWL_Wnd* pParent = GetParentWindow()) {
153     CPDF_Rect rcScroll = GetScrollArea();
154     GetScrollPos();
155 
156     PWL_SCROLL_INFO sInfo;
157     sInfo.fContentMin = rcScroll.bottom;
158     sInfo.fContentMax = rcScroll.top;
159     sInfo.fPlateWidth = GetClientRect().Height();
160     sInfo.fSmallStep = 13.0f;
161     sInfo.fBigStep = sInfo.fPlateWidth;
162 
163     pParent->OnNotify(this, PNM_SETSCROLLINFO, SBT_VSCROLL, (intptr_t)&sInfo);
164   }
165 }
166 
OnLButtonDown(const CPDF_Point & point,FX_DWORD nFlag)167 FX_BOOL CPWL_IconList_Content::OnLButtonDown(const CPDF_Point& point,
168                                              FX_DWORD nFlag) {
169   SetFocus();
170 
171   SetCapture();
172   m_bMouseDown = TRUE;
173 
174   int32_t nItemIndex = FindItemIndex(point);
175   SetSelect(nItemIndex);
176   ScrollToItem(nItemIndex);
177 
178   return TRUE;
179 }
180 
OnLButtonUp(const CPDF_Point & point,FX_DWORD nFlag)181 FX_BOOL CPWL_IconList_Content::OnLButtonUp(const CPDF_Point& point,
182                                            FX_DWORD nFlag) {
183   m_bMouseDown = FALSE;
184   ReleaseCapture();
185 
186   return TRUE;
187 }
188 
OnMouseMove(const CPDF_Point & point,FX_DWORD nFlag)189 FX_BOOL CPWL_IconList_Content::OnMouseMove(const CPDF_Point& point,
190                                            FX_DWORD nFlag) {
191   if (m_bMouseDown) {
192     int32_t nItemIndex = FindItemIndex(point);
193     SetSelect(nItemIndex);
194     ScrollToItem(nItemIndex);
195   }
196 
197   return TRUE;
198 }
199 
OnKeyDown(FX_WORD nChar,FX_DWORD nFlag)200 FX_BOOL CPWL_IconList_Content::OnKeyDown(FX_WORD nChar, FX_DWORD nFlag) {
201   switch (nChar) {
202     case FWL_VKEY_Up:
203       if (m_nSelectIndex > 0) {
204         int32_t nItemIndex = m_nSelectIndex - 1;
205         SetSelect(nItemIndex);
206         ScrollToItem(nItemIndex);
207       }
208       return TRUE;
209     case FWL_VKEY_Down:
210       if (m_nSelectIndex < m_nListCount - 1) {
211         int32_t nItemIndex = m_nSelectIndex + 1;
212         SetSelect(nItemIndex);
213         ScrollToItem(nItemIndex);
214       }
215       return TRUE;
216   }
217 
218   return FALSE;
219 }
220 
FindItemIndex(const CPDF_Point & point)221 int32_t CPWL_IconList_Content::FindItemIndex(const CPDF_Point& point) {
222   int32_t nIndex = 0;
223   for (int32_t i = 0, sz = m_aChildren.GetSize(); i < sz; i++) {
224     if (CPWL_Wnd* pChild = m_aChildren.GetAt(i)) {
225       CPDF_Rect rcWnd = pChild->ChildToParent(pChild->GetWindowRect());
226 
227       if (point.y < rcWnd.top) {
228         nIndex = i;
229       }
230     }
231   }
232 
233   return nIndex;
234 }
235 
ScrollToItem(int32_t nItemIndex)236 void CPWL_IconList_Content::ScrollToItem(int32_t nItemIndex) {
237   CPDF_Rect rcClient = GetClientRect();
238 
239   if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex)) {
240     CPDF_Rect rcOrigin = pItem->GetWindowRect();
241     CPDF_Rect rcWnd = pItem->ChildToParent(rcOrigin);
242 
243     if (!(rcWnd.bottom > rcClient.bottom && rcWnd.top < rcClient.top)) {
244       CPDF_Point ptScroll = GetScrollPos();
245 
246       if (rcWnd.top > rcClient.top) {
247         ptScroll.y = rcOrigin.top;
248       } else if (rcWnd.bottom < rcClient.bottom) {
249         ptScroll.y = rcOrigin.bottom + rcClient.Height();
250       }
251 
252       SetScrollPos(ptScroll);
253       ResetFace();
254       InvalidateRect();
255       if (CPWL_Wnd* pParent = GetParentWindow()) {
256         pParent->OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL,
257                           (intptr_t)&ptScroll.y);
258       }
259     }
260   }
261 }
262 
SetSelect(int32_t nIndex)263 void CPWL_IconList_Content::SetSelect(int32_t nIndex) {
264   if (m_nSelectIndex != nIndex) {
265     SelectItem(m_nSelectIndex, FALSE);
266     SelectItem(nIndex, TRUE);
267     m_nSelectIndex = nIndex;
268 
269     if (IPWL_IconList_Notify* pNotify = GetNotify())
270       pNotify->OnNoteListSelChanged(nIndex);
271   }
272 }
273 
GetSelect() const274 int32_t CPWL_IconList_Content::GetSelect() const {
275   return m_nSelectIndex;
276 }
277 
GetNotify() const278 IPWL_IconList_Notify* CPWL_IconList_Content::GetNotify() const {
279   if (m_bEnableNotify)
280     return m_pNotify;
281   return NULL;
282 }
283 
SetNotify(IPWL_IconList_Notify * pNotify)284 void CPWL_IconList_Content::SetNotify(IPWL_IconList_Notify* pNotify) {
285   m_pNotify = pNotify;
286 }
287 
EnableNotify(FX_BOOL bNotify)288 void CPWL_IconList_Content::EnableNotify(FX_BOOL bNotify) {
289   m_bEnableNotify = bNotify;
290 }
291 
SelectItem(int32_t nItemIndex,FX_BOOL bSelect)292 void CPWL_IconList_Content::SelectItem(int32_t nItemIndex, FX_BOOL bSelect) {
293   if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex)) {
294     pItem->SetSelect(bSelect);
295     pItem->InvalidateRect();
296   }
297 }
298 
GetListItem(int32_t nItemIndex) const299 CPWL_IconList_Item* CPWL_IconList_Content::GetListItem(
300     int32_t nItemIndex) const {
301   if (nItemIndex >= 0 && nItemIndex < m_aChildren.GetSize()) {
302     if (CPWL_Wnd* pChild = m_aChildren.GetAt(nItemIndex)) {
303       if (pChild->GetClassName() == "CPWL_IconList_Item") {
304         return (CPWL_IconList_Item*)pChild;
305       }
306     }
307   }
308 
309   return NULL;
310 }
311 
SetListData(int32_t nItemIndex,void * pData)312 void CPWL_IconList_Content::SetListData(int32_t nItemIndex, void* pData) {
313   if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
314     pItem->SetData(pData);
315 }
316 
SetListIcon(int32_t nItemIndex,int32_t nIconIndex)317 void CPWL_IconList_Content::SetListIcon(int32_t nItemIndex,
318                                         int32_t nIconIndex) {
319   if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
320     pItem->SetIcon(nIconIndex);
321 }
322 
SetListString(int32_t nItemIndex,const CFX_WideString & str)323 void CPWL_IconList_Content::SetListString(int32_t nItemIndex,
324                                           const CFX_WideString& str) {
325   if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
326     pItem->SetText(str);
327 }
328 
GetListString(int32_t nItemIndex) const329 CFX_WideString CPWL_IconList_Content::GetListString(int32_t nItemIndex) const {
330   if (CPWL_IconList_Item* pItem = GetListItem(nItemIndex))
331     return pItem->GetText();
332 
333   return L"";
334 }
335 
SetIconFillColor(const CPWL_Color & color)336 void CPWL_IconList_Content::SetIconFillColor(const CPWL_Color& color) {
337   for (int32_t i = 0, sz = m_aChildren.GetSize(); i < sz; i++) {
338     if (CPWL_Wnd* pChild = m_aChildren.GetAt(i)) {
339       if (pChild->GetClassName() == "CPWL_IconList_Item") {
340         CPWL_IconList_Item* pItem = (CPWL_IconList_Item*)pChild;
341         pItem->SetIconFillColor(color);
342         pItem->InvalidateRect();
343       }
344     }
345   }
346 }
347 
CPWL_IconList(int32_t nListCount)348 CPWL_IconList::CPWL_IconList(int32_t nListCount)
349     : m_pListContent(NULL), m_nListCount(nListCount) {}
350 
~CPWL_IconList()351 CPWL_IconList::~CPWL_IconList() {}
352 
RePosChildWnd()353 void CPWL_IconList::RePosChildWnd() {
354   CPWL_Wnd::RePosChildWnd();
355 
356   if (m_pListContent)
357     m_pListContent->Move(GetClientRect(), TRUE, FALSE);
358 }
359 
CreateChildWnd(const PWL_CREATEPARAM & cp)360 void CPWL_IconList::CreateChildWnd(const PWL_CREATEPARAM& cp) {
361   m_pListContent = new CPWL_IconList_Content(m_nListCount);
362 
363   PWL_CREATEPARAM ccp = cp;
364   ccp.pParentWnd = this;
365   ccp.dwFlags = PWS_CHILD | PWS_VISIBLE;
366   m_pListContent->Create(ccp);
367 }
368 
OnCreated()369 void CPWL_IconList::OnCreated() {
370   if (CPWL_ScrollBar* pScrollBar = GetVScrollBar()) {
371     pScrollBar->RemoveFlag(PWS_AUTOTRANSPARENT);
372     pScrollBar->SetTransparency(255);
373     pScrollBar->SetNotifyForever(TRUE);
374   }
375 }
376 
OnNotify(CPWL_Wnd * pWnd,FX_DWORD msg,intptr_t wParam,intptr_t lParam)377 void CPWL_IconList::OnNotify(CPWL_Wnd* pWnd,
378                              FX_DWORD msg,
379                              intptr_t wParam,
380                              intptr_t lParam) {
381   CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam);
382 
383   if (wParam == SBT_VSCROLL) {
384     switch (msg) {
385       case PNM_SETSCROLLINFO:
386         if (PWL_SCROLL_INFO* pInfo = (PWL_SCROLL_INFO*)lParam) {
387           if (CPWL_ScrollBar* pScrollBar = GetVScrollBar()) {
388             if (pInfo->fContentMax - pInfo->fContentMin > pInfo->fPlateWidth) {
389               if (!pScrollBar->IsVisible()) {
390                 pScrollBar->SetVisible(TRUE);
391                 RePosChildWnd();
392               } else {
393               }
394             } else {
395               if (pScrollBar->IsVisible()) {
396                 pScrollBar->SetVisible(FALSE);
397                 RePosChildWnd();
398               }
399 
400               if (m_pListContent)
401                 m_pListContent->SetScrollPos(CPDF_Point(0.0f, 0.0f));
402             }
403 
404             pScrollBar->OnNotify(pWnd, PNM_SETSCROLLINFO, wParam, lParam);
405           }
406         }
407         return;
408       case PNM_SCROLLWINDOW:
409         if (m_pListContent) {
410           m_pListContent->SetScrollPos(CPDF_Point(0.0f, *(FX_FLOAT*)lParam));
411           m_pListContent->ResetFace();
412           m_pListContent->InvalidateRect(NULL);
413         }
414         return;
415       case PNM_SETSCROLLPOS:
416         if (CPWL_ScrollBar* pScrollBar = GetVScrollBar())
417           pScrollBar->OnNotify(pWnd, PNM_SETSCROLLPOS, wParam, lParam);
418         return;
419     }
420   }
421 }
422 
SetSelect(int32_t nIndex)423 void CPWL_IconList::SetSelect(int32_t nIndex) {
424   m_pListContent->SetSelect(nIndex);
425 }
426 
SetTopItem(int32_t nIndex)427 void CPWL_IconList::SetTopItem(int32_t nIndex) {
428   m_pListContent->ScrollToItem(nIndex);
429 }
430 
GetSelect() const431 int32_t CPWL_IconList::GetSelect() const {
432   return m_pListContent->GetSelect();
433 }
434 
SetNotify(IPWL_IconList_Notify * pNotify)435 void CPWL_IconList::SetNotify(IPWL_IconList_Notify* pNotify) {
436   m_pListContent->SetNotify(pNotify);
437 }
438 
EnableNotify(FX_BOOL bNotify)439 void CPWL_IconList::EnableNotify(FX_BOOL bNotify) {
440   m_pListContent->EnableNotify(bNotify);
441 }
442 
SetListData(int32_t nItemIndex,void * pData)443 void CPWL_IconList::SetListData(int32_t nItemIndex, void* pData) {
444   m_pListContent->SetListData(nItemIndex, pData);
445 }
446 
SetListIcon(int32_t nItemIndex,int32_t nIconIndex)447 void CPWL_IconList::SetListIcon(int32_t nItemIndex, int32_t nIconIndex) {
448   m_pListContent->SetListIcon(nItemIndex, nIconIndex);
449 }
450 
SetListString(int32_t nItemIndex,const CFX_WideString & str)451 void CPWL_IconList::SetListString(int32_t nItemIndex,
452                                   const CFX_WideString& str) {
453   m_pListContent->SetListString(nItemIndex, str);
454 }
455 
GetListString(int32_t nItemIndex) const456 CFX_WideString CPWL_IconList::GetListString(int32_t nItemIndex) const {
457   return m_pListContent->GetListString(nItemIndex);
458 }
459 
SetIconFillColor(const CPWL_Color & color)460 void CPWL_IconList::SetIconFillColor(const CPWL_Color& color) {
461   m_pListContent->SetIconFillColor(color);
462 }
463 
OnMouseWheel(short zDelta,const CPDF_Point & point,FX_DWORD nFlag)464 FX_BOOL CPWL_IconList::OnMouseWheel(short zDelta,
465                                     const CPDF_Point& point,
466                                     FX_DWORD nFlag) {
467   CPDF_Point ptScroll = m_pListContent->GetScrollPos();
468   CPDF_Rect rcScroll = m_pListContent->GetScrollArea();
469   CPDF_Rect rcContents = m_pListContent->GetClientRect();
470 
471   if (rcScroll.top - rcScroll.bottom > rcContents.Height()) {
472     CPDF_Point ptNew = ptScroll;
473 
474     if (zDelta > 0)
475       ptNew.y += 30;
476     else
477       ptNew.y -= 30;
478 
479     if (ptNew.y > rcScroll.top)
480       ptNew.y = rcScroll.top;
481     if (ptNew.y < rcScroll.bottom + rcContents.Height())
482       ptNew.y = rcScroll.bottom + rcContents.Height();
483     if (ptNew.y < rcScroll.bottom)
484       ptNew.y = rcScroll.bottom;
485 
486     if (ptNew.y != ptScroll.y) {
487       m_pListContent->SetScrollPos(ptNew);
488       m_pListContent->ResetFace();
489       m_pListContent->InvalidateRect(NULL);
490 
491       if (CPWL_ScrollBar* pScrollBar = GetVScrollBar())
492         pScrollBar->OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL,
493                              (intptr_t)&ptNew.y);
494 
495       return TRUE;
496     }
497   }
498 
499   return FALSE;
500 }
501