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