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