cfwl_pushbutton.cpp revision 4d3acf4ec42bf6e838f9060103aff98fbf170794
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/fwl/cfwl_pushbutton.h"
8
9#include <memory>
10#include <utility>
11
12#include "third_party/base/ptr_util.h"
13#include "xfa/fde/tto/fde_textout.h"
14#include "xfa/fwl/cfwl_event.h"
15#include "xfa/fwl/cfwl_eventmouse.h"
16#include "xfa/fwl/cfwl_messagekey.h"
17#include "xfa/fwl/cfwl_messagemouse.h"
18#include "xfa/fwl/cfwl_notedriver.h"
19#include "xfa/fwl/cfwl_themebackground.h"
20#include "xfa/fwl/cfwl_themetext.h"
21#include "xfa/fwl/ifwl_themeprovider.h"
22
23CFWL_PushButton::CFWL_PushButton(const CFWL_App* app)
24    : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr),
25      m_bBtnDown(false),
26      m_dwTTOStyles(FDE_TTOSTYLE_SingleLine),
27      m_iTTOAlign(FDE_TTOALIGNMENT_Center) {
28  m_rtClient.Set(0, 0, 0, 0);
29  m_rtCaption.Set(0, 0, 0, 0);
30}
31
32CFWL_PushButton::~CFWL_PushButton() {}
33
34FWL_Type CFWL_PushButton::GetClassID() const {
35  return FWL_Type::PushButton;
36}
37
38void CFWL_PushButton::SetStates(uint32_t dwStates) {
39  if (dwStates & FWL_WGTSTATE_Disabled) {
40    m_pProperties->m_dwStates = FWL_WGTSTATE_Disabled;
41    return;
42  }
43  CFWL_Widget::SetStates(dwStates);
44}
45
46void CFWL_PushButton::Update() {
47  if (IsLocked())
48    return;
49  if (!m_pProperties->m_pThemeProvider)
50    m_pProperties->m_pThemeProvider = GetAvailableTheme();
51
52  UpdateTextOutStyles();
53  m_rtClient = GetClientRect();
54  m_rtCaption = m_rtClient;
55}
56
57void CFWL_PushButton::DrawWidget(CFX_Graphics* pGraphics,
58                                 const CFX_Matrix* pMatrix) {
59  if (!pGraphics)
60    return;
61  if (!m_pProperties->m_pThemeProvider)
62    return;
63
64  if (HasBorder()) {
65    DrawBorder(pGraphics, CFWL_Part::Border, m_pProperties->m_pThemeProvider,
66               pMatrix);
67  }
68  DrawBkground(pGraphics, m_pProperties->m_pThemeProvider, pMatrix);
69}
70
71void CFWL_PushButton::DrawBkground(CFX_Graphics* pGraphics,
72                                   IFWL_ThemeProvider* pTheme,
73                                   const CFX_Matrix* pMatrix) {
74  CFWL_ThemeBackground param;
75  param.m_pWidget = this;
76  param.m_iPart = CFWL_Part::Background;
77  param.m_dwStates = GetPartStates();
78  param.m_pGraphics = pGraphics;
79  if (pMatrix)
80    param.m_matrix.Concat(*pMatrix);
81  param.m_rtPart = m_rtClient;
82  if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
83    param.m_pData = &m_rtCaption;
84  pTheme->DrawBackground(&param);
85}
86
87uint32_t CFWL_PushButton::GetPartStates() {
88  uint32_t dwStates = CFWL_PartState_Normal;
89  if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
90    dwStates |= CFWL_PartState_Focused;
91  if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
92    dwStates = CFWL_PartState_Disabled;
93  else if (m_pProperties->m_dwStates & FWL_STATE_PSB_Pressed)
94    dwStates |= CFWL_PartState_Pressed;
95  else if (m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered)
96    dwStates |= CFWL_PartState_Hovered;
97  return dwStates;
98}
99
100void CFWL_PushButton::UpdateTextOutStyles() {
101  m_iTTOAlign = FDE_TTOALIGNMENT_TopLeft;
102  m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
103}
104
105void CFWL_PushButton::OnProcessMessage(CFWL_Message* pMessage) {
106  if (!pMessage)
107    return;
108  if (!IsEnabled())
109    return;
110
111  switch (pMessage->GetType()) {
112    case CFWL_Message::Type::SetFocus:
113      OnFocusChanged(pMessage, true);
114      break;
115    case CFWL_Message::Type::KillFocus:
116      OnFocusChanged(pMessage, false);
117      break;
118    case CFWL_Message::Type::Mouse: {
119      CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
120      switch (pMsg->m_dwCmd) {
121        case FWL_MouseCommand::LeftButtonDown:
122          OnLButtonDown(pMsg);
123          break;
124        case FWL_MouseCommand::LeftButtonUp:
125          OnLButtonUp(pMsg);
126          break;
127        case FWL_MouseCommand::Move:
128          OnMouseMove(pMsg);
129          break;
130        case FWL_MouseCommand::Leave:
131          OnMouseLeave(pMsg);
132          break;
133        default:
134          break;
135      }
136      break;
137    }
138    case CFWL_Message::Type::Key: {
139      CFWL_MessageKey* pKey = static_cast<CFWL_MessageKey*>(pMessage);
140      if (pKey->m_dwCmd == FWL_KeyCommand::KeyDown)
141        OnKeyDown(pKey);
142      break;
143    }
144    default:
145      break;
146  }
147  CFWL_Widget::OnProcessMessage(pMessage);
148}
149
150void CFWL_PushButton::OnDrawWidget(CFX_Graphics* pGraphics,
151                                   const CFX_Matrix* pMatrix) {
152  DrawWidget(pGraphics, pMatrix);
153}
154
155void CFWL_PushButton::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
156  if (bSet)
157    m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
158  else
159    m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
160
161  RepaintRect(m_rtClient);
162}
163
164void CFWL_PushButton::OnLButtonDown(CFWL_MessageMouse* pMsg) {
165  if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
166    SetFocus(true);
167
168  m_bBtnDown = true;
169  m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered;
170  m_pProperties->m_dwStates |= FWL_STATE_PSB_Pressed;
171  RepaintRect(m_rtClient);
172}
173
174void CFWL_PushButton::OnLButtonUp(CFWL_MessageMouse* pMsg) {
175  m_bBtnDown = false;
176  if (m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy)) {
177    m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed;
178    m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered;
179  } else {
180    m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Hovered;
181    m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed;
182  }
183  if (m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy)) {
184    CFWL_Event wmClick(CFWL_Event::Type::Click, this);
185    DispatchEvent(&wmClick);
186  }
187  RepaintRect(m_rtClient);
188}
189
190void CFWL_PushButton::OnMouseMove(CFWL_MessageMouse* pMsg) {
191  bool bRepaint = false;
192  if (m_bBtnDown) {
193    if (m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy)) {
194      if ((m_pProperties->m_dwStates & FWL_STATE_PSB_Pressed) == 0) {
195        m_pProperties->m_dwStates |= FWL_STATE_PSB_Pressed;
196        bRepaint = true;
197      }
198      if (m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered) {
199        m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Hovered;
200        bRepaint = true;
201      }
202    } else {
203      if (m_pProperties->m_dwStates & FWL_STATE_PSB_Pressed) {
204        m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed;
205        bRepaint = true;
206      }
207      if ((m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered) == 0) {
208        m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered;
209        bRepaint = true;
210      }
211    }
212  } else {
213    if (!m_rtClient.Contains(pMsg->m_fx, pMsg->m_fy))
214      return;
215    if ((m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered) == 0) {
216      m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered;
217      bRepaint = true;
218    }
219  }
220  if (bRepaint)
221    RepaintRect(m_rtClient);
222}
223
224void CFWL_PushButton::OnMouseLeave(CFWL_MessageMouse* pMsg) {
225  m_bBtnDown = false;
226  m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Hovered;
227  m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed;
228  RepaintRect(m_rtClient);
229}
230
231void CFWL_PushButton::OnKeyDown(CFWL_MessageKey* pMsg) {
232  if (pMsg->m_dwKeyCode != FWL_VKEY_Return)
233    return;
234
235  CFWL_EventMouse wmMouse(this);
236  wmMouse.m_dwCmd = FWL_MouseCommand::LeftButtonUp;
237  DispatchEvent(&wmMouse);
238
239  CFWL_Event wmClick(CFWL_Event::Type::Click, this);
240  DispatchEvent(&wmClick);
241}
242