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_ffpushbutton.h"
8
9#include "xfa/fwl/cfwl_notedriver.h"
10#include "xfa/fwl/cfwl_pushbutton.h"
11#include "xfa/fwl/cfwl_widgetmgr.h"
12#include "xfa/fxfa/app/cxfa_textlayout.h"
13#include "xfa/fxfa/app/xfa_fffield.h"
14#include "xfa/fxfa/app/xfa_ffwidgetacc.h"
15#include "xfa/fxfa/xfa_ffapp.h"
16#include "xfa/fxfa/xfa_ffpageview.h"
17#include "xfa/fxfa/xfa_ffwidget.h"
18#include "xfa/fxgraphics/cfx_color.h"
19#include "xfa/fxgraphics/cfx_path.h"
20
21CXFA_FFPushButton::CXFA_FFPushButton(CXFA_WidgetAcc* pDataAcc)
22    : CXFA_FFField(pDataAcc),
23      m_pRolloverTextLayout(nullptr),
24      m_pDownTextLayout(nullptr),
25      m_pDownProvider(nullptr),
26      m_pRollProvider(nullptr),
27      m_pOldDelegate(nullptr) {}
28
29CXFA_FFPushButton::~CXFA_FFPushButton() {
30  CXFA_FFPushButton::UnloadWidget();
31}
32
33void CXFA_FFPushButton::RenderWidget(CFX_Graphics* pGS,
34                                     CFX_Matrix* pMatrix,
35                                     uint32_t dwStatus) {
36  if (!IsMatchVisibleStatus(dwStatus))
37    return;
38
39  CFX_Matrix mtRotate = GetRotateMatrix();
40  if (pMatrix)
41    mtRotate.Concat(*pMatrix);
42
43  CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
44  RenderHighlightCaption(pGS, &mtRotate);
45
46  CFX_RectF rtWidget = GetRectWithoutRotate();
47  CFX_Matrix mt(1, 0, 0, 1, rtWidget.left, rtWidget.top);
48  mt.Concat(mtRotate);
49  GetApp()->GetWidgetMgrDelegate()->OnDrawWidget(m_pNormalWidget, pGS, &mt);
50}
51
52bool CXFA_FFPushButton::LoadWidget() {
53  ASSERT(!m_pNormalWidget);
54  CFWL_PushButton* pPushButton = new CFWL_PushButton(GetFWLApp());
55  m_pOldDelegate = pPushButton->GetDelegate();
56  pPushButton->SetDelegate(this);
57
58  m_pNormalWidget = pPushButton;
59  m_pNormalWidget->SetLayoutItem(this);
60
61  CFWL_NoteDriver* pNoteDriver =
62      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
63  pNoteDriver->RegisterEventTarget(m_pNormalWidget, m_pNormalWidget);
64  m_pNormalWidget->LockUpdate();
65  UpdateWidgetProperty();
66  LoadHighlightCaption();
67  m_pNormalWidget->UnlockUpdate();
68  return CXFA_FFField::LoadWidget();
69}
70void CXFA_FFPushButton::UpdateWidgetProperty() {
71  uint32_t dwStyleEx = 0;
72  switch (m_pDataAcc->GetButtonHighlight()) {
73    case XFA_ATTRIBUTEENUM_Inverted:
74      dwStyleEx = XFA_FWL_PSBSTYLEEXT_HiliteInverted;
75      break;
76    case XFA_ATTRIBUTEENUM_Outline:
77      dwStyleEx = XFA_FWL_PSBSTYLEEXT_HiliteOutLine;
78      break;
79    case XFA_ATTRIBUTEENUM_Push:
80      dwStyleEx = XFA_FWL_PSBSTYLEEXT_HilitePush;
81      break;
82    default:
83      break;
84  }
85  m_pNormalWidget->ModifyStylesEx(dwStyleEx, 0xFFFFFFFF);
86}
87
88void CXFA_FFPushButton::UnloadWidget() {
89  delete m_pRolloverTextLayout;
90  m_pRolloverTextLayout = nullptr;
91  delete m_pDownTextLayout;
92  m_pDownTextLayout = nullptr;
93  delete m_pDownProvider;
94  m_pDownProvider = nullptr;
95  delete m_pRollProvider;
96  m_pRollProvider = nullptr;
97  CXFA_FFField::UnloadWidget();
98}
99
100bool CXFA_FFPushButton::PerformLayout() {
101  CXFA_FFWidget::PerformLayout();
102  CFX_RectF rtWidget = GetRectWithoutRotate();
103
104  m_rtUI = rtWidget;
105  if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin())
106    XFA_RectWidthoutMargin(rtWidget, mgWidget);
107
108  CXFA_Caption caption = m_pDataAcc->GetCaption();
109  m_rtCaption = rtWidget;
110  if (CXFA_Margin mgCap = caption.GetMargin())
111    XFA_RectWidthoutMargin(m_rtCaption, mgCap);
112
113  LayoutHighlightCaption();
114  SetFWLRect();
115  if (m_pNormalWidget)
116    m_pNormalWidget->Update();
117
118  return true;
119}
120FX_FLOAT CXFA_FFPushButton::GetLineWidth() {
121  CXFA_Border border = m_pDataAcc->GetBorder();
122  if (border && border.GetPresence() == XFA_ATTRIBUTEENUM_Visible) {
123    CXFA_Edge edge = border.GetEdge(0);
124    return edge.GetThickness();
125  }
126  return 0;
127}
128FX_ARGB CXFA_FFPushButton::GetLineColor() {
129  return 0xFF000000;
130}
131FX_ARGB CXFA_FFPushButton::GetFillColor() {
132  return 0xFFFFFFFF;
133}
134void CXFA_FFPushButton::LoadHighlightCaption() {
135  CXFA_Caption caption = m_pDataAcc->GetCaption();
136  if (caption && caption.GetPresence() != XFA_ATTRIBUTEENUM_Hidden) {
137    {
138      CFX_WideString wsRollover;
139      bool bRichText;
140      if (m_pDataAcc->GetButtonRollover(wsRollover, bRichText)) {
141        if (!m_pRollProvider) {
142          m_pRollProvider =
143              new CXFA_TextProvider(m_pDataAcc, XFA_TEXTPROVIDERTYPE_Rollover);
144        }
145        m_pRolloverTextLayout = new CXFA_TextLayout(m_pRollProvider);
146      }
147      CFX_WideString wsDown;
148      if (m_pDataAcc->GetButtonDown(wsDown, bRichText)) {
149        if (!m_pDownProvider) {
150          m_pDownProvider =
151              new CXFA_TextProvider(m_pDataAcc, XFA_TEXTPROVIDERTYPE_Down);
152        }
153        m_pDownTextLayout = new CXFA_TextLayout(m_pDownProvider);
154      }
155    }
156  }
157}
158void CXFA_FFPushButton::LayoutHighlightCaption() {
159  CFX_SizeF sz(m_rtCaption.width, m_rtCaption.height);
160  LayoutCaption();
161  if (m_pRolloverTextLayout) {
162    m_pRolloverTextLayout->Layout(sz);
163  }
164  if (m_pDownTextLayout) {
165    m_pDownTextLayout->Layout(sz);
166  }
167}
168void CXFA_FFPushButton::RenderHighlightCaption(CFX_Graphics* pGS,
169                                               CFX_Matrix* pMatrix) {
170  CXFA_TextLayout* pCapTextLayout = m_pDataAcc->GetCaptionTextLayout();
171  CXFA_Caption caption = m_pDataAcc->GetCaption();
172  if (!caption || caption.GetPresence() != XFA_ATTRIBUTEENUM_Visible)
173    return;
174
175  CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
176  CFX_RectF rtClip = m_rtCaption;
177  rtClip.Intersect(GetRectWithoutRotate());
178  CFX_Matrix mt(1, 0, 0, 1, m_rtCaption.left, m_rtCaption.top);
179  if (pMatrix) {
180    pMatrix->TransformRect(rtClip);
181    mt.Concat(*pMatrix);
182  }
183
184  uint32_t dwState = m_pNormalWidget->GetStates();
185  if (m_pDownTextLayout && (dwState & FWL_STATE_PSB_Pressed) &&
186      (dwState & FWL_STATE_PSB_Hovered)) {
187    if (m_pDownTextLayout->DrawString(pRenderDevice, mt, rtClip))
188      return;
189  } else if (m_pRolloverTextLayout && (dwState & FWL_STATE_PSB_Hovered)) {
190    if (m_pRolloverTextLayout->DrawString(pRenderDevice, mt, rtClip))
191      return;
192  }
193
194  if (pCapTextLayout)
195    pCapTextLayout->DrawString(pRenderDevice, mt, rtClip);
196}
197
198void CXFA_FFPushButton::OnProcessMessage(CFWL_Message* pMessage) {
199  m_pOldDelegate->OnProcessMessage(pMessage);
200}
201
202void CXFA_FFPushButton::OnProcessEvent(CFWL_Event* pEvent) {
203  m_pOldDelegate->OnProcessEvent(pEvent);
204  CXFA_FFField::OnProcessEvent(pEvent);
205}
206
207void CXFA_FFPushButton::OnDrawWidget(CFX_Graphics* pGraphics,
208                                     const CFX_Matrix* pMatrix) {
209  if (m_pNormalWidget->GetStylesEx() & XFA_FWL_PSBSTYLEEXT_HiliteInverted) {
210    if ((m_pNormalWidget->GetStates() & FWL_STATE_PSB_Pressed) &&
211        (m_pNormalWidget->GetStates() & FWL_STATE_PSB_Hovered)) {
212      CFX_RectF rtFill(0, 0, m_pNormalWidget->GetWidgetRect().Size());
213      FX_FLOAT fLineWith = GetLineWidth();
214      rtFill.Deflate(fLineWith, fLineWith);
215      CFX_Color cr(FXARGB_MAKE(128, 128, 255, 255));
216      pGraphics->SetFillColor(&cr);
217
218      CFX_Path path;
219      path.AddRectangle(rtFill.left, rtFill.top, rtFill.width, rtFill.height);
220      pGraphics->FillPath(&path, FXFILL_WINDING, (CFX_Matrix*)pMatrix);
221    }
222  } else if (m_pNormalWidget->GetStylesEx() &
223             XFA_FWL_PSBSTYLEEXT_HiliteOutLine) {
224    if ((m_pNormalWidget->GetStates() & FWL_STATE_PSB_Pressed) &&
225        (m_pNormalWidget->GetStates() & FWL_STATE_PSB_Hovered)) {
226      FX_FLOAT fLineWidth = GetLineWidth();
227      CFX_Color cr(FXARGB_MAKE(255, 128, 255, 255));
228      pGraphics->SetStrokeColor(&cr);
229      pGraphics->SetLineWidth(fLineWidth);
230
231      CFX_Path path;
232      CFX_RectF rect = m_pNormalWidget->GetWidgetRect();
233      path.AddRectangle(0, 0, rect.width, rect.height);
234      pGraphics->StrokePath(&path, (CFX_Matrix*)pMatrix);
235    }
236  }
237}
238