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/fwl_widgetdef.h"
22 #include "xfa/fwl/ifwl_themeprovider.h"
23
CFWL_PushButton(const CFWL_App * app)24 CFWL_PushButton::CFWL_PushButton(const CFWL_App* app)
25 : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr) {}
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
56 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider.Get();
57 if (!pTheme)
58 return;
59
60 if (HasBorder())
61 DrawBorder(pGraphics, CFWL_Part::Border, pTheme, matrix);
62 DrawBkground(pGraphics, pTheme, &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_pRtData = &m_rtCaption;
78 pTheme->DrawBackground(param);
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 // Dst target could be |this|, continue only if not destroyed by above.
137 if (pMessage->GetDstTarget())
138 CFWL_Widget::OnProcessMessage(pMessage);
139 }
140
OnDrawWidget(CXFA_Graphics * pGraphics,const CFX_Matrix & matrix)141 void CFWL_PushButton::OnDrawWidget(CXFA_Graphics* pGraphics,
142 const CFX_Matrix& matrix) {
143 DrawWidget(pGraphics, matrix);
144 }
145
OnFocusChanged(CFWL_Message * pMsg,bool bSet)146 void CFWL_PushButton::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
147 if (bSet)
148 m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
149 else
150 m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
151
152 RepaintRect(m_rtClient);
153 }
154
OnLButtonDown(CFWL_MessageMouse * pMsg)155 void CFWL_PushButton::OnLButtonDown(CFWL_MessageMouse* pMsg) {
156 m_bBtnDown = true;
157 m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered;
158 m_pProperties->m_dwStates |= FWL_STATE_PSB_Pressed;
159 RepaintRect(m_rtClient);
160 }
161
OnLButtonUp(CFWL_MessageMouse * pMsg)162 void CFWL_PushButton::OnLButtonUp(CFWL_MessageMouse* pMsg) {
163 m_bBtnDown = false;
164 if (m_rtClient.Contains(pMsg->m_pos)) {
165 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed;
166 m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered;
167 } else {
168 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Hovered;
169 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed;
170 }
171 if (m_rtClient.Contains(pMsg->m_pos)) {
172 CFWL_Event wmClick(CFWL_Event::Type::Click, this);
173 DispatchEvent(&wmClick);
174 }
175 RepaintRect(m_rtClient);
176 }
177
OnMouseMove(CFWL_MessageMouse * pMsg)178 void CFWL_PushButton::OnMouseMove(CFWL_MessageMouse* pMsg) {
179 bool bRepaint = false;
180 if (m_bBtnDown) {
181 if (m_rtClient.Contains(pMsg->m_pos)) {
182 if ((m_pProperties->m_dwStates & FWL_STATE_PSB_Pressed) == 0) {
183 m_pProperties->m_dwStates |= FWL_STATE_PSB_Pressed;
184 bRepaint = true;
185 }
186 if (m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered) {
187 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Hovered;
188 bRepaint = true;
189 }
190 } else {
191 if (m_pProperties->m_dwStates & FWL_STATE_PSB_Pressed) {
192 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed;
193 bRepaint = true;
194 }
195 if ((m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered) == 0) {
196 m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered;
197 bRepaint = true;
198 }
199 }
200 } else {
201 if (!m_rtClient.Contains(pMsg->m_pos))
202 return;
203 if ((m_pProperties->m_dwStates & FWL_STATE_PSB_Hovered) == 0) {
204 m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered;
205 bRepaint = true;
206 }
207 }
208 if (bRepaint)
209 RepaintRect(m_rtClient);
210 }
211
OnMouseLeave(CFWL_MessageMouse * pMsg)212 void CFWL_PushButton::OnMouseLeave(CFWL_MessageMouse* pMsg) {
213 m_bBtnDown = false;
214 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Hovered;
215 m_pProperties->m_dwStates &= ~FWL_STATE_PSB_Pressed;
216 RepaintRect(m_rtClient);
217 }
218
OnKeyDown(CFWL_MessageKey * pMsg)219 void CFWL_PushButton::OnKeyDown(CFWL_MessageKey* pMsg) {
220 if (pMsg->m_dwKeyCode != XFA_FWL_VKEY_Return)
221 return;
222
223 CFWL_EventMouse wmMouse(this);
224 wmMouse.m_dwCmd = FWL_MouseCommand::LeftButtonUp;
225 DispatchEvent(&wmMouse);
226 if (!wmMouse.GetSrcTarget())
227 return;
228
229 CFWL_Event wmClick(CFWL_Event::Type::Click, this);
230 DispatchEvent(&wmClick);
231 }
232