OLD | NEW |
| (Empty) |
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/core/cfwl_spinbutton.h" | |
8 | |
9 #include <memory> | |
10 #include <utility> | |
11 | |
12 #include "third_party/base/ptr_util.h" | |
13 #include "xfa/fwl/core/cfwl_event.h" | |
14 #include "xfa/fwl/core/cfwl_msgkey.h" | |
15 #include "xfa/fwl/core/cfwl_msgmouse.h" | |
16 #include "xfa/fwl/core/cfwl_notedriver.h" | |
17 #include "xfa/fwl/core/cfwl_themebackground.h" | |
18 #include "xfa/fwl/core/cfwl_timerinfo.h" | |
19 #include "xfa/fwl/core/cfwl_widgetproperties.h" | |
20 #include "xfa/fwl/core/ifwl_themeprovider.h" | |
21 | |
22 namespace { | |
23 const int kElapseTime = 200; | |
24 | |
25 } // namespace | |
26 | |
27 CFWL_SpinButton::CFWL_SpinButton( | |
28 const CFWL_App* app, | |
29 std::unique_ptr<CFWL_WidgetProperties> properties) | |
30 : CFWL_Widget(app, std::move(properties), nullptr), | |
31 m_dwUpState(CFWL_PartState_Normal), | |
32 m_dwDnState(CFWL_PartState_Normal), | |
33 m_iButtonIndex(0), | |
34 m_bLButtonDwn(false), | |
35 m_pTimerInfo(nullptr), | |
36 m_Timer(this) { | |
37 m_rtClient.Reset(); | |
38 m_rtUpButton.Reset(); | |
39 m_rtDnButton.Reset(); | |
40 m_pProperties->m_dwStyleExes |= FWL_STYLEEXE_SPB_Vert; | |
41 } | |
42 | |
43 CFWL_SpinButton::~CFWL_SpinButton() {} | |
44 | |
45 FWL_Type CFWL_SpinButton::GetClassID() const { | |
46 return FWL_Type::SpinButton; | |
47 } | |
48 | |
49 void CFWL_SpinButton::Update() { | |
50 if (IsLocked()) | |
51 return; | |
52 | |
53 GetClientRect(m_rtClient); | |
54 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXE_SPB_Vert) { | |
55 m_rtUpButton.Set(m_rtClient.top, m_rtClient.left, m_rtClient.width, | |
56 m_rtClient.height / 2); | |
57 m_rtDnButton.Set(m_rtClient.left, m_rtClient.top + m_rtClient.height / 2, | |
58 m_rtClient.width, m_rtClient.height / 2); | |
59 } else { | |
60 m_rtUpButton.Set(m_rtClient.left, m_rtClient.top, m_rtClient.width / 2, | |
61 m_rtClient.height); | |
62 m_rtDnButton.Set(m_rtClient.left + m_rtClient.width / 2, m_rtClient.top, | |
63 m_rtClient.width / 2, m_rtClient.height); | |
64 } | |
65 } | |
66 | |
67 FWL_WidgetHit CFWL_SpinButton::HitTest(FX_FLOAT fx, FX_FLOAT fy) { | |
68 if (m_rtClient.Contains(fx, fy)) | |
69 return FWL_WidgetHit::Client; | |
70 if (HasBorder() && (m_rtClient.Contains(fx, fy))) | |
71 return FWL_WidgetHit::Border; | |
72 if (HasEdge()) { | |
73 CFX_RectF rtEdge; | |
74 GetEdgeRect(rtEdge); | |
75 if (rtEdge.Contains(fx, fy)) | |
76 return FWL_WidgetHit::Left; | |
77 } | |
78 if (m_rtUpButton.Contains(fx, fy)) | |
79 return FWL_WidgetHit::UpButton; | |
80 if (m_rtDnButton.Contains(fx, fy)) | |
81 return FWL_WidgetHit::DownButton; | |
82 return FWL_WidgetHit::Unknown; | |
83 } | |
84 | |
85 void CFWL_SpinButton::DrawWidget(CFX_Graphics* pGraphics, | |
86 const CFX_Matrix* pMatrix) { | |
87 if (!pGraphics) | |
88 return; | |
89 | |
90 CFX_RectF rtClip(m_rtClient); | |
91 if (pMatrix) | |
92 pMatrix->TransformRect(rtClip); | |
93 | |
94 IFWL_ThemeProvider* pTheme = GetAvailableTheme(); | |
95 if (HasBorder()) | |
96 DrawBorder(pGraphics, CFWL_Part::Border, pTheme, pMatrix); | |
97 if (HasEdge()) | |
98 DrawEdge(pGraphics, CFWL_Part::Edge, pTheme, pMatrix); | |
99 | |
100 DrawUpButton(pGraphics, pTheme, pMatrix); | |
101 DrawDownButton(pGraphics, pTheme, pMatrix); | |
102 } | |
103 | |
104 void CFWL_SpinButton::DisableButton() { | |
105 m_dwDnState = CFWL_PartState_Disabled; | |
106 } | |
107 | |
108 bool CFWL_SpinButton::IsUpButtonEnabled() { | |
109 return m_dwUpState != CFWL_PartState_Disabled; | |
110 } | |
111 | |
112 bool CFWL_SpinButton::IsDownButtonEnabled() { | |
113 return m_dwDnState != CFWL_PartState_Disabled; | |
114 } | |
115 | |
116 void CFWL_SpinButton::DrawUpButton(CFX_Graphics* pGraphics, | |
117 IFWL_ThemeProvider* pTheme, | |
118 const CFX_Matrix* pMatrix) { | |
119 CFWL_ThemeBackground params; | |
120 params.m_pWidget = this; | |
121 params.m_iPart = CFWL_Part::UpButton; | |
122 params.m_pGraphics = pGraphics; | |
123 params.m_dwStates = m_dwUpState + 1; | |
124 if (pMatrix) | |
125 params.m_matrix.Concat(*pMatrix); | |
126 | |
127 params.m_rtPart = m_rtUpButton; | |
128 pTheme->DrawBackground(¶ms); | |
129 } | |
130 | |
131 void CFWL_SpinButton::DrawDownButton(CFX_Graphics* pGraphics, | |
132 IFWL_ThemeProvider* pTheme, | |
133 const CFX_Matrix* pMatrix) { | |
134 CFWL_ThemeBackground params; | |
135 params.m_pWidget = this; | |
136 params.m_iPart = CFWL_Part::DownButton; | |
137 params.m_pGraphics = pGraphics; | |
138 params.m_dwStates = m_dwDnState + 1; | |
139 if (pMatrix) | |
140 params.m_matrix.Concat(*pMatrix); | |
141 | |
142 params.m_rtPart = m_rtDnButton; | |
143 pTheme->DrawBackground(¶ms); | |
144 } | |
145 | |
146 void CFWL_SpinButton::OnProcessMessage(CFWL_Message* pMessage) { | |
147 if (!pMessage) | |
148 return; | |
149 | |
150 switch (pMessage->GetType()) { | |
151 case CFWL_Message::Type::SetFocus: { | |
152 OnFocusChanged(pMessage, true); | |
153 break; | |
154 } | |
155 case CFWL_Message::Type::KillFocus: { | |
156 OnFocusChanged(pMessage, false); | |
157 break; | |
158 } | |
159 case CFWL_Message::Type::Mouse: { | |
160 CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage); | |
161 switch (pMsg->m_dwCmd) { | |
162 case FWL_MouseCommand::LeftButtonDown: | |
163 OnLButtonDown(pMsg); | |
164 break; | |
165 case FWL_MouseCommand::LeftButtonUp: | |
166 OnLButtonUp(pMsg); | |
167 break; | |
168 case FWL_MouseCommand::Move: | |
169 OnMouseMove(pMsg); | |
170 break; | |
171 case FWL_MouseCommand::Leave: | |
172 OnMouseLeave(pMsg); | |
173 break; | |
174 default: | |
175 break; | |
176 } | |
177 break; | |
178 } | |
179 case CFWL_Message::Type::Key: { | |
180 CFWL_MsgKey* pKey = static_cast<CFWL_MsgKey*>(pMessage); | |
181 if (pKey->m_dwCmd == FWL_KeyCommand::KeyDown) | |
182 OnKeyDown(pKey); | |
183 break; | |
184 } | |
185 default: | |
186 break; | |
187 } | |
188 CFWL_Widget::OnProcessMessage(pMessage); | |
189 } | |
190 | |
191 void CFWL_SpinButton::OnDrawWidget(CFX_Graphics* pGraphics, | |
192 const CFX_Matrix* pMatrix) { | |
193 DrawWidget(pGraphics, pMatrix); | |
194 } | |
195 | |
196 void CFWL_SpinButton::OnFocusChanged(CFWL_Message* pMsg, bool bSet) { | |
197 if (bSet) | |
198 m_pProperties->m_dwStates |= (FWL_WGTSTATE_Focused); | |
199 else | |
200 m_pProperties->m_dwStates &= ~(FWL_WGTSTATE_Focused); | |
201 | |
202 Repaint(&m_rtClient); | |
203 } | |
204 | |
205 void CFWL_SpinButton::OnLButtonDown(CFWL_MsgMouse* pMsg) { | |
206 m_bLButtonDwn = true; | |
207 SetGrab(true); | |
208 SetFocus(true); | |
209 | |
210 bool bUpPress = | |
211 (m_rtUpButton.Contains(pMsg->m_fx, pMsg->m_fy) && IsUpButtonEnabled()); | |
212 bool bDnPress = | |
213 (m_rtDnButton.Contains(pMsg->m_fx, pMsg->m_fy) && IsDownButtonEnabled()); | |
214 if (!bUpPress && !bDnPress) | |
215 return; | |
216 if (bUpPress) { | |
217 m_iButtonIndex = 0; | |
218 m_dwUpState = CFWL_PartState_Pressed; | |
219 } | |
220 if (bDnPress) { | |
221 m_iButtonIndex = 1; | |
222 m_dwDnState = CFWL_PartState_Pressed; | |
223 } | |
224 | |
225 CFWL_Event wmPosChanged(CFWL_Event::Type::Click, this); | |
226 DispatchEvent(&wmPosChanged); | |
227 | |
228 Repaint(bUpPress ? &m_rtUpButton : &m_rtDnButton); | |
229 m_pTimerInfo = m_Timer.StartTimer(kElapseTime, true); | |
230 } | |
231 | |
232 void CFWL_SpinButton::OnLButtonUp(CFWL_MsgMouse* pMsg) { | |
233 if (m_pProperties->m_dwStates & CFWL_PartState_Disabled) | |
234 return; | |
235 | |
236 m_bLButtonDwn = false; | |
237 SetGrab(false); | |
238 SetFocus(false); | |
239 if (m_pTimerInfo) { | |
240 m_pTimerInfo->StopTimer(); | |
241 m_pTimerInfo = nullptr; | |
242 } | |
243 bool bRepaint = false; | |
244 CFX_RectF rtInvalidate; | |
245 if (m_dwUpState == CFWL_PartState_Pressed && IsUpButtonEnabled()) { | |
246 m_dwUpState = CFWL_PartState_Normal; | |
247 bRepaint = true; | |
248 rtInvalidate = m_rtUpButton; | |
249 } else if (m_dwDnState == CFWL_PartState_Pressed && IsDownButtonEnabled()) { | |
250 m_dwDnState = CFWL_PartState_Normal; | |
251 bRepaint = true; | |
252 rtInvalidate = m_rtDnButton; | |
253 } | |
254 if (bRepaint) | |
255 Repaint(&rtInvalidate); | |
256 } | |
257 | |
258 void CFWL_SpinButton::OnMouseMove(CFWL_MsgMouse* pMsg) { | |
259 if (m_bLButtonDwn) | |
260 return; | |
261 | |
262 bool bRepaint = false; | |
263 CFX_RectF rtInvlidate; | |
264 rtInvlidate.Reset(); | |
265 if (m_rtUpButton.Contains(pMsg->m_fx, pMsg->m_fy)) { | |
266 if (IsUpButtonEnabled()) { | |
267 if (m_dwUpState == CFWL_PartState_Hovered) { | |
268 m_dwUpState = CFWL_PartState_Hovered; | |
269 bRepaint = true; | |
270 rtInvlidate = m_rtUpButton; | |
271 } | |
272 if (m_dwDnState != CFWL_PartState_Normal && IsDownButtonEnabled()) { | |
273 m_dwDnState = CFWL_PartState_Normal; | |
274 if (bRepaint) | |
275 rtInvlidate.Union(m_rtDnButton); | |
276 else | |
277 rtInvlidate = m_rtDnButton; | |
278 | |
279 bRepaint = true; | |
280 } | |
281 } | |
282 if (!IsDownButtonEnabled()) | |
283 DisableButton(); | |
284 | |
285 } else if (m_rtDnButton.Contains(pMsg->m_fx, pMsg->m_fy)) { | |
286 if (IsDownButtonEnabled()) { | |
287 if (m_dwDnState != CFWL_PartState_Hovered) { | |
288 m_dwDnState = CFWL_PartState_Hovered; | |
289 bRepaint = true; | |
290 rtInvlidate = m_rtDnButton; | |
291 } | |
292 if (m_dwUpState != CFWL_PartState_Normal && IsUpButtonEnabled()) { | |
293 m_dwUpState = CFWL_PartState_Normal; | |
294 if (bRepaint) | |
295 rtInvlidate.Union(m_rtUpButton); | |
296 else | |
297 rtInvlidate = m_rtUpButton; | |
298 bRepaint = true; | |
299 } | |
300 } | |
301 } else if (m_dwUpState != CFWL_PartState_Normal || | |
302 m_dwDnState != CFWL_PartState_Normal) { | |
303 if (m_dwUpState != CFWL_PartState_Normal) { | |
304 m_dwUpState = CFWL_PartState_Normal; | |
305 bRepaint = true; | |
306 rtInvlidate = m_rtUpButton; | |
307 } | |
308 if (m_dwDnState != CFWL_PartState_Normal) { | |
309 m_dwDnState = CFWL_PartState_Normal; | |
310 if (bRepaint) | |
311 rtInvlidate.Union(m_rtDnButton); | |
312 else | |
313 rtInvlidate = m_rtDnButton; | |
314 | |
315 bRepaint = true; | |
316 } | |
317 } | |
318 if (bRepaint) | |
319 Repaint(&rtInvlidate); | |
320 } | |
321 | |
322 void CFWL_SpinButton::OnMouseLeave(CFWL_MsgMouse* pMsg) { | |
323 if (!pMsg) | |
324 return; | |
325 if (m_dwUpState != CFWL_PartState_Normal && IsUpButtonEnabled()) | |
326 m_dwUpState = CFWL_PartState_Normal; | |
327 if (m_dwDnState != CFWL_PartState_Normal && IsDownButtonEnabled()) | |
328 m_dwDnState = CFWL_PartState_Normal; | |
329 | |
330 Repaint(&m_rtClient); | |
331 } | |
332 | |
333 void CFWL_SpinButton::OnKeyDown(CFWL_MsgKey* pMsg) { | |
334 bool bUp = | |
335 pMsg->m_dwKeyCode == FWL_VKEY_Up || pMsg->m_dwKeyCode == FWL_VKEY_Left; | |
336 bool bDown = | |
337 pMsg->m_dwKeyCode == FWL_VKEY_Down || pMsg->m_dwKeyCode == FWL_VKEY_Right; | |
338 if (!bUp && !bDown) | |
339 return; | |
340 | |
341 bool bUpEnable = IsUpButtonEnabled(); | |
342 bool bDownEnable = IsDownButtonEnabled(); | |
343 if (!bUpEnable && !bDownEnable) | |
344 return; | |
345 | |
346 CFWL_Event wmPosChanged(CFWL_Event::Type::Click, this); | |
347 DispatchEvent(&wmPosChanged); | |
348 | |
349 Repaint(bUpEnable ? &m_rtUpButton : &m_rtDnButton); | |
350 } | |
351 | |
352 CFWL_SpinButton::Timer::Timer(CFWL_SpinButton* pToolTip) | |
353 : CFWL_Timer(pToolTip) {} | |
354 | |
355 void CFWL_SpinButton::Timer::Run(CFWL_TimerInfo* pTimerInfo) { | |
356 CFWL_SpinButton* pButton = static_cast<CFWL_SpinButton*>(m_pWidget); | |
357 | |
358 if (!pButton->m_pTimerInfo) | |
359 return; | |
360 | |
361 CFWL_Event wmPosChanged(CFWL_Event::Type::Click, pButton); | |
362 pButton->DispatchEvent(&wmPosChanged); | |
363 } | |
OLD | NEW |