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