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 21 CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_WidgetAcc* pDataAcc) 22 : CXFA_FFField(pDataAcc), m_pOldDelegate(nullptr) {} 23 24 CXFA_FFCheckButton::~CXFA_FFCheckButton() {} 25 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 } 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 } 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 } 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 } 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 } 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 } 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 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 257 bool CXFA_FFCheckButton::CommitData() { 258 XFA_CHECKSTATE eCheckState = FWLState2XFAState(); 259 m_pDataAcc->SetCheckState(eCheckState, true); 260 return true; 261 } 262 263 bool CXFA_FFCheckButton::IsDataChanged() { 264 XFA_CHECKSTATE eCheckState = FWLState2XFAState(); 265 return m_pDataAcc->GetCheckState() != eCheckState; 266 } 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 } 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 287 void CXFA_FFCheckButton::OnProcessMessage(CFWL_Message* pMessage) { 288 m_pOldDelegate->OnProcessMessage(pMessage); 289 } 290 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 325 void CXFA_FFCheckButton::OnDrawWidget(CFX_Graphics* pGraphics, 326 const CFX_Matrix* pMatrix) { 327 m_pOldDelegate->OnDrawWidget(pGraphics, pMatrix); 328 } 329