| 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 |