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_ListCtrl.h"
8 #include "fpdfsdk/include/pdfwindow/PWL_Wnd.h"
9 
CPWL_ListCtrl()10 CPWL_ListCtrl::CPWL_ListCtrl()
11     : m_rcContent(0, 0, 0, 0),
12       m_ptScroll(0, 0),
13       m_fItemSpace(0.0f),
14       m_fTopSpace(0.0f),
15       m_fBottomSpace(0.0f) {}
16 
~CPWL_ListCtrl()17 CPWL_ListCtrl::~CPWL_ListCtrl() {}
18 
SetScrollPos(const CPDF_Point & point)19 void CPWL_ListCtrl::SetScrollPos(const CPDF_Point& point) {
20   m_ptScroll = point;
21 
22   if (m_ptScroll.x < m_rcContent.left)
23     m_ptScroll.x = m_rcContent.left;
24 
25   if (m_ptScroll.x > m_rcContent.right)
26     m_ptScroll.x = m_rcContent.right;
27 
28   if (m_ptScroll.y > m_rcContent.top)
29     m_ptScroll.y = m_rcContent.top;
30 
31   if (m_ptScroll.y < m_rcContent.bottom)
32     m_ptScroll.y = m_rcContent.bottom;
33 }
34 
GetScrollPos() const35 CPDF_Point CPWL_ListCtrl::GetScrollPos() const {
36   return m_ptScroll;
37 }
38 
GetScrollArea() const39 CPDF_Rect CPWL_ListCtrl::GetScrollArea() const {
40   return m_rcContent;
41 }
42 
ResetFace()43 void CPWL_ListCtrl::ResetFace() {
44   ResetAll(FALSE, 0);
45 }
46 
ResetContent(int32_t nStart)47 void CPWL_ListCtrl::ResetContent(int32_t nStart) {
48   if (nStart < 0)
49     nStart = 0;
50   if (nStart >= 0 && nStart < m_aChildren.GetSize())
51     ResetAll(TRUE, nStart);
52 }
53 
GetContentsHeight(FX_FLOAT fLimitWidth)54 FX_FLOAT CPWL_ListCtrl::GetContentsHeight(FX_FLOAT fLimitWidth) {
55   FX_FLOAT fRet = m_fTopSpace;
56 
57   FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
58 
59   if (fLimitWidth > fBorderWidth * 2) {
60     for (int32_t i = 0, sz = m_aChildren.GetSize(); i < sz; i++) {
61       if (CPWL_Wnd* pChild = m_aChildren.GetAt(i)) {
62         FX_FLOAT fLeft = pChild->GetItemLeftMargin();
63         FX_FLOAT fRight = pChild->GetItemRightMargin();
64 
65         fRet += pChild->GetItemHeight(fLimitWidth - fBorderWidth * 2 - fLeft -
66                                       fRight);
67         fRet += m_fItemSpace;
68       }
69     }
70 
71     fRet -= m_fItemSpace;
72   }
73 
74   fRet += m_fBottomSpace;
75 
76   return fRet;
77 }
78 
ResetAll(FX_BOOL bMove,int32_t nStart)79 void CPWL_ListCtrl::ResetAll(FX_BOOL bMove, int32_t nStart) {
80   CPDF_Rect rcClient = GetClientRect();
81 
82   FX_FLOAT fWidth = rcClient.Width();
83 
84   FX_FLOAT fy = 0.0f - m_fTopSpace;
85 
86   if (nStart - 1 >= 0 && nStart - 1 < m_aChildren.GetSize())
87     if (CPWL_Wnd* pChild = m_aChildren.GetAt(nStart - 1))
88       fy = pChild->GetWindowRect().bottom - m_fItemSpace;
89 
90   for (int32_t i = nStart, sz = m_aChildren.GetSize(); i < sz; i++) {
91     if (CPWL_Wnd* pChild = m_aChildren.GetAt(i)) {
92       FX_FLOAT fLeft = pChild->GetItemLeftMargin();
93       FX_FLOAT fRight = pChild->GetItemRightMargin();
94 
95       pChild->SetChildMatrix(CFX_Matrix(1, 0, 0, 1,
96                                         rcClient.left - m_ptScroll.x,
97                                         rcClient.top - m_ptScroll.y));
98 
99       if (bMove) {
100         FX_FLOAT fItemHeight = pChild->GetItemHeight(fWidth - fLeft - fRight);
101         pChild->Move(CPDF_Rect(fLeft, fy - fItemHeight, fWidth - fRight, fy),
102                      TRUE, FALSE);
103         fy -= fItemHeight;
104         fy -= m_fItemSpace;
105       }
106     }
107   }
108 
109   fy += m_fItemSpace;
110 
111   fy -= m_fBottomSpace;
112 
113   if (bMove) {
114     m_rcContent.left = 0;
115     m_rcContent.top = 0;
116     m_rcContent.right = fWidth;
117     m_rcContent.bottom = fy;
118   }
119 }
120 
SetItemSpace(FX_FLOAT fSpace)121 void CPWL_ListCtrl::SetItemSpace(FX_FLOAT fSpace) {
122   m_fItemSpace = fSpace;
123 }
124 
SetTopSpace(FX_FLOAT fSpace)125 void CPWL_ListCtrl::SetTopSpace(FX_FLOAT fSpace) {
126   m_fTopSpace = fSpace;
127 }
128 
SetBottomSpace(FX_FLOAT fSpace)129 void CPWL_ListCtrl::SetBottomSpace(FX_FLOAT fSpace) {
130   m_fBottomSpace = fSpace;
131 }
132 
RePosChildWnd()133 void CPWL_ListCtrl::RePosChildWnd() {
134   ResetFace();
135 }
136 
DrawChildAppearance(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device)137 void CPWL_ListCtrl::DrawChildAppearance(CFX_RenderDevice* pDevice,
138                                         CFX_Matrix* pUser2Device) {
139   pDevice->SaveState();
140   CPDF_Rect rcClient = GetClientRect();
141   CPDF_Rect rcTemp = rcClient;
142   pUser2Device->TransformRect(rcTemp);
143   FX_RECT rcClip((int32_t)rcTemp.left, (int32_t)rcTemp.bottom,
144                  (int32_t)rcTemp.right, (int32_t)rcTemp.top);
145 
146   pDevice->SetClip_Rect(&rcClip);
147 
148   for (int32_t i = 0, sz = m_aChildren.GetSize(); i < sz; i++) {
149     if (CPWL_Wnd* pChild = m_aChildren.GetAt(i)) {
150       CPDF_Rect rcChild = pChild->ChildToParent(pChild->GetWindowRect());
151       if (!(rcChild.top < rcClient.bottom || rcChild.bottom > rcClient.top)) {
152         CFX_Matrix mt = pChild->GetChildMatrix();
153         if (mt.IsIdentity()) {
154           pChild->DrawAppearance(pDevice, pUser2Device);
155         } else {
156           mt.Concat(*pUser2Device);
157           pChild->DrawAppearance(pDevice, &mt);
158         }
159       }
160     }
161   }
162 
163   pDevice->RestoreState();
164 }
165 
GetItemIndex(CPWL_Wnd * pItem)166 int32_t CPWL_ListCtrl::GetItemIndex(CPWL_Wnd* pItem) {
167   for (int32_t i = 0, sz = m_aChildren.GetSize(); i < sz; i++) {
168     if (pItem == m_aChildren.GetAt(i))
169       return i;
170   }
171 
172   return -1;
173 }
174 
InToOut(const CPDF_Point & point) const175 CPDF_Point CPWL_ListCtrl::InToOut(const CPDF_Point& point) const {
176   CPDF_Rect rcClient = GetClientRect();
177 
178   return CPDF_Point(point.x + rcClient.left - m_ptScroll.x,
179                     point.y + rcClient.top - m_ptScroll.y);
180 }
181 
OutToIn(const CPDF_Point & point) const182 CPDF_Point CPWL_ListCtrl::OutToIn(const CPDF_Point& point) const {
183   CPDF_Rect rcClient = GetClientRect();
184 
185   return CPDF_Point(point.x - rcClient.left + m_ptScroll.x,
186                     point.y - rcClient.top + m_ptScroll.y);
187 }
188 
InToOut(const CPDF_Rect & rect) const189 CPDF_Rect CPWL_ListCtrl::InToOut(const CPDF_Rect& rect) const {
190   CPDF_Rect rcClient = GetClientRect();
191 
192   return CPDF_Rect(rect.left + rcClient.left - m_ptScroll.x,
193                    rect.bottom + rcClient.top - m_ptScroll.y,
194                    rect.right + rcClient.left - m_ptScroll.x,
195                    rect.top + rcClient.top - m_ptScroll.y);
196 }
197 
OutToIn(const CPDF_Rect & rect) const198 CPDF_Rect CPWL_ListCtrl::OutToIn(const CPDF_Rect& rect) const {
199   CPDF_Rect rcClient = GetClientRect();
200 
201   return CPDF_Rect(rect.left - rcClient.left + m_ptScroll.x,
202                    rect.bottom - rcClient.top + m_ptScroll.y,
203                    rect.right - rcClient.left + m_ptScroll.x,
204                    rect.top - rcClient.top + m_ptScroll.y);
205 }
206