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/cfwl_checkbox.h"
10 #include "xfa/fwl/cfwl_messagemouse.h"
11 #include "xfa/fwl/cfwl_notedriver.h"
12 #include "xfa/fwl/cfwl_widgetmgr.h"
13 #include "xfa/fxfa/app/xfa_ffexclgroup.h"
14 #include "xfa/fxfa/app/xfa_fffield.h"
15 #include "xfa/fxfa/xfa_ffapp.h"
16 #include "xfa/fxfa/xfa_ffdoc.h"
17 #include "xfa/fxfa/xfa_ffdocview.h"
18 #include "xfa/fxfa/xfa_ffpageview.h"
19 #include "xfa/fxfa/xfa_ffwidget.h"
20
CXFA_FFCheckButton(CXFA_WidgetAcc * pDataAcc)21 CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_WidgetAcc* pDataAcc)
22 : CXFA_FFField(pDataAcc), m_pOldDelegate(nullptr) {}
23
~CXFA_FFCheckButton()24 CXFA_FFCheckButton::~CXFA_FFCheckButton() {}
25
LoadWidget()26 bool CXFA_FFCheckButton::LoadWidget() {
27 CFWL_CheckBox* pCheckBox = new CFWL_CheckBox(GetFWLApp());
28 m_pNormalWidget = pCheckBox;
29 m_pNormalWidget->SetLayoutItem(this);
30
31 CFWL_NoteDriver* pNoteDriver =
32 m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
33 pNoteDriver->RegisterEventTarget(m_pNormalWidget, m_pNormalWidget);
34
35 m_pOldDelegate = m_pNormalWidget->GetDelegate();
36 m_pNormalWidget->SetDelegate(this);
37
38 if (m_pDataAcc->IsRadioButton())
39 pCheckBox->ModifyStylesEx(FWL_STYLEEXT_CKB_RadioButton, 0xFFFFFFFF);
40
41 m_pNormalWidget->LockUpdate();
42 UpdateWidgetProperty();
43 SetFWLCheckState(m_pDataAcc->GetCheckState());
44 m_pNormalWidget->UnlockUpdate();
45 return CXFA_FFField::LoadWidget();
46 }
UpdateWidgetProperty()47 void CXFA_FFCheckButton::UpdateWidgetProperty() {
48 CFWL_CheckBox* pCheckBox = (CFWL_CheckBox*)m_pNormalWidget;
49 if (!m_pNormalWidget) {
50 return;
51 }
52 FX_FLOAT fSize = m_pDataAcc->GetCheckButtonSize();
53 pCheckBox->SetBoxSize(fSize);
54 uint32_t dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCross;
55 int32_t iCheckMark = m_pDataAcc->GetCheckButtonMark();
56 switch (iCheckMark) {
57 case XFA_ATTRIBUTEENUM_Check:
58 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCheck;
59 break;
60 case XFA_ATTRIBUTEENUM_Circle:
61 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle;
62 break;
63 case XFA_ATTRIBUTEENUM_Cross:
64 break;
65 case XFA_ATTRIBUTEENUM_Diamond:
66 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeDiamond;
67 break;
68 case XFA_ATTRIBUTEENUM_Square:
69 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeSquare;
70 break;
71 case XFA_ATTRIBUTEENUM_Star:
72 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeStar;
73 break;
74 default: {
75 int32_t iShape = m_pDataAcc->GetCheckButtonShape();
76 if (iShape == XFA_ATTRIBUTEENUM_Round) {
77 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle;
78 }
79 } break;
80 }
81 if (m_pDataAcc->IsAllowNeutral()) {
82 dwStyleEx |= FWL_STYLEEXT_CKB_3State;
83 }
84 pCheckBox->ModifyStylesEx(
85 dwStyleEx, FWL_STYLEEXT_CKB_SignShapeMask | FWL_STYLEEXT_CKB_3State);
86 }
PerformLayout()87 bool CXFA_FFCheckButton::PerformLayout() {
88 CXFA_FFWidget::PerformLayout();
89 FX_FLOAT fCheckSize = m_pDataAcc->GetCheckButtonSize();
90 CXFA_Margin mgWidget = m_pDataAcc->GetMargin();
91 CFX_RectF rtWidget = GetRectWithoutRotate();
92 if (mgWidget) {
93 XFA_RectWidthoutMargin(rtWidget, mgWidget);
94 }
95 int32_t iCapPlacement = -1;
96 FX_FLOAT fCapReserve = 0;
97 CXFA_Caption caption = m_pDataAcc->GetCaption();
98 if (caption && caption.GetPresence()) {
99 m_rtCaption = rtWidget;
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 = m_pDataAcc->GetUIMargin();
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,uint32_t dwStatus)211 void CXFA_FFCheckButton::RenderWidget(CFX_Graphics* pGS,
212 CFX_Matrix* pMatrix,
213 uint32_t dwStatus) {
214 if (!IsMatchVisibleStatus(dwStatus))
215 return;
216
217 CFX_Matrix mtRotate = GetRotateMatrix();
218 if (pMatrix)
219 mtRotate.Concat(*pMatrix);
220
221 CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
222 CXFA_Border borderUI = m_pDataAcc->GetUIBorder();
223 DrawBorder(pGS, borderUI, m_rtUI, &mtRotate,
224 m_pDataAcc->GetCheckButtonShape() == XFA_ATTRIBUTEENUM_Round
225 ? XFA_DRAWBOX_ForceRound
226 : 0);
227 RenderCaption(pGS, &mtRotate);
228 DrawHighlight(pGS, &mtRotate, dwStatus,
229 m_pDataAcc->GetCheckButtonShape() == XFA_ATTRIBUTEENUM_Round);
230 CFX_Matrix mt(1, 0, 0, 1, m_rtCheckBox.left, m_rtCheckBox.top);
231 mt.Concat(mtRotate);
232 GetApp()->GetWidgetMgrDelegate()->OnDrawWidget(m_pNormalWidget, pGS, &mt);
233 }
OnLButtonUp(uint32_t dwFlags,const CFX_PointF & point)234 bool CXFA_FFCheckButton::OnLButtonUp(uint32_t dwFlags,
235 const CFX_PointF& point) {
236 if (!m_pNormalWidget || !IsButtonDown())
237 return false;
238
239 SetButtonDown(false);
240 CFWL_MessageMouse ms(nullptr, m_pNormalWidget);
241 ms.m_dwCmd = FWL_MouseCommand::LeftButtonUp;
242 ms.m_dwFlags = dwFlags;
243 ms.m_pos = FWLToClient(point);
244 TranslateFWLMessage(&ms);
245 return true;
246 }
247
FWLState2XFAState()248 XFA_CHECKSTATE CXFA_FFCheckButton::FWLState2XFAState() {
249 uint32_t dwState = m_pNormalWidget->GetStates();
250 if (dwState & FWL_STATE_CKB_Checked)
251 return XFA_CHECKSTATE_On;
252 if (dwState & FWL_STATE_CKB_Neutral)
253 return XFA_CHECKSTATE_Neutral;
254 return XFA_CHECKSTATE_Off;
255 }
256
CommitData()257 bool CXFA_FFCheckButton::CommitData() {
258 XFA_CHECKSTATE eCheckState = FWLState2XFAState();
259 m_pDataAcc->SetCheckState(eCheckState, true);
260 return true;
261 }
262
IsDataChanged()263 bool CXFA_FFCheckButton::IsDataChanged() {
264 XFA_CHECKSTATE eCheckState = FWLState2XFAState();
265 return m_pDataAcc->GetCheckState() != eCheckState;
266 }
SetFWLCheckState(XFA_CHECKSTATE eCheckState)267 void CXFA_FFCheckButton::SetFWLCheckState(XFA_CHECKSTATE eCheckState) {
268 if (eCheckState == XFA_CHECKSTATE_Neutral) {
269 m_pNormalWidget->SetStates(FWL_STATE_CKB_Neutral);
270 } else {
271 if (eCheckState == XFA_CHECKSTATE_On)
272 m_pNormalWidget->SetStates(FWL_STATE_CKB_Checked);
273 else
274 m_pNormalWidget->RemoveStates(FWL_STATE_CKB_Checked);
275 }
276 }
UpdateFWLData()277 bool CXFA_FFCheckButton::UpdateFWLData() {
278 if (!m_pNormalWidget) {
279 return false;
280 }
281 XFA_CHECKSTATE eState = m_pDataAcc->GetCheckState();
282 SetFWLCheckState(eState);
283 m_pNormalWidget->Update();
284 return true;
285 }
286
OnProcessMessage(CFWL_Message * pMessage)287 void CXFA_FFCheckButton::OnProcessMessage(CFWL_Message* pMessage) {
288 m_pOldDelegate->OnProcessMessage(pMessage);
289 }
290
OnProcessEvent(CFWL_Event * pEvent)291 void CXFA_FFCheckButton::OnProcessEvent(CFWL_Event* pEvent) {
292 CXFA_FFField::OnProcessEvent(pEvent);
293 switch (pEvent->GetType()) {
294 case CFWL_Event::Type::CheckStateChanged: {
295 CXFA_EventParam eParam;
296 eParam.m_eType = XFA_EVENT_Change;
297 m_pDataAcc->GetValue(eParam.m_wsNewText, XFA_VALUEPICTURE_Raw);
298 CXFA_WidgetAcc* pFFExclGroup = m_pDataAcc->GetExclGroup();
299 if (ProcessCommittedData()) {
300 eParam.m_pTarget = pFFExclGroup;
301 if (pFFExclGroup) {
302 m_pDocView->AddValidateWidget(pFFExclGroup);
303 m_pDocView->AddCalculateWidgetAcc(pFFExclGroup);
304 pFFExclGroup->ProcessEvent(XFA_ATTRIBUTEENUM_Change, &eParam);
305 }
306 eParam.m_pTarget = m_pDataAcc;
307 m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Change, &eParam);
308 } else {
309 SetFWLCheckState(m_pDataAcc->GetCheckState());
310 }
311 if (pFFExclGroup) {
312 eParam.m_pTarget = pFFExclGroup;
313 pFFExclGroup->ProcessEvent(XFA_ATTRIBUTEENUM_Click, &eParam);
314 }
315 eParam.m_pTarget = m_pDataAcc;
316 m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Click, &eParam);
317 break;
318 }
319 default:
320 break;
321 }
322 m_pOldDelegate->OnProcessEvent(pEvent);
323 }
324
OnDrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)325 void CXFA_FFCheckButton::OnDrawWidget(CFX_Graphics* pGraphics,
326 const CFX_Matrix* pMatrix) {
327 m_pOldDelegate->OnDrawWidget(pGraphics, pMatrix);
328 }
329