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