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