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 "xfa/src/foxitlib.h"
8 #include "xfa/src/fxfa/src/common/xfa_common.h"
9 #include "xfa_ffwidget.h"
10 #include "xfa_fffield.h"
11 #include "xfa_ffpageview.h"
12 #include "xfa_ffcheckbutton.h"
13 #include "xfa_ffexclgroup.h"
14 #include "xfa_ffdocview.h"
15 #include "xfa_ffapp.h"
16 #include "xfa_ffdoc.h"
CXFA_FFCheckButton(CXFA_FFPageView * pPageView,CXFA_WidgetAcc * pDataAcc)17 CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_FFPageView* pPageView,
18                                        CXFA_WidgetAcc* pDataAcc)
19     : CXFA_FFField(pPageView, pDataAcc), m_pOldDelegate(NULL) {
20   m_rtCheckBox.Set(0, 0, 0, 0);
21 }
~CXFA_FFCheckButton()22 CXFA_FFCheckButton::~CXFA_FFCheckButton() {}
LoadWidget()23 FX_BOOL CXFA_FFCheckButton::LoadWidget() {
24   CFWL_CheckBox* pCheckBox = CFWL_CheckBox::Create();
25   pCheckBox->Initialize();
26   m_pNormalWidget = pCheckBox;
27   IFWL_Widget* pWidget = m_pNormalWidget->GetWidget();
28   m_pNormalWidget->SetPrivateData(pWidget, this, NULL);
29   IFWL_NoteDriver* pNoteDriver = FWL_GetApp()->GetNoteDriver();
30   pNoteDriver->RegisterEventTarget(pWidget, pWidget);
31   m_pOldDelegate = m_pNormalWidget->SetDelegate(this);
32   if (m_pDataAcc->IsRadioButton()) {
33     pCheckBox->ModifyStylesEx(FWL_STYLEEXT_CKB_RadioButton, 0xFFFFFFFF);
34   }
35   m_pNormalWidget = (CFWL_Widget*)pCheckBox;
36   m_pNormalWidget->SetPrivateData(m_pNormalWidget->GetWidget(), this, NULL);
37   m_pNormalWidget->LockUpdate();
38   UpdateWidgetProperty();
39   XFA_CHECKSTATE eState = m_pDataAcc->GetCheckState();
40   SetFWLCheckState(eState);
41   m_pNormalWidget->UnlockUpdate();
42   return CXFA_FFField::LoadWidget();
43 }
UpdateWidgetProperty()44 void CXFA_FFCheckButton::UpdateWidgetProperty() {
45   CFWL_CheckBox* pCheckBox = (CFWL_CheckBox*)m_pNormalWidget;
46   if (!m_pNormalWidget) {
47     return;
48   }
49   FX_FLOAT fSize = m_pDataAcc->GetCheckButtonSize();
50   pCheckBox->SetBoxSize(fSize);
51   FX_DWORD dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCross;
52   int32_t iCheckMark = m_pDataAcc->GetCheckButtonMark();
53   switch (iCheckMark) {
54     case XFA_ATTRIBUTEENUM_Check:
55       dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCheck;
56       break;
57     case XFA_ATTRIBUTEENUM_Circle:
58       dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle;
59       break;
60     case XFA_ATTRIBUTEENUM_Cross:
61       break;
62     case XFA_ATTRIBUTEENUM_Diamond:
63       dwStyleEx = FWL_STYLEEXT_CKB_SignShapeDiamond;
64       break;
65     case XFA_ATTRIBUTEENUM_Square:
66       dwStyleEx = FWL_STYLEEXT_CKB_SignShapeSquare;
67       break;
68     case XFA_ATTRIBUTEENUM_Star:
69       dwStyleEx = FWL_STYLEEXT_CKB_SignShapeStar;
70       break;
71     default: {
72       int32_t iShape = m_pDataAcc->GetCheckButtonShape();
73       if (iShape == XFA_ATTRIBUTEENUM_Round) {
74         dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle;
75       }
76     } break;
77   }
78   if (m_pDataAcc->IsAllowNeutral()) {
79     dwStyleEx |= FWL_STYLEEXT_CKB_3State;
80   }
81   pCheckBox->ModifyStylesEx(
82       dwStyleEx, FWL_STYLEEXT_CKB_SignShapeMask | FWL_STYLEEXT_CKB_3State);
83 }
PerformLayout()84 FX_BOOL CXFA_FFCheckButton::PerformLayout() {
85   CXFA_FFWidget::PerformLayout();
86   FX_FLOAT fCheckSize = m_pDataAcc->GetCheckButtonSize();
87   CXFA_Margin mgWidget = m_pDataAcc->GetMargin();
88   CFX_RectF rtWidget;
89   GetRectWithoutRotate(rtWidget);
90   if (mgWidget.IsExistInXML()) {
91     XFA_RectWidthoutMargin(rtWidget, mgWidget);
92   }
93   int32_t iCapPlacement = -1;
94   FX_FLOAT fCapReserve = 0;
95   CXFA_Caption caption = m_pDataAcc->GetCaption();
96   if (caption.IsExistInXML() && caption.GetPresence()) {
97     m_rtCaption.Set(rtWidget.left, rtWidget.top, rtWidget.width,
98                     rtWidget.height);
99     iCapPlacement = caption.GetPlacementType();
100     fCapReserve = caption.GetReserve();
101     if (fCapReserve <= 0) {
102       if (iCapPlacement == XFA_ATTRIBUTEENUM_Top ||
103           iCapPlacement == XFA_ATTRIBUTEENUM_Bottom) {
104         fCapReserve = rtWidget.height - fCheckSize;
105       } else {
106         fCapReserve = rtWidget.width - fCheckSize;
107       }
108     }
109   }
110   int32_t iHorzAlign = XFA_ATTRIBUTEENUM_Left;
111   int32_t iVertAlign = XFA_ATTRIBUTEENUM_Top;
112   if (CXFA_Para para = m_pDataAcc->GetPara()) {
113     iHorzAlign = para.GetHorizontalAlign();
114     iVertAlign = para.GetVerticalAlign();
115   }
116   m_rtUI = rtWidget;
117   CXFA_Margin mgCap = caption.GetMargin();
118   switch (iCapPlacement) {
119     case XFA_ATTRIBUTEENUM_Left: {
120       m_rtCaption.width = fCapReserve;
121       CapLeftRightPlacement(mgCap);
122       m_rtUI.width -= fCapReserve;
123       m_rtUI.left += fCapReserve;
124     } break;
125     case XFA_ATTRIBUTEENUM_Top: {
126       m_rtCaption.height = fCapReserve;
127       XFA_RectWidthoutMargin(m_rtCaption, mgCap);
128       m_rtUI.height -= fCapReserve;
129       m_rtUI.top += fCapReserve;
130     } break;
131     case XFA_ATTRIBUTEENUM_Right: {
132       m_rtCaption.left = m_rtCaption.right() - fCapReserve;
133       m_rtCaption.width = fCapReserve;
134       CapLeftRightPlacement(mgCap);
135       m_rtUI.width -= fCapReserve;
136     } break;
137     case XFA_ATTRIBUTEENUM_Bottom: {
138       m_rtCaption.top = m_rtCaption.bottom() - fCapReserve;
139       m_rtCaption.height = fCapReserve;
140       XFA_RectWidthoutMargin(m_rtCaption, mgCap);
141       m_rtUI.height -= fCapReserve;
142     } break;
143     case XFA_ATTRIBUTEENUM_Inline:
144       break;
145     default:
146       iHorzAlign = XFA_ATTRIBUTEENUM_Right;
147       break;
148   }
149   if (iHorzAlign == XFA_ATTRIBUTEENUM_Center) {
150     m_rtUI.left += (m_rtUI.width - fCheckSize) / 2;
151   } else if (iHorzAlign == XFA_ATTRIBUTEENUM_Right) {
152     m_rtUI.left = m_rtUI.right() - fCheckSize;
153   }
154   if (iVertAlign == XFA_ATTRIBUTEENUM_Middle) {
155     m_rtUI.top += (m_rtUI.height - fCheckSize) / 2;
156   } else if (iVertAlign == XFA_ATTRIBUTEENUM_Bottom) {
157     m_rtUI.top = m_rtUI.bottom() - fCheckSize;
158   }
159   m_rtUI.width = fCheckSize;
160   m_rtUI.height = fCheckSize;
161   AddUIMargin(iCapPlacement);
162   m_rtCheckBox = m_rtUI;
163   CXFA_Border borderUI = m_pDataAcc->GetUIBorder();
164   if (borderUI) {
165     CXFA_Margin margin = borderUI.GetMargin();
166     if (margin.IsExistInXML()) {
167       XFA_RectWidthoutMargin(m_rtUI, margin);
168     }
169   }
170   m_rtUI.Normalize();
171   LayoutCaption();
172   SetFWLRect();
173   if (m_pNormalWidget) {
174     m_pNormalWidget->Update();
175   }
176   return TRUE;
177 }
CapLeftRightPlacement(CXFA_Margin mgCap)178 void CXFA_FFCheckButton::CapLeftRightPlacement(CXFA_Margin mgCap) {
179   XFA_RectWidthoutMargin(m_rtCaption, mgCap);
180   if (m_rtCaption.height < 0) {
181     m_rtCaption.top += m_rtCaption.height;
182   }
183   if (m_rtCaption.width < 0) {
184     m_rtCaption.left += m_rtCaption.width;
185     m_rtCaption.width = -m_rtCaption.width;
186   }
187 }
AddUIMargin(int32_t iCapPlacement)188 void CXFA_FFCheckButton::AddUIMargin(int32_t iCapPlacement) {
189   CFX_RectF rtUIMargin;
190   m_pDataAcc->GetUIMargin(rtUIMargin);
191   m_rtUI.top -= rtUIMargin.top / 2 - rtUIMargin.height / 2;
192   FX_FLOAT fLeftAddRight = rtUIMargin.left + rtUIMargin.width;
193   FX_FLOAT fTopAddBottom = rtUIMargin.top + rtUIMargin.height;
194   if (m_rtUI.width < fLeftAddRight) {
195     if (iCapPlacement == XFA_ATTRIBUTEENUM_Right ||
196         iCapPlacement == XFA_ATTRIBUTEENUM_Left) {
197       m_rtUI.left -= fLeftAddRight - m_rtUI.width;
198     } else {
199       m_rtUI.left -= 2 * (fLeftAddRight - m_rtUI.width);
200     }
201     m_rtUI.width += 2 * (fLeftAddRight - m_rtUI.width);
202   }
203   if (m_rtUI.height < fTopAddBottom) {
204     if (iCapPlacement == XFA_ATTRIBUTEENUM_Right) {
205       m_rtUI.left -= fTopAddBottom - m_rtUI.height;
206     }
207     m_rtUI.top -= fTopAddBottom - m_rtUI.height;
208     m_rtUI.height += 2 * (fTopAddBottom - m_rtUI.height);
209   }
210 }
RenderWidget(CFX_Graphics * pGS,CFX_Matrix * pMatrix,FX_DWORD dwStatus,int32_t iRotate)211 void CXFA_FFCheckButton::RenderWidget(CFX_Graphics* pGS,
212                                       CFX_Matrix* pMatrix,
213                                       FX_DWORD dwStatus,
214                                       int32_t iRotate) {
215   if (!IsMatchVisibleStatus(dwStatus)) {
216     return;
217   }
218   CFX_Matrix mtRotate;
219   GetRotateMatrix(mtRotate);
220   if (pMatrix) {
221     mtRotate.Concat(*pMatrix);
222   }
223   CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
224   CXFA_Border borderUI = m_pDataAcc->GetUIBorder();
225   DrawBorder(pGS, borderUI, m_rtUI, &mtRotate,
226              m_pDataAcc->GetCheckButtonShape() == XFA_ATTRIBUTEENUM_Round
227                  ? XFA_DRAWBOX_ForceRound
228                  : 0);
229   RenderCaption(pGS, &mtRotate);
230   DrawHighlight(pGS, &mtRotate, dwStatus,
231                 m_pDataAcc->GetCheckButtonShape() == XFA_ATTRIBUTEENUM_Round);
232   CFX_Matrix mt;
233   mt.Set(1, 0, 0, 1, m_rtCheckBox.left, m_rtCheckBox.top);
234   mt.Concat(mtRotate);
235   GetApp()->GetWidgetMgrDelegate()->OnDrawWidget(m_pNormalWidget->GetWidget(),
236                                                  pGS, &mt);
237 }
OnLButtonUp(FX_DWORD dwFlags,FX_FLOAT fx,FX_FLOAT fy)238 FX_BOOL CXFA_FFCheckButton::OnLButtonUp(FX_DWORD dwFlags,
239                                         FX_FLOAT fx,
240                                         FX_FLOAT fy) {
241   if (!m_pNormalWidget) {
242     return FALSE;
243   }
244   if (!IsButtonDown()) {
245     return FALSE;
246   }
247   SetButtonDown(FALSE);
248   CFWL_MsgMouse ms;
249   ms.m_dwCmd = FWL_MSGMOUSECMD_LButtonUp;
250   ms.m_dwFlags = dwFlags;
251   ms.m_fx = fx;
252   ms.m_fy = fy;
253   FWLToClient(ms.m_fx, ms.m_fy);
254   ms.m_pDstTarget = m_pNormalWidget->m_pIface;
255   TranslateFWLMessage(&ms);
256   return TRUE;
257 }
FWLState2XFAState()258 XFA_CHECKSTATE CXFA_FFCheckButton::FWLState2XFAState() {
259   XFA_CHECKSTATE eCheckState = XFA_CHECKSTATE_Off;
260   FX_DWORD dwState = m_pNormalWidget->GetStates();
261   if (dwState & FWL_STATE_CKB_Checked) {
262     eCheckState = XFA_CHECKSTATE_On;
263   } else if (dwState & FWL_STATE_CKB_Neutral) {
264     eCheckState = XFA_CHECKSTATE_Neutral;
265   }
266   return eCheckState;
267 }
CommitData()268 FX_BOOL CXFA_FFCheckButton::CommitData() {
269   XFA_CHECKSTATE eCheckState = FWLState2XFAState();
270   m_pDataAcc->SetCheckState(eCheckState, TRUE);
271   return TRUE;
272 }
IsDataChanged()273 FX_BOOL CXFA_FFCheckButton::IsDataChanged() {
274   XFA_CHECKSTATE eCheckState = FWLState2XFAState();
275   return m_pDataAcc->GetCheckState() != eCheckState;
276 }
SetFWLCheckState(XFA_CHECKSTATE eCheckState)277 void CXFA_FFCheckButton::SetFWLCheckState(XFA_CHECKSTATE eCheckState) {
278   if (eCheckState == XFA_CHECKSTATE_Neutral) {
279     m_pNormalWidget->SetStates(FWL_STATE_CKB_Neutral, TRUE);
280   } else {
281     m_pNormalWidget->SetStates(FWL_STATE_CKB_Checked,
282                                eCheckState == XFA_CHECKSTATE_On);
283   }
284 }
UpdateFWLData()285 FX_BOOL CXFA_FFCheckButton::UpdateFWLData() {
286   if (!m_pNormalWidget) {
287     return FALSE;
288   }
289   XFA_CHECKSTATE eState = m_pDataAcc->GetCheckState();
290   SetFWLCheckState(eState);
291   m_pNormalWidget->Update();
292   return TRUE;
293 }
OnProcessMessage(CFWL_Message * pMessage)294 int32_t CXFA_FFCheckButton::OnProcessMessage(CFWL_Message* pMessage) {
295   return m_pOldDelegate->OnProcessMessage(pMessage);
296 }
OnProcessEvent(CFWL_Event * pEvent)297 FWL_ERR CXFA_FFCheckButton::OnProcessEvent(CFWL_Event* pEvent) {
298   CXFA_FFField::OnProcessEvent(pEvent);
299   FX_DWORD dwEventID = pEvent->GetClassID();
300   switch (dwEventID) {
301     case FWL_EVTHASH_CKB_CheckStateChanged: {
302       CXFA_EventParam eParam;
303       eParam.m_eType = XFA_EVENT_Change;
304       m_pDataAcc->GetValue(eParam.m_wsNewText, XFA_VALUEPICTURE_Raw);
305       CXFA_WidgetAcc* pFFExclGroup = m_pDataAcc->GetExclGroup();
306       if (ProcessCommittedData()) {
307         eParam.m_pTarget = pFFExclGroup;
308         if (pFFExclGroup) {
309           m_pDocView->AddValidateWidget(pFFExclGroup);
310           m_pDocView->AddCalculateWidgetAcc(pFFExclGroup);
311           pFFExclGroup->ProcessEvent(XFA_ATTRIBUTEENUM_Change, &eParam);
312         }
313         eParam.m_pTarget = m_pDataAcc;
314         m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Change, &eParam);
315       } else {
316         SetFWLCheckState(m_pDataAcc->GetCheckState());
317       }
318       if (pFFExclGroup) {
319         eParam.m_pTarget = pFFExclGroup;
320         pFFExclGroup->ProcessEvent(XFA_ATTRIBUTEENUM_Click, &eParam);
321       }
322       eParam.m_pTarget = m_pDataAcc;
323       m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Click, &eParam);
324       break;
325     }
326     default: {}
327   }
328   return m_pOldDelegate->OnProcessEvent(pEvent);
329 }
OnDrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)330 FWL_ERR CXFA_FFCheckButton::OnDrawWidget(CFX_Graphics* pGraphics,
331                                          const CFX_Matrix* pMatrix) {
332   return m_pOldDelegate->OnDrawWidget(pGraphics, pMatrix);
333 }
334