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 26 CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_Node* pNode) 27 : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {} 28 29 CXFA_FFCheckButton::~CXFA_FFCheckButton() {} 30 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 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 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 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 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 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 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 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 270 bool CXFA_FFCheckButton::CommitData() { 271 XFA_CHECKSTATE eCheckState = FWLState2XFAState(); 272 m_pNode->GetWidgetAcc()->SetCheckState(eCheckState, true); 273 return true; 274 } 275 276 bool CXFA_FFCheckButton::IsDataChanged() { 277 XFA_CHECKSTATE eCheckState = FWLState2XFAState(); 278 return m_pNode->GetWidgetAcc()->GetCheckState() != eCheckState; 279 } 280 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 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 300 void CXFA_FFCheckButton::OnProcessMessage(CFWL_Message* pMessage) { 301 m_pOldDelegate->OnProcessMessage(pMessage); 302 } 303 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 341 void CXFA_FFCheckButton::OnDrawWidget(CXFA_Graphics* pGraphics, 342 const CFX_Matrix& matrix) { 343 m_pOldDelegate->OnDrawWidget(pGraphics, matrix); 344 } 345 346 FormFieldType CXFA_FFCheckButton::GetFormFieldType() { 347 return FormFieldType::kXFA_CheckBox; 348 } 349