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