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/cxfa_ffcheckbutton.h"
8
9 #include <utility>
10 #include "third_party/base/ptr_util.h"
11 #include "xfa/fwl/cfwl_checkbox.h"
12 #include "xfa/fwl/cfwl_messagemouse.h"
13 #include "xfa/fwl/cfwl_notedriver.h"
14 #include "xfa/fwl/cfwl_widgetmgr.h"
15 #include "xfa/fxfa/cxfa_ffapp.h"
16 #include "xfa/fxfa/cxfa_ffdoc.h"
17 #include "xfa/fxfa/cxfa_ffdocview.h"
18 #include "xfa/fxfa/cxfa_ffexclgroup.h"
19 #include "xfa/fxfa/cxfa_fffield.h"
20 #include "xfa/fxfa/cxfa_ffpageview.h"
21 #include "xfa/fxfa/cxfa_ffwidget.h"
22 #include "xfa/fxfa/parser/cxfa_border.h"
23 #include "xfa/fxfa/parser/cxfa_caption.h"
24 #include "xfa/fxfa/parser/cxfa_para.h"
25
CXFA_FFCheckButton(CXFA_Node * pNode)26 CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_Node* pNode)
27 : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
28
~CXFA_FFCheckButton()29 CXFA_FFCheckButton::~CXFA_FFCheckButton() {}
30
LoadWidget()31 bool CXFA_FFCheckButton::LoadWidget() {
32 auto pNew = pdfium::MakeUnique<CFWL_CheckBox>(GetFWLApp());
33 CFWL_CheckBox* pCheckBox = pNew.get();
34 m_pNormalWidget = std::move(pNew);
35 m_pNormalWidget->SetLayoutItem(this);
36
37 CFWL_NoteDriver* pNoteDriver =
38 m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
39 pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
40 m_pNormalWidget.get());
41 m_pOldDelegate = m_pNormalWidget->GetDelegate();
42 m_pNormalWidget->SetDelegate(this);
43 if (m_pNode->GetWidgetAcc()->IsRadioButton())
44 pCheckBox->ModifyStylesEx(FWL_STYLEEXT_CKB_RadioButton, 0xFFFFFFFF);
45
46 m_pNormalWidget->LockUpdate();
47 UpdateWidgetProperty();
48 SetFWLCheckState(m_pNode->GetWidgetAcc()->GetCheckState());
49 m_pNormalWidget->UnlockUpdate();
50 return CXFA_FFField::LoadWidget();
51 }
52
UpdateWidgetProperty()53 void CXFA_FFCheckButton::UpdateWidgetProperty() {
54 auto* pCheckBox = static_cast<CFWL_CheckBox*>(m_pNormalWidget.get());
55 if (!pCheckBox)
56 return;
57
58 pCheckBox->SetBoxSize(m_pNode->GetWidgetAcc()->GetCheckButtonSize());
59 uint32_t dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCross;
60 switch (m_pNode->GetWidgetAcc()->GetCheckButtonMark()) {
61 case XFA_AttributeEnum::Check:
62 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCheck;
63 break;
64 case XFA_AttributeEnum::Circle:
65 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle;
66 break;
67 case XFA_AttributeEnum::Cross:
68 break;
69 case XFA_AttributeEnum::Diamond:
70 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeDiamond;
71 break;
72 case XFA_AttributeEnum::Square:
73 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeSquare;
74 break;
75 case XFA_AttributeEnum::Star:
76 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeStar;
77 break;
78 default: {
79 if (m_pNode->GetWidgetAcc()->IsCheckButtonRound())
80 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle;
81 } break;
82 }
83 if (m_pNode->GetWidgetAcc()->IsAllowNeutral())
84 dwStyleEx |= FWL_STYLEEXT_CKB_3State;
85
86 pCheckBox->ModifyStylesEx(
87 dwStyleEx, FWL_STYLEEXT_CKB_SignShapeMask | FWL_STYLEEXT_CKB_3State);
88 }
89
PerformLayout()90 bool CXFA_FFCheckButton::PerformLayout() {
91 CXFA_FFWidget::PerformLayout();
92
93 float fCheckSize = m_pNode->GetWidgetAcc()->GetCheckButtonSize();
94 CXFA_Margin* margin = m_pNode->GetMarginIfExists();
95 CFX_RectF rtWidget = GetRectWithoutRotate();
96 if (margin)
97 XFA_RectWithoutMargin(rtWidget, margin);
98
99 XFA_AttributeEnum iCapPlacement = XFA_AttributeEnum::Unknown;
100 float fCapReserve = 0;
101 CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
102 if (caption && caption->IsVisible()) {
103 m_rtCaption = rtWidget;
104 iCapPlacement = caption->GetPlacementType();
105 fCapReserve = caption->GetReserve();
106 if (fCapReserve <= 0) {
107 if (iCapPlacement == XFA_AttributeEnum::Top ||
108 iCapPlacement == XFA_AttributeEnum::Bottom) {
109 fCapReserve = rtWidget.height - fCheckSize;
110 } else {
111 fCapReserve = rtWidget.width - fCheckSize;
112 }
113 }
114 }
115
116 XFA_AttributeEnum iHorzAlign = XFA_AttributeEnum::Left;
117 XFA_AttributeEnum iVertAlign = XFA_AttributeEnum::Top;
118 CXFA_Para* para = m_pNode->GetParaIfExists();
119 if (para) {
120 iHorzAlign = para->GetHorizontalAlign();
121 iVertAlign = para->GetVerticalAlign();
122 }
123
124 m_rtUI = rtWidget;
125 CXFA_Margin* captionMargin = caption ? caption->GetMarginIfExists() : nullptr;
126 switch (iCapPlacement) {
127 case XFA_AttributeEnum::Left: {
128 m_rtCaption.width = fCapReserve;
129 CapLeftRightPlacement(captionMargin);
130 m_rtUI.width -= fCapReserve;
131 m_rtUI.left += fCapReserve;
132 break;
133 }
134 case XFA_AttributeEnum::Top: {
135 m_rtCaption.height = fCapReserve;
136 XFA_RectWithoutMargin(m_rtCaption, captionMargin);
137 m_rtUI.height -= fCapReserve;
138 m_rtUI.top += fCapReserve;
139 break;
140 }
141 case XFA_AttributeEnum::Right: {
142 m_rtCaption.left = m_rtCaption.right() - fCapReserve;
143 m_rtCaption.width = fCapReserve;
144 CapLeftRightPlacement(captionMargin);
145 m_rtUI.width -= fCapReserve;
146 break;
147 }
148 case XFA_AttributeEnum::Bottom: {
149 m_rtCaption.top = m_rtCaption.bottom() - fCapReserve;
150 m_rtCaption.height = fCapReserve;
151 XFA_RectWithoutMargin(m_rtCaption, captionMargin);
152 m_rtUI.height -= fCapReserve;
153 break;
154 }
155 case XFA_AttributeEnum::Inline:
156 break;
157 default:
158 iHorzAlign = XFA_AttributeEnum::Right;
159 break;
160 }
161
162 if (iHorzAlign == XFA_AttributeEnum::Center)
163 m_rtUI.left += (m_rtUI.width - fCheckSize) / 2;
164 else if (iHorzAlign == XFA_AttributeEnum::Right)
165 m_rtUI.left = m_rtUI.right() - fCheckSize;
166
167 if (iVertAlign == XFA_AttributeEnum::Middle)
168 m_rtUI.top += (m_rtUI.height - fCheckSize) / 2;
169 else if (iVertAlign == XFA_AttributeEnum::Bottom)
170 m_rtUI.top = m_rtUI.bottom() - fCheckSize;
171
172 m_rtUI.width = fCheckSize;
173 m_rtUI.height = fCheckSize;
174 AddUIMargin(iCapPlacement);
175 m_rtCheckBox = m_rtUI;
176 CXFA_Border* borderUI = m_pNode->GetWidgetAcc()->GetUIBorder();
177 if (borderUI) {
178 CXFA_Margin* borderMargin = borderUI->GetMarginIfExists();
179 if (borderMargin)
180 XFA_RectWithoutMargin(m_rtUI, borderMargin);
181 }
182
183 m_rtUI.Normalize();
184 LayoutCaption();
185 SetFWLRect();
186 if (m_pNormalWidget)
187 m_pNormalWidget->Update();
188
189 return true;
190 }
191
CapLeftRightPlacement(const CXFA_Margin * captionMargin)192 void CXFA_FFCheckButton::CapLeftRightPlacement(
193 const CXFA_Margin* captionMargin) {
194 XFA_RectWithoutMargin(m_rtCaption, captionMargin);
195 if (m_rtCaption.height < 0)
196 m_rtCaption.top += m_rtCaption.height;
197 if (m_rtCaption.width < 0) {
198 m_rtCaption.left += m_rtCaption.width;
199 m_rtCaption.width = -m_rtCaption.width;
200 }
201 }
202
AddUIMargin(XFA_AttributeEnum iCapPlacement)203 void CXFA_FFCheckButton::AddUIMargin(XFA_AttributeEnum iCapPlacement) {
204 CFX_RectF rtUIMargin = m_pNode->GetWidgetAcc()->GetUIMargin();
205 m_rtUI.top -= rtUIMargin.top / 2 - rtUIMargin.height / 2;
206
207 float fLeftAddRight = rtUIMargin.left + rtUIMargin.width;
208 float fTopAddBottom = rtUIMargin.top + rtUIMargin.height;
209 if (m_rtUI.width < fLeftAddRight) {
210 if (iCapPlacement == XFA_AttributeEnum::Right ||
211 iCapPlacement == XFA_AttributeEnum::Left) {
212 m_rtUI.left -= fLeftAddRight - m_rtUI.width;
213 } else {
214 m_rtUI.left -= 2 * (fLeftAddRight - m_rtUI.width);
215 }
216 m_rtUI.width += 2 * (fLeftAddRight - m_rtUI.width);
217 }
218 if (m_rtUI.height < fTopAddBottom) {
219 if (iCapPlacement == XFA_AttributeEnum::Right)
220 m_rtUI.left -= fTopAddBottom - m_rtUI.height;
221
222 m_rtUI.top -= fTopAddBottom - m_rtUI.height;
223 m_rtUI.height += 2 * (fTopAddBottom - m_rtUI.height);
224 }
225 }
226
RenderWidget(CXFA_Graphics * pGS,const CFX_Matrix & matrix,uint32_t dwStatus)227 void CXFA_FFCheckButton::RenderWidget(CXFA_Graphics* pGS,
228 const CFX_Matrix& matrix,
229 uint32_t dwStatus) {
230 if (!IsMatchVisibleStatus(dwStatus))
231 return;
232
233 CFX_Matrix mtRotate = GetRotateMatrix();
234 mtRotate.Concat(matrix);
235
236 CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus);
237 DrawBorderWithFlag(pGS, m_pNode->GetWidgetAcc()->GetUIBorder(), m_rtUI,
238 mtRotate, m_pNode->GetWidgetAcc()->IsCheckButtonRound());
239 RenderCaption(pGS, &mtRotate);
240 DrawHighlight(pGS, &mtRotate, dwStatus,
241 m_pNode->GetWidgetAcc()->IsCheckButtonRound());
242 CFX_Matrix mt(1, 0, 0, 1, m_rtCheckBox.left, m_rtCheckBox.top);
243 mt.Concat(mtRotate);
244 GetApp()->GetFWLWidgetMgr()->OnDrawWidget(m_pNormalWidget.get(), pGS, mt);
245 }
246
OnLButtonUp(uint32_t dwFlags,const CFX_PointF & point)247 bool CXFA_FFCheckButton::OnLButtonUp(uint32_t dwFlags,
248 const CFX_PointF& point) {
249 if (!m_pNormalWidget || !IsButtonDown())
250 return false;
251
252 SetButtonDown(false);
253 CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
254 ms.m_dwCmd = FWL_MouseCommand::LeftButtonUp;
255 ms.m_dwFlags = dwFlags;
256 ms.m_pos = FWLToClient(point);
257 TranslateFWLMessage(&ms);
258 return true;
259 }
260
FWLState2XFAState()261 XFA_CHECKSTATE CXFA_FFCheckButton::FWLState2XFAState() {
262 uint32_t dwState = m_pNormalWidget->GetStates();
263 if (dwState & FWL_STATE_CKB_Checked)
264 return XFA_CHECKSTATE_On;
265 if (dwState & FWL_STATE_CKB_Neutral)
266 return XFA_CHECKSTATE_Neutral;
267 return XFA_CHECKSTATE_Off;
268 }
269
CommitData()270 bool CXFA_FFCheckButton::CommitData() {
271 XFA_CHECKSTATE eCheckState = FWLState2XFAState();
272 m_pNode->GetWidgetAcc()->SetCheckState(eCheckState, true);
273 return true;
274 }
275
IsDataChanged()276 bool CXFA_FFCheckButton::IsDataChanged() {
277 XFA_CHECKSTATE eCheckState = FWLState2XFAState();
278 return m_pNode->GetWidgetAcc()->GetCheckState() != eCheckState;
279 }
280
SetFWLCheckState(XFA_CHECKSTATE eCheckState)281 void CXFA_FFCheckButton::SetFWLCheckState(XFA_CHECKSTATE eCheckState) {
282 if (eCheckState == XFA_CHECKSTATE_Neutral)
283 m_pNormalWidget->SetStates(FWL_STATE_CKB_Neutral);
284 else if (eCheckState == XFA_CHECKSTATE_On)
285 m_pNormalWidget->SetStates(FWL_STATE_CKB_Checked);
286 else
287 m_pNormalWidget->RemoveStates(FWL_STATE_CKB_Checked);
288 }
289
UpdateFWLData()290 bool CXFA_FFCheckButton::UpdateFWLData() {
291 if (!m_pNormalWidget)
292 return false;
293
294 XFA_CHECKSTATE eState = m_pNode->GetWidgetAcc()->GetCheckState();
295 SetFWLCheckState(eState);
296 m_pNormalWidget->Update();
297 return true;
298 }
299
OnProcessMessage(CFWL_Message * pMessage)300 void CXFA_FFCheckButton::OnProcessMessage(CFWL_Message* pMessage) {
301 m_pOldDelegate->OnProcessMessage(pMessage);
302 }
303
OnProcessEvent(CFWL_Event * pEvent)304 void CXFA_FFCheckButton::OnProcessEvent(CFWL_Event* pEvent) {
305 CXFA_FFField::OnProcessEvent(pEvent);
306 switch (pEvent->GetType()) {
307 case CFWL_Event::Type::CheckStateChanged: {
308 CXFA_EventParam eParam;
309 eParam.m_eType = XFA_EVENT_Change;
310 eParam.m_wsNewText =
311 m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
312
313 CXFA_Node* exclNode = m_pNode->GetExclGroupIfExists();
314 if (ProcessCommittedData()) {
315 eParam.m_pTarget = exclNode ? exclNode->GetWidgetAcc() : nullptr;
316 if (exclNode) {
317 m_pDocView->AddValidateWidget(exclNode->GetWidgetAcc());
318 m_pDocView->AddCalculateWidgetAcc(exclNode->GetWidgetAcc());
319 exclNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change,
320 &eParam);
321 }
322 eParam.m_pTarget = m_pNode->GetWidgetAcc();
323 m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, &eParam);
324 } else {
325 SetFWLCheckState(m_pNode->GetWidgetAcc()->GetCheckState());
326 }
327 if (exclNode) {
328 eParam.m_pTarget = exclNode->GetWidgetAcc();
329 exclNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Click, &eParam);
330 }
331 eParam.m_pTarget = m_pNode->GetWidgetAcc();
332 m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Click, &eParam);
333 break;
334 }
335 default:
336 break;
337 }
338 m_pOldDelegate->OnProcessEvent(pEvent);
339 }
340
OnDrawWidget(CXFA_Graphics * pGraphics,const CFX_Matrix & matrix)341 void CXFA_FFCheckButton::OnDrawWidget(CXFA_Graphics* pGraphics,
342 const CFX_Matrix& matrix) {
343 m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
344 }
345
GetFormFieldType()346 FormFieldType CXFA_FFCheckButton::GetFormFieldType() {
347 return FormFieldType::kXFA_CheckBox;
348 }
349