// Copyright 2014 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "xfa/fxfa/app/xfa_ffcheckbutton.h" #include "xfa/fwl/cfwl_checkbox.h" #include "xfa/fwl/cfwl_messagemouse.h" #include "xfa/fwl/cfwl_notedriver.h" #include "xfa/fwl/cfwl_widgetmgr.h" #include "xfa/fxfa/app/xfa_ffexclgroup.h" #include "xfa/fxfa/app/xfa_fffield.h" #include "xfa/fxfa/xfa_ffapp.h" #include "xfa/fxfa/xfa_ffdoc.h" #include "xfa/fxfa/xfa_ffdocview.h" #include "xfa/fxfa/xfa_ffpageview.h" #include "xfa/fxfa/xfa_ffwidget.h" CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc) : CXFA_FFField(pPageView, pDataAcc), m_pOldDelegate(nullptr) { m_rtCheckBox.Set(0, 0, 0, 0); } CXFA_FFCheckButton::~CXFA_FFCheckButton() {} bool CXFA_FFCheckButton::LoadWidget() { CFWL_CheckBox* pCheckBox = new CFWL_CheckBox(GetFWLApp()); m_pNormalWidget = pCheckBox; m_pNormalWidget->SetLayoutItem(this); CFWL_NoteDriver* pNoteDriver = m_pNormalWidget->GetOwnerApp()->GetNoteDriver(); pNoteDriver->RegisterEventTarget(m_pNormalWidget, m_pNormalWidget); m_pOldDelegate = m_pNormalWidget->GetDelegate(); m_pNormalWidget->SetDelegate(this); if (m_pDataAcc->IsRadioButton()) pCheckBox->ModifyStylesEx(FWL_STYLEEXT_CKB_RadioButton, 0xFFFFFFFF); m_pNormalWidget->LockUpdate(); UpdateWidgetProperty(); SetFWLCheckState(m_pDataAcc->GetCheckState()); m_pNormalWidget->UnlockUpdate(); return CXFA_FFField::LoadWidget(); } void CXFA_FFCheckButton::UpdateWidgetProperty() { CFWL_CheckBox* pCheckBox = (CFWL_CheckBox*)m_pNormalWidget; if (!m_pNormalWidget) { return; } FX_FLOAT fSize = m_pDataAcc->GetCheckButtonSize(); pCheckBox->SetBoxSize(fSize); uint32_t dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCross; int32_t iCheckMark = m_pDataAcc->GetCheckButtonMark(); switch (iCheckMark) { case XFA_ATTRIBUTEENUM_Check: dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCheck; break; case XFA_ATTRIBUTEENUM_Circle: dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle; break; case XFA_ATTRIBUTEENUM_Cross: break; case XFA_ATTRIBUTEENUM_Diamond: dwStyleEx = FWL_STYLEEXT_CKB_SignShapeDiamond; break; case XFA_ATTRIBUTEENUM_Square: dwStyleEx = FWL_STYLEEXT_CKB_SignShapeSquare; break; case XFA_ATTRIBUTEENUM_Star: dwStyleEx = FWL_STYLEEXT_CKB_SignShapeStar; break; default: { int32_t iShape = m_pDataAcc->GetCheckButtonShape(); if (iShape == XFA_ATTRIBUTEENUM_Round) { dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle; } } break; } if (m_pDataAcc->IsAllowNeutral()) { dwStyleEx |= FWL_STYLEEXT_CKB_3State; } pCheckBox->ModifyStylesEx( dwStyleEx, FWL_STYLEEXT_CKB_SignShapeMask | FWL_STYLEEXT_CKB_3State); } bool CXFA_FFCheckButton::PerformLayout() { CXFA_FFWidget::PerformLayout(); FX_FLOAT fCheckSize = m_pDataAcc->GetCheckButtonSize(); CXFA_Margin mgWidget = m_pDataAcc->GetMargin(); CFX_RectF rtWidget; GetRectWithoutRotate(rtWidget); if (mgWidget) { XFA_RectWidthoutMargin(rtWidget, mgWidget); } int32_t iCapPlacement = -1; FX_FLOAT fCapReserve = 0; CXFA_Caption caption = m_pDataAcc->GetCaption(); if (caption && caption.GetPresence()) { m_rtCaption.Set(rtWidget.left, rtWidget.top, rtWidget.width, rtWidget.height); iCapPlacement = caption.GetPlacementType(); fCapReserve = caption.GetReserve(); if (fCapReserve <= 0) { if (iCapPlacement == XFA_ATTRIBUTEENUM_Top || iCapPlacement == XFA_ATTRIBUTEENUM_Bottom) { fCapReserve = rtWidget.height - fCheckSize; } else { fCapReserve = rtWidget.width - fCheckSize; } } } int32_t iHorzAlign = XFA_ATTRIBUTEENUM_Left; int32_t iVertAlign = XFA_ATTRIBUTEENUM_Top; if (CXFA_Para para = m_pDataAcc->GetPara()) { iHorzAlign = para.GetHorizontalAlign(); iVertAlign = para.GetVerticalAlign(); } m_rtUI = rtWidget; CXFA_Margin mgCap = caption.GetMargin(); switch (iCapPlacement) { case XFA_ATTRIBUTEENUM_Left: { m_rtCaption.width = fCapReserve; CapLeftRightPlacement(mgCap); m_rtUI.width -= fCapReserve; m_rtUI.left += fCapReserve; } break; case XFA_ATTRIBUTEENUM_Top: { m_rtCaption.height = fCapReserve; XFA_RectWidthoutMargin(m_rtCaption, mgCap); m_rtUI.height -= fCapReserve; m_rtUI.top += fCapReserve; } break; case XFA_ATTRIBUTEENUM_Right: { m_rtCaption.left = m_rtCaption.right() - fCapReserve; m_rtCaption.width = fCapReserve; CapLeftRightPlacement(mgCap); m_rtUI.width -= fCapReserve; } break; case XFA_ATTRIBUTEENUM_Bottom: { m_rtCaption.top = m_rtCaption.bottom() - fCapReserve; m_rtCaption.height = fCapReserve; XFA_RectWidthoutMargin(m_rtCaption, mgCap); m_rtUI.height -= fCapReserve; } break; case XFA_ATTRIBUTEENUM_Inline: break; default: iHorzAlign = XFA_ATTRIBUTEENUM_Right; break; } if (iHorzAlign == XFA_ATTRIBUTEENUM_Center) { m_rtUI.left += (m_rtUI.width - fCheckSize) / 2; } else if (iHorzAlign == XFA_ATTRIBUTEENUM_Right) { m_rtUI.left = m_rtUI.right() - fCheckSize; } if (iVertAlign == XFA_ATTRIBUTEENUM_Middle) { m_rtUI.top += (m_rtUI.height - fCheckSize) / 2; } else if (iVertAlign == XFA_ATTRIBUTEENUM_Bottom) { m_rtUI.top = m_rtUI.bottom() - fCheckSize; } m_rtUI.width = fCheckSize; m_rtUI.height = fCheckSize; AddUIMargin(iCapPlacement); m_rtCheckBox = m_rtUI; CXFA_Border borderUI = m_pDataAcc->GetUIBorder(); if (borderUI) { CXFA_Margin margin = borderUI.GetMargin(); if (margin) { XFA_RectWidthoutMargin(m_rtUI, margin); } } m_rtUI.Normalize(); LayoutCaption(); SetFWLRect(); if (m_pNormalWidget) { m_pNormalWidget->Update(); } return true; } void CXFA_FFCheckButton::CapLeftRightPlacement(CXFA_Margin mgCap) { XFA_RectWidthoutMargin(m_rtCaption, mgCap); if (m_rtCaption.height < 0) { m_rtCaption.top += m_rtCaption.height; } if (m_rtCaption.width < 0) { m_rtCaption.left += m_rtCaption.width; m_rtCaption.width = -m_rtCaption.width; } } void CXFA_FFCheckButton::AddUIMargin(int32_t iCapPlacement) { CFX_RectF rtUIMargin = m_pDataAcc->GetUIMargin(); m_rtUI.top -= rtUIMargin.top / 2 - rtUIMargin.height / 2; FX_FLOAT fLeftAddRight = rtUIMargin.left + rtUIMargin.width; FX_FLOAT fTopAddBottom = rtUIMargin.top + rtUIMargin.height; if (m_rtUI.width < fLeftAddRight) { if (iCapPlacement == XFA_ATTRIBUTEENUM_Right || iCapPlacement == XFA_ATTRIBUTEENUM_Left) { m_rtUI.left -= fLeftAddRight - m_rtUI.width; } else { m_rtUI.left -= 2 * (fLeftAddRight - m_rtUI.width); } m_rtUI.width += 2 * (fLeftAddRight - m_rtUI.width); } if (m_rtUI.height < fTopAddBottom) { if (iCapPlacement == XFA_ATTRIBUTEENUM_Right) { m_rtUI.left -= fTopAddBottom - m_rtUI.height; } m_rtUI.top -= fTopAddBottom - m_rtUI.height; m_rtUI.height += 2 * (fTopAddBottom - m_rtUI.height); } } void CXFA_FFCheckButton::RenderWidget(CFX_Graphics* pGS, CFX_Matrix* pMatrix, uint32_t dwStatus) { if (!IsMatchVisibleStatus(dwStatus)) { return; } CFX_Matrix mtRotate; GetRotateMatrix(mtRotate); if (pMatrix) { mtRotate.Concat(*pMatrix); } CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus); CXFA_Border borderUI = m_pDataAcc->GetUIBorder(); DrawBorder(pGS, borderUI, m_rtUI, &mtRotate, m_pDataAcc->GetCheckButtonShape() == XFA_ATTRIBUTEENUM_Round ? XFA_DRAWBOX_ForceRound : 0); RenderCaption(pGS, &mtRotate); DrawHighlight(pGS, &mtRotate, dwStatus, m_pDataAcc->GetCheckButtonShape() == XFA_ATTRIBUTEENUM_Round); CFX_Matrix mt; mt.Set(1, 0, 0, 1, m_rtCheckBox.left, m_rtCheckBox.top); mt.Concat(mtRotate); GetApp()->GetWidgetMgrDelegate()->OnDrawWidget(m_pNormalWidget, pGS, &mt); } bool CXFA_FFCheckButton::OnLButtonUp(uint32_t dwFlags, FX_FLOAT fx, FX_FLOAT fy) { if (!m_pNormalWidget || !IsButtonDown()) return false; SetButtonDown(false); CFWL_MessageMouse ms(nullptr, m_pNormalWidget); ms.m_dwCmd = FWL_MouseCommand::LeftButtonUp; ms.m_dwFlags = dwFlags; ms.m_fx = fx; ms.m_fy = fy; FWLToClient(ms.m_fx, ms.m_fy); TranslateFWLMessage(&ms); return true; } XFA_CHECKSTATE CXFA_FFCheckButton::FWLState2XFAState() { uint32_t dwState = m_pNormalWidget->GetStates(); if (dwState & FWL_STATE_CKB_Checked) return XFA_CHECKSTATE_On; if (dwState & FWL_STATE_CKB_Neutral) return XFA_CHECKSTATE_Neutral; return XFA_CHECKSTATE_Off; } bool CXFA_FFCheckButton::CommitData() { XFA_CHECKSTATE eCheckState = FWLState2XFAState(); m_pDataAcc->SetCheckState(eCheckState, true); return true; } bool CXFA_FFCheckButton::IsDataChanged() { XFA_CHECKSTATE eCheckState = FWLState2XFAState(); return m_pDataAcc->GetCheckState() != eCheckState; } void CXFA_FFCheckButton::SetFWLCheckState(XFA_CHECKSTATE eCheckState) { if (eCheckState == XFA_CHECKSTATE_Neutral) { m_pNormalWidget->SetStates(FWL_STATE_CKB_Neutral); } else { if (eCheckState == XFA_CHECKSTATE_On) m_pNormalWidget->SetStates(FWL_STATE_CKB_Checked); else m_pNormalWidget->RemoveStates(FWL_STATE_CKB_Checked); } } bool CXFA_FFCheckButton::UpdateFWLData() { if (!m_pNormalWidget) { return false; } XFA_CHECKSTATE eState = m_pDataAcc->GetCheckState(); SetFWLCheckState(eState); m_pNormalWidget->Update(); return true; } void CXFA_FFCheckButton::OnProcessMessage(CFWL_Message* pMessage) { m_pOldDelegate->OnProcessMessage(pMessage); } void CXFA_FFCheckButton::OnProcessEvent(CFWL_Event* pEvent) { CXFA_FFField::OnProcessEvent(pEvent); switch (pEvent->GetType()) { case CFWL_Event::Type::CheckStateChanged: { CXFA_EventParam eParam; eParam.m_eType = XFA_EVENT_Change; m_pDataAcc->GetValue(eParam.m_wsNewText, XFA_VALUEPICTURE_Raw); CXFA_WidgetAcc* pFFExclGroup = m_pDataAcc->GetExclGroup(); if (ProcessCommittedData()) { eParam.m_pTarget = pFFExclGroup; if (pFFExclGroup) { m_pDocView->AddValidateWidget(pFFExclGroup); m_pDocView->AddCalculateWidgetAcc(pFFExclGroup); pFFExclGroup->ProcessEvent(XFA_ATTRIBUTEENUM_Change, &eParam); } eParam.m_pTarget = m_pDataAcc; m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Change, &eParam); } else { SetFWLCheckState(m_pDataAcc->GetCheckState()); } if (pFFExclGroup) { eParam.m_pTarget = pFFExclGroup; pFFExclGroup->ProcessEvent(XFA_ATTRIBUTEENUM_Click, &eParam); } eParam.m_pTarget = m_pDataAcc; m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Click, &eParam); break; } default: break; } m_pOldDelegate->OnProcessEvent(pEvent); } void CXFA_FFCheckButton::OnDrawWidget(CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix) { m_pOldDelegate->OnDrawWidget(pGraphics, pMatrix); }