Home | History | Annotate | Download | only in fxfa
      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