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/src/fwl/basewidget/fwl_spinbuttonimp.h" | |
8 | |
9 #include "xfa/include/fwl/basewidget/fwl_spinbutton.h" | |
10 #include "xfa/include/fwl/core/fwl_theme.h" | |
11 #include "xfa/include/fwl/core/fwl_timer.h" | |
12 #include "xfa/src/fwl/core/fwl_noteimp.h" | |
13 #include "xfa/src/fwl/core/fwl_targetimp.h" | |
14 #include "xfa/src/fwl/core/fwl_widgetimp.h" | |
15 | |
16 #define FWL_SPN_MinWidth 18 | |
17 #define FWL_SPN_MinHeight 32 | |
18 #define FWL_SPIN_Elapse 200 | |
19 | |
20 // static | |
21 IFWL_SpinButton* IFWL_SpinButton::Create( | |
22 const CFWL_WidgetImpProperties& properties, | |
23 IFWL_Widget* pOuter) { | |
24 IFWL_SpinButton* pSpinButton = new IFWL_SpinButton; | |
25 CFWL_SpinButtonImp* pSpinButtonImpl = | |
26 new CFWL_SpinButtonImp(properties, nullptr); | |
27 pSpinButton->SetImpl(pSpinButtonImpl); | |
28 pSpinButtonImpl->SetInterface(pSpinButton); | |
29 return pSpinButton; | |
30 } | |
31 IFWL_SpinButton::IFWL_SpinButton() {} | |
32 FWL_ERR IFWL_SpinButton::EnableButton(FX_BOOL bEnable, FX_BOOL bUp) { | |
33 return static_cast<CFWL_SpinButtonImp*>(GetImpl()) | |
34 ->EnableButton(bEnable, bUp); | |
35 } | |
36 FX_BOOL IFWL_SpinButton::IsButtonEnable(FX_BOOL bUp) { | |
37 return static_cast<CFWL_SpinButtonImp*>(GetImpl())->IsButtonEnable(bUp); | |
38 } | |
39 | |
40 CFWL_SpinButtonImp::CFWL_SpinButtonImp( | |
41 const CFWL_WidgetImpProperties& properties, | |
42 IFWL_Widget* pOuter) | |
43 : CFWL_WidgetImp(properties, pOuter), | |
44 m_dwUpState(FWL_PARTSTATE_SPB_Normal), | |
45 m_dwDnState(FWL_PARTSTATE_SPB_Normal), | |
46 m_iButtonIndex(0), | |
47 m_bLButtonDwn(FALSE), | |
48 m_hTimer(NULL) { | |
49 m_rtClient.Reset(); | |
50 m_rtUpButton.Reset(); | |
51 m_rtDnButton.Reset(); | |
52 m_pProperties->m_dwStyleExes |= FWL_STYLEEXE_SPB_Vert; | |
53 } | |
54 CFWL_SpinButtonImp::~CFWL_SpinButtonImp() {} | |
55 FWL_ERR CFWL_SpinButtonImp::GetClassName(CFX_WideString& wsClass) const { | |
56 wsClass = FWL_CLASS_SpinButton; | |
57 return FWL_ERR_Succeeded; | |
58 } | |
59 FX_DWORD CFWL_SpinButtonImp::GetClassID() const { | |
60 return FWL_CLASSHASH_SpinButton; | |
61 } | |
62 FWL_ERR CFWL_SpinButtonImp::Initialize() { | |
63 if (CFWL_WidgetImp::Initialize() != FWL_ERR_Succeeded) | |
64 return FWL_ERR_Indefinite; | |
65 m_pDelegate = new CFWL_SpinButtonImpDelegate(this); | |
66 return FWL_ERR_Succeeded; | |
67 } | |
68 FWL_ERR CFWL_SpinButtonImp::Finalize() { | |
69 delete m_pDelegate; | |
70 m_pDelegate = nullptr; | |
71 return CFWL_WidgetImp::Finalize(); | |
72 } | |
73 FWL_ERR CFWL_SpinButtonImp::GetWidgetRect(CFX_RectF& rect, FX_BOOL bAutoSize) { | |
74 if (bAutoSize) { | |
75 rect.Set(0, 0, FWL_SPN_MinWidth, FWL_SPN_MinHeight); | |
76 CFWL_WidgetImp::GetWidgetRect(rect, TRUE); | |
77 } else { | |
78 rect = m_pProperties->m_rtWidget; | |
79 } | |
80 return FWL_ERR_Succeeded; | |
81 } | |
82 FWL_ERR CFWL_SpinButtonImp::Update() { | |
83 if (IsLocked()) { | |
84 return FWL_ERR_Indefinite; | |
85 } | |
86 GetClientRect(m_rtClient); | |
87 if (m_pProperties->m_dwStyleExes & FWL_STYLEEXE_SPB_Vert) { | |
88 m_rtUpButton.Set(m_rtClient.top, m_rtClient.left, m_rtClient.width, | |
89 m_rtClient.height / 2); | |
90 m_rtDnButton.Set(m_rtClient.left, m_rtClient.top + m_rtClient.height / 2, | |
91 m_rtClient.width, m_rtClient.height / 2); | |
92 } else { | |
93 m_rtUpButton.Set(m_rtClient.left, m_rtClient.top, m_rtClient.width / 2, | |
94 m_rtClient.height); | |
95 m_rtDnButton.Set(m_rtClient.left + m_rtClient.width / 2, m_rtClient.top, | |
96 m_rtClient.width / 2, m_rtClient.height); | |
97 } | |
98 return FWL_ERR_Succeeded; | |
99 } | |
100 FX_DWORD CFWL_SpinButtonImp::HitTest(FX_FLOAT fx, FX_FLOAT fy) { | |
101 if (m_rtClient.Contains(fx, fy)) { | |
102 return FWL_WGTHITTEST_Client; | |
103 } | |
104 if (HasBorder() && (m_rtClient.Contains(fx, fy))) { | |
105 return FWL_WGTHITTEST_Border; | |
106 } | |
107 if (HasEdge()) { | |
108 CFX_RectF rtEdge; | |
109 GetEdgeRect(rtEdge); | |
110 if (rtEdge.Contains(fx, fy)) { | |
111 return FWL_PART_SPB_Edge; | |
112 } | |
113 } | |
114 if (m_rtUpButton.Contains(fx, fy)) { | |
115 return FWL_WGTHITTEST_SPB_UpButton; | |
116 } | |
117 if (m_rtDnButton.Contains(fx, fy)) { | |
118 return FWL_WGTHITTEST_SPB_DownButton; | |
119 } | |
120 return FWL_WGTHITTEST_Unknown; | |
121 } | |
122 FWL_ERR CFWL_SpinButtonImp::DrawWidget(CFX_Graphics* pGraphics, | |
123 const CFX_Matrix* pMatrix) { | |
124 if (!pGraphics) | |
125 return FWL_ERR_Indefinite; | |
126 CFX_RectF rtClip(m_rtClient); | |
127 if (pMatrix != NULL) { | |
128 pMatrix->TransformRect(rtClip); | |
129 } | |
130 IFWL_ThemeProvider* pTheme = GetAvailableTheme(); | |
131 if (HasBorder()) { | |
132 DrawBorder(pGraphics, FWL_PART_SPB_Border, pTheme, pMatrix); | |
133 } | |
134 if (HasEdge()) { | |
135 DrawEdge(pGraphics, FWL_PART_SPB_Edge, pTheme, pMatrix); | |
136 } | |
137 DrawUpButton(pGraphics, pTheme, pMatrix); | |
138 DrawDownButton(pGraphics, pTheme, pMatrix); | |
139 return FWL_ERR_Succeeded; | |
140 } | |
141 int32_t CFWL_SpinButtonImp::Run(FWL_HTIMER hTimer) { | |
142 if (m_hTimer) { | |
143 CFWL_EvtSpbClick wmPosChanged; | |
144 wmPosChanged.m_pSrcTarget = m_pInterface; | |
145 wmPosChanged.m_bUp = m_iButtonIndex == 0; | |
146 DispatchEvent(&wmPosChanged); | |
147 } | |
148 return 1; | |
149 } | |
150 FWL_ERR CFWL_SpinButtonImp::EnableButton(FX_BOOL bEnable, FX_BOOL bUp) { | |
151 if (bUp) { | |
152 if (bEnable) { | |
153 m_dwUpState = FWL_PARTSTATE_SPB_Normal; | |
154 } else { | |
155 m_dwUpState = FWL_PARTSTATE_SPB_Disabled; | |
156 } | |
157 } else { | |
158 if (bEnable) { | |
159 m_dwDnState = FWL_PARTSTATE_SPB_Normal; | |
160 } else { | |
161 m_dwDnState = FWL_PARTSTATE_SPB_Disabled; | |
162 } | |
163 } | |
164 return FWL_ERR_Succeeded; | |
165 } | |
166 FX_BOOL CFWL_SpinButtonImp::IsButtonEnable(FX_BOOL bUp) { | |
167 if (bUp) { | |
168 return (m_dwUpState != FWL_PARTSTATE_SPB_Disabled); | |
169 } | |
170 return (m_dwDnState != FWL_PARTSTATE_SPB_Disabled); | |
171 } | |
172 void CFWL_SpinButtonImp::DrawUpButton(CFX_Graphics* pGraphics, | |
173 IFWL_ThemeProvider* pTheme, | |
174 const CFX_Matrix* pMatrix) { | |
175 CFWL_ThemeBackground params; | |
176 params.m_pWidget = m_pInterface; | |
177 params.m_iPart = FWL_PART_SPB_UpButton; | |
178 params.m_pGraphics = pGraphics; | |
179 params.m_dwStates = m_dwUpState + 1; | |
180 if (pMatrix) { | |
181 params.m_matrix.Concat(*pMatrix); | |
182 } | |
183 params.m_rtPart = m_rtUpButton; | |
184 pTheme->DrawBackground(¶ms); | |
185 } | |
186 void CFWL_SpinButtonImp::DrawDownButton(CFX_Graphics* pGraphics, | |
187 IFWL_ThemeProvider* pTheme, | |
188 const CFX_Matrix* pMatrix) { | |
189 CFWL_ThemeBackground params; | |
190 params.m_pWidget = m_pInterface; | |
191 params.m_iPart = FWL_PART_SPB_DownButton; | |
192 params.m_pGraphics = pGraphics; | |
193 params.m_dwStates = m_dwDnState + 1; | |
194 if (pMatrix) { | |
195 params.m_matrix.Concat(*pMatrix); | |
196 } | |
197 params.m_rtPart = m_rtDnButton; | |
198 pTheme->DrawBackground(¶ms); | |
199 } | |
200 CFWL_SpinButtonImpDelegate::CFWL_SpinButtonImpDelegate( | |
201 CFWL_SpinButtonImp* pOwner) | |
202 : m_pOwner(pOwner) {} | |
203 int32_t CFWL_SpinButtonImpDelegate::OnProcessMessage(CFWL_Message* pMessage) { | |
204 if (!pMessage) | |
205 return 0; | |
206 int32_t iRet = 1; | |
207 FX_DWORD dwMsgCode = pMessage->GetClassID(); | |
208 switch (dwMsgCode) { | |
209 case FWL_MSGHASH_SetFocus: | |
210 case FWL_MSGHASH_KillFocus: { | |
211 OnFocusChanged(pMessage, dwMsgCode == FWL_MSGHASH_SetFocus); | |
212 break; | |
213 } | |
214 case FWL_MSGHASH_Mouse: { | |
215 CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage); | |
216 FX_DWORD dwCmd = pMsg->m_dwCmd; | |
217 switch (dwCmd) { | |
218 case FWL_MSGMOUSECMD_LButtonDown: { | |
219 OnLButtonDown(pMsg); | |
220 break; | |
221 } | |
222 case FWL_MSGMOUSECMD_LButtonUp: { | |
223 OnLButtonUp(pMsg); | |
224 break; | |
225 } | |
226 case FWL_MSGMOUSECMD_MouseMove: { | |
227 OnMouseMove(pMsg); | |
228 break; | |
229 } | |
230 case FWL_MSGMOUSECMD_MouseLeave: { | |
231 OnMouseLeave(pMsg); | |
232 break; | |
233 } | |
234 default: {} | |
235 } | |
236 break; | |
237 } | |
238 case FWL_MSGHASH_Key: { | |
239 CFWL_MsgKey* pKey = static_cast<CFWL_MsgKey*>(pMessage); | |
240 if (pKey->m_dwCmd == FWL_MSGKEYCMD_KeyDown) { | |
241 OnKeyDown(pKey); | |
242 } | |
243 break; | |
244 } | |
245 default: { | |
246 iRet = 0; | |
247 break; | |
248 } | |
249 } | |
250 CFWL_WidgetImpDelegate::OnProcessMessage(pMessage); | |
251 return iRet; | |
252 } | |
253 FWL_ERR CFWL_SpinButtonImpDelegate::OnProcessEvent(CFWL_Event* pEvent) { | |
254 return FWL_ERR_Succeeded; | |
255 } | |
256 FWL_ERR CFWL_SpinButtonImpDelegate::OnDrawWidget(CFX_Graphics* pGraphics, | |
257 const CFX_Matrix* pMatrix) { | |
258 return m_pOwner->DrawWidget(pGraphics, pMatrix); | |
259 } | |
260 void CFWL_SpinButtonImpDelegate::OnFocusChanged(CFWL_Message* pMsg, | |
261 FX_BOOL bSet) { | |
262 if (bSet) { | |
263 m_pOwner->m_pProperties->m_dwStates |= (FWL_WGTSTATE_Focused); | |
264 } else { | |
265 m_pOwner->m_pProperties->m_dwStates &= ~(FWL_WGTSTATE_Focused); | |
266 } | |
267 m_pOwner->Repaint(&m_pOwner->m_rtClient); | |
268 } | |
269 void CFWL_SpinButtonImpDelegate::OnLButtonDown(CFWL_MsgMouse* pMsg) { | |
270 m_pOwner->m_bLButtonDwn = TRUE; | |
271 m_pOwner->SetGrab(TRUE); | |
272 m_pOwner->SetFocus(TRUE); | |
273 if (!m_pOwner->m_pProperties->m_pDataProvider) | |
274 return; | |
275 FX_BOOL bUpPress = (m_pOwner->m_rtUpButton.Contains(pMsg->m_fx, pMsg->m_fy) && | |
276 m_pOwner->IsButtonEnable(TRUE)); | |
277 FX_BOOL bDnPress = (m_pOwner->m_rtDnButton.Contains(pMsg->m_fx, pMsg->m_fy) && | |
278 m_pOwner->IsButtonEnable(FALSE)); | |
279 if (!bUpPress && !bDnPress) { | |
280 return; | |
281 } | |
282 if (bUpPress) { | |
283 m_pOwner->m_iButtonIndex = 0; | |
284 m_pOwner->m_dwUpState = FWL_PARTSTATE_SPB_Pressed; | |
285 } | |
286 if (bDnPress) { | |
287 m_pOwner->m_iButtonIndex = 1; | |
288 m_pOwner->m_dwDnState = FWL_PARTSTATE_SPB_Pressed; | |
289 } | |
290 CFWL_EvtSpbClick wmPosChanged; | |
291 wmPosChanged.m_pSrcTarget = m_pOwner->m_pInterface; | |
292 wmPosChanged.m_bUp = bUpPress; | |
293 m_pOwner->DispatchEvent(&wmPosChanged); | |
294 m_pOwner->Repaint(bUpPress ? &m_pOwner->m_rtUpButton | |
295 : &m_pOwner->m_rtDnButton); | |
296 m_pOwner->m_hTimer = FWL_StartTimer(m_pOwner, FWL_SPIN_Elapse); | |
297 } | |
298 void CFWL_SpinButtonImpDelegate::OnLButtonUp(CFWL_MsgMouse* pMsg) { | |
299 if (m_pOwner->m_pProperties->m_dwStates & FWL_PARTSTATE_SPB_Disabled) { | |
300 return; | |
301 } | |
302 m_pOwner->m_bLButtonDwn = FALSE; | |
303 m_pOwner->SetGrab(FALSE); | |
304 m_pOwner->SetFocus(FALSE); | |
305 if (m_pOwner->m_hTimer) { | |
306 FWL_StopTimer(m_pOwner->m_hTimer); | |
307 m_pOwner->m_hTimer = NULL; | |
308 } | |
309 FX_BOOL bRepaint = FALSE; | |
310 CFX_RectF rtInvalidate; | |
311 if (m_pOwner->m_dwUpState == FWL_PARTSTATE_SPB_Pressed && | |
312 m_pOwner->IsButtonEnable(TRUE)) { | |
313 m_pOwner->m_dwUpState = FWL_PARTSTATE_SPB_Normal; | |
314 bRepaint = TRUE; | |
315 rtInvalidate = m_pOwner->m_rtUpButton; | |
316 } else if (m_pOwner->m_dwDnState == FWL_PARTSTATE_SPB_Pressed && | |
317 m_pOwner->IsButtonEnable(FALSE)) { | |
318 m_pOwner->m_dwDnState = FWL_PARTSTATE_SPB_Normal; | |
319 bRepaint = TRUE; | |
320 rtInvalidate = m_pOwner->m_rtDnButton; | |
321 } | |
322 if (bRepaint) { | |
323 m_pOwner->Repaint(&rtInvalidate); | |
324 } | |
325 } | |
326 void CFWL_SpinButtonImpDelegate::OnMouseMove(CFWL_MsgMouse* pMsg) { | |
327 if (!m_pOwner->m_pProperties->m_pDataProvider) | |
328 return; | |
329 if (m_pOwner->m_bLButtonDwn) { | |
330 return; | |
331 } | |
332 FX_BOOL bRepaint = FALSE; | |
333 CFX_RectF rtInvlidate; | |
334 rtInvlidate.Reset(); | |
335 if (m_pOwner->m_rtUpButton.Contains(pMsg->m_fx, pMsg->m_fy)) { | |
336 if (m_pOwner->IsButtonEnable(TRUE)) { | |
337 if (m_pOwner->m_dwUpState == FWL_PARTSTATE_SPB_Hovered) { | |
338 m_pOwner->m_dwUpState = FWL_PARTSTATE_SPB_Hovered; | |
339 bRepaint = TRUE; | |
340 rtInvlidate = m_pOwner->m_rtUpButton; | |
341 } | |
342 if (m_pOwner->m_dwDnState != FWL_PARTSTATE_SPB_Normal && | |
343 m_pOwner->IsButtonEnable(FALSE)) { | |
344 m_pOwner->m_dwDnState = FWL_PARTSTATE_SPB_Normal; | |
345 if (bRepaint) { | |
346 rtInvlidate.Union(m_pOwner->m_rtDnButton); | |
347 } else { | |
348 rtInvlidate = m_pOwner->m_rtDnButton; | |
349 } | |
350 bRepaint = TRUE; | |
351 } | |
352 } | |
353 if (!m_pOwner->IsButtonEnable(FALSE)) { | |
354 m_pOwner->EnableButton(FALSE, FALSE); | |
355 } | |
356 } else if (m_pOwner->m_rtDnButton.Contains(pMsg->m_fx, pMsg->m_fy)) { | |
357 if (m_pOwner->IsButtonEnable(FALSE)) { | |
358 if (m_pOwner->m_dwDnState != FWL_PARTSTATE_SPB_Hovered) { | |
359 m_pOwner->m_dwDnState = FWL_PARTSTATE_SPB_Hovered; | |
360 bRepaint = TRUE; | |
361 rtInvlidate = m_pOwner->m_rtDnButton; | |
362 } | |
363 if (m_pOwner->m_dwUpState != FWL_PARTSTATE_SPB_Normal && | |
364 m_pOwner->IsButtonEnable(TRUE)) { | |
365 m_pOwner->m_dwUpState = FWL_PARTSTATE_SPB_Normal; | |
366 if (bRepaint) { | |
367 rtInvlidate.Union(m_pOwner->m_rtUpButton); | |
368 } else { | |
369 rtInvlidate = m_pOwner->m_rtUpButton; | |
370 } | |
371 bRepaint = TRUE; | |
372 } | |
373 } | |
374 } else if (m_pOwner->m_dwUpState != FWL_PARTSTATE_SPB_Normal || | |
375 m_pOwner->m_dwDnState != FWL_PARTSTATE_SPB_Normal) { | |
376 if (m_pOwner->m_dwUpState != FWL_PARTSTATE_SPB_Normal) { | |
377 m_pOwner->m_dwUpState = FWL_PARTSTATE_SPB_Normal; | |
378 bRepaint = TRUE; | |
379 rtInvlidate = m_pOwner->m_rtUpButton; | |
380 } | |
381 if (m_pOwner->m_dwDnState != FWL_PARTSTATE_SPB_Normal) { | |
382 m_pOwner->m_dwDnState = FWL_PARTSTATE_SPB_Normal; | |
383 if (bRepaint) { | |
384 rtInvlidate.Union(m_pOwner->m_rtDnButton); | |
385 } else { | |
386 rtInvlidate = m_pOwner->m_rtDnButton; | |
387 } | |
388 bRepaint = TRUE; | |
389 } | |
390 } | |
391 if (bRepaint) { | |
392 m_pOwner->Repaint(&rtInvlidate); | |
393 } | |
394 } | |
395 void CFWL_SpinButtonImpDelegate::OnMouseLeave(CFWL_MsgMouse* pMsg) { | |
396 if (!pMsg) | |
397 return; | |
398 if (m_pOwner->m_dwUpState != FWL_PARTSTATE_SPB_Normal && | |
399 m_pOwner->IsButtonEnable(TRUE)) { | |
400 m_pOwner->m_dwUpState = FWL_PARTSTATE_SPB_Normal; | |
401 } | |
402 if (m_pOwner->m_dwDnState != FWL_PARTSTATE_SPB_Normal && | |
403 m_pOwner->IsButtonEnable(FALSE)) { | |
404 m_pOwner->m_dwDnState = FWL_PARTSTATE_SPB_Normal; | |
405 } | |
406 m_pOwner->Repaint(&m_pOwner->m_rtClient); | |
407 } | |
408 void CFWL_SpinButtonImpDelegate::OnKeyDown(CFWL_MsgKey* pMsg) { | |
409 if (!m_pOwner->m_pProperties->m_pDataProvider) | |
410 return; | |
411 FX_BOOL bUp = | |
412 pMsg->m_dwKeyCode == FWL_VKEY_Up || pMsg->m_dwKeyCode == FWL_VKEY_Left; | |
413 FX_BOOL bDown = | |
414 pMsg->m_dwKeyCode == FWL_VKEY_Down || pMsg->m_dwKeyCode == FWL_VKEY_Right; | |
415 if (!bUp && !bDown) { | |
416 return; | |
417 } | |
418 FX_BOOL bUpEnable = m_pOwner->IsButtonEnable(TRUE); | |
419 FX_BOOL bDownEnable = m_pOwner->IsButtonEnable(FALSE); | |
420 if (!bUpEnable && !bDownEnable) { | |
421 return; | |
422 } | |
423 CFWL_EvtSpbClick wmPosChanged; | |
424 wmPosChanged.m_pSrcTarget = m_pOwner->m_pInterface; | |
425 wmPosChanged.m_bUp = bUpEnable; | |
426 m_pOwner->DispatchEvent(&wmPosChanged); | |
427 m_pOwner->Repaint(bUpEnable ? &m_pOwner->m_rtUpButton | |
428 : &m_pOwner->m_rtDnButton); | |
429 } | |
OLD | NEW |