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