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_scrollbarimp.h" 12 #define FWL_SCROLLBAR_Elapse 500 13 #define FWL_SCROLLBAR_MinThumb 5 14 15 // static 16 IFWL_ScrollBar* IFWL_ScrollBar::Create( 17 const CFWL_WidgetImpProperties& properties, 18 IFWL_Widget* pOuter) { 19 IFWL_ScrollBar* pScrollBar = new IFWL_ScrollBar; 20 CFWL_ScrollBarImp* pScrollBarImpl = new CFWL_ScrollBarImp(properties, pOuter); 21 pScrollBar->SetImpl(pScrollBarImpl); 22 pScrollBarImpl->SetInterface(pScrollBar); 23 return pScrollBar; 24 } 25 IFWL_ScrollBar::IFWL_ScrollBar() {} 26 FX_BOOL IFWL_ScrollBar::IsVertical() { 27 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->IsVertical(); 28 } 29 FWL_ERR IFWL_ScrollBar::GetRange(FX_FLOAT& fMin, FX_FLOAT& fMax) { 30 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->GetRange(fMin, fMax); 31 } 32 FWL_ERR IFWL_ScrollBar::SetRange(FX_FLOAT fMin, FX_FLOAT fMax) { 33 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->SetRange(fMin, fMax); 34 } 35 FX_FLOAT IFWL_ScrollBar::GetPageSize() { 36 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->GetPageSize(); 37 } 38 FWL_ERR IFWL_ScrollBar::SetPageSize(FX_FLOAT fPageSize) { 39 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->SetPageSize(fPageSize); 40 } 41 FX_FLOAT IFWL_ScrollBar::GetStepSize() { 42 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->GetStepSize(); 43 } 44 FWL_ERR IFWL_ScrollBar::SetStepSize(FX_FLOAT fStepSize) { 45 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->SetStepSize(fStepSize); 46 } 47 FX_FLOAT IFWL_ScrollBar::GetPos() { 48 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->GetPos(); 49 } 50 FWL_ERR IFWL_ScrollBar::SetPos(FX_FLOAT fPos) { 51 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->SetPos(fPos); 52 } 53 FX_FLOAT IFWL_ScrollBar::GetTrackPos() { 54 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->GetTrackPos(); 55 } 56 FWL_ERR IFWL_ScrollBar::SetTrackPos(FX_FLOAT fTrackPos) { 57 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->SetTrackPos(fTrackPos); 58 } 59 FX_BOOL IFWL_ScrollBar::DoScroll(FX_DWORD dwCode, FX_FLOAT fPos) { 60 return static_cast<CFWL_ScrollBarImp*>(GetImpl())->DoScroll(dwCode, fPos); 61 } 62 CFWL_ScrollBarImp::CFWL_ScrollBarImp(const CFWL_WidgetImpProperties& properties, 63 IFWL_Widget* pOuter) 64 : CFWL_WidgetImp(properties, pOuter), 65 m_hTimer(nullptr), 66 m_fRangeMin(0), 67 m_fRangeMax(-1), 68 m_fPageSize(0), 69 m_fStepSize(0), 70 m_fPos(0), 71 m_fTrackPos(0), 72 m_iMinButtonState(FWL_PARTSTATE_SCB_Normal), 73 m_iMaxButtonState(FWL_PARTSTATE_SCB_Normal), 74 m_iThumbButtonState(FWL_PARTSTATE_SCB_Normal), 75 m_iMinTrackState(FWL_PARTSTATE_SCB_Normal), 76 m_iMaxTrackState(FWL_PARTSTATE_SCB_Normal), 77 m_fLastTrackPos(0), 78 m_cpTrackPointX(0), 79 m_cpTrackPointY(0), 80 m_iMouseWheel(0), 81 m_bTrackMouseLeave(FALSE), 82 m_bMouseHover(FALSE), 83 m_bMouseDown(FALSE), 84 m_bRepaintThumb(FALSE), 85 m_fButtonLen(0), 86 m_bMinSize(FALSE), 87 m_bCustomLayout(FALSE), 88 m_fMinThumb(FWL_SCROLLBAR_MinThumb) { 89 m_rtClient.Reset(); 90 m_rtThumb.Reset(); 91 m_rtMinBtn.Reset(); 92 m_rtMaxBtn.Reset(); 93 m_rtMinTrack.Reset(); 94 m_rtMaxTrack.Reset(); 95 } 96 CFWL_ScrollBarImp::~CFWL_ScrollBarImp() {} 97 FWL_ERR CFWL_ScrollBarImp::GetClassName(CFX_WideString& wsClass) const { 98 wsClass = FWL_CLASS_ScrollBar; 99 return FWL_ERR_Succeeded; 100 } 101 FX_DWORD CFWL_ScrollBarImp::GetClassID() const { 102 return FWL_CLASSHASH_ScrollBar; 103 } 104 FWL_ERR CFWL_ScrollBarImp::Initialize() { 105 if (CFWL_WidgetImp::Initialize() != FWL_ERR_Succeeded) 106 return FWL_ERR_Indefinite; 107 m_pDelegate = new CFWL_ScrollBarImpDelegate(this); 108 return FWL_ERR_Succeeded; 109 } 110 FWL_ERR CFWL_ScrollBarImp::Finalize() { 111 delete m_pDelegate; 112 m_pDelegate = nullptr; 113 return CFWL_WidgetImp::Finalize(); 114 } 115 FWL_ERR CFWL_ScrollBarImp::GetWidgetRect(CFX_RectF& rect, FX_BOOL bAutoSize) { 116 if (bAutoSize) { 117 rect.Set(0, 0, 0, 0); 118 FX_FLOAT* pfMinWidth = static_cast<FX_FLOAT*>( 119 GetThemeCapacity(FWL_WGTCAPACITY_ScrollBarWidth)); 120 if (!pfMinWidth) 121 return FWL_ERR_Indefinite; 122 if (IsVertical()) { 123 rect.Set(0, 0, (*pfMinWidth), (*pfMinWidth) * 3); 124 } else { 125 rect.Set(0, 0, (*pfMinWidth) * 3, (*pfMinWidth)); 126 } 127 CFWL_WidgetImp::GetWidgetRect(rect, TRUE); 128 } else { 129 rect = m_pProperties->m_rtWidget; 130 } 131 return FWL_ERR_Succeeded; 132 } 133 FWL_ERR CFWL_ScrollBarImp::Update() { 134 if (IsLocked()) { 135 return FWL_ERR_Indefinite; 136 } 137 if (!m_pProperties->m_pThemeProvider) { 138 m_pProperties->m_pThemeProvider = GetAvailableTheme(); 139 } 140 Layout(); 141 return FWL_ERR_Succeeded; 142 } 143 FWL_ERR CFWL_ScrollBarImp::DrawWidget(CFX_Graphics* pGraphics, 144 const CFX_Matrix* pMatrix) { 145 if (!pGraphics) 146 return FWL_ERR_Indefinite; 147 if (!m_pProperties->m_pThemeProvider) 148 return FWL_ERR_Indefinite; 149 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider; 150 if (HasBorder()) { 151 DrawBorder(pGraphics, FWL_PART_SCB_Border, pTheme, pMatrix); 152 } 153 if (HasEdge()) { 154 DrawEdge(pGraphics, FWL_PART_SCB_Edge, pTheme, pMatrix); 155 } 156 DrawTrack(pGraphics, pTheme, TRUE, pMatrix); 157 DrawTrack(pGraphics, pTheme, FALSE, pMatrix); 158 DrawArrowBtn(pGraphics, pTheme, TRUE, pMatrix); 159 DrawArrowBtn(pGraphics, pTheme, FALSE, pMatrix); 160 DrawThumb(pGraphics, pTheme, pMatrix); 161 return FWL_ERR_Succeeded; 162 } 163 inline FX_BOOL CFWL_ScrollBarImp::IsVertical() { 164 return m_pProperties->m_dwStyleExes & FWL_STYLEEXT_SCB_Vert; 165 } 166 FWL_ERR CFWL_ScrollBarImp::GetRange(FX_FLOAT& fMin, FX_FLOAT& fMax) { 167 fMin = m_fRangeMin; 168 fMax = m_fRangeMax; 169 return FWL_ERR_Succeeded; 170 } 171 FWL_ERR CFWL_ScrollBarImp::SetRange(FX_FLOAT fMin, FX_FLOAT fMax) { 172 m_fRangeMin = fMin; 173 m_fRangeMax = fMax; 174 return FWL_ERR_Succeeded; 175 } 176 FX_FLOAT CFWL_ScrollBarImp::GetPageSize() { 177 return m_fPageSize; 178 } 179 FWL_ERR CFWL_ScrollBarImp::SetPageSize(FX_FLOAT fPageSize) { 180 m_fPageSize = fPageSize; 181 return FWL_ERR_Succeeded; 182 } 183 FX_FLOAT CFWL_ScrollBarImp::GetStepSize() { 184 return m_fStepSize; 185 } 186 FWL_ERR CFWL_ScrollBarImp::SetStepSize(FX_FLOAT fStepSize) { 187 m_fStepSize = fStepSize; 188 return FWL_ERR_Succeeded; 189 } 190 FX_FLOAT CFWL_ScrollBarImp::GetPos() { 191 return m_fPos; 192 } 193 FWL_ERR CFWL_ScrollBarImp::SetPos(FX_FLOAT fPos) { 194 m_fPos = fPos; 195 return FWL_ERR_Succeeded; 196 } 197 FX_FLOAT CFWL_ScrollBarImp::GetTrackPos() { 198 return m_fTrackPos; 199 } 200 FWL_ERR CFWL_ScrollBarImp::SetTrackPos(FX_FLOAT fTrackPos) { 201 m_fTrackPos = fTrackPos; 202 CalcThumbButtonRect(m_rtThumb); 203 CalcMinTrackRect(m_rtMinTrack); 204 CalcMaxTrackRect(m_rtMaxTrack); 205 return FWL_ERR_Succeeded; 206 } 207 FX_BOOL CFWL_ScrollBarImp::DoScroll(FX_DWORD dwCode, FX_FLOAT fPos) { 208 switch (dwCode) { 209 case FWL_SCBCODE_Min: 210 case FWL_SCBCODE_Max: 211 case FWL_SCBCODE_PageBackward: 212 case FWL_SCBCODE_PageForward: 213 case FWL_SCBCODE_StepBackward: 214 break; 215 case FWL_SCBCODE_StepForward: 216 break; 217 case FWL_SCBCODE_Pos: 218 case FWL_SCBCODE_TrackPos: 219 case FWL_SCBCODE_EndScroll: 220 break; 221 default: { return FALSE; } 222 } 223 return OnScroll(dwCode, fPos); 224 } 225 int32_t CFWL_ScrollBarImp::Run(FWL_HTIMER hTimer) { 226 if (m_hTimer) { 227 FWL_StopTimer(m_hTimer); 228 } 229 if (!SendEvent()) { 230 m_hTimer = FWL_StartTimer(this, 0); 231 } 232 return 1; 233 } 234 FWL_ERR CFWL_ScrollBarImp::SetOuter(IFWL_Widget* pOuter) { 235 m_pOuter = pOuter; 236 return FWL_ERR_Succeeded; 237 } 238 void CFWL_ScrollBarImp::DrawTrack(CFX_Graphics* pGraphics, 239 IFWL_ThemeProvider* pTheme, 240 FX_BOOL bLower, 241 const CFX_Matrix* pMatrix) { 242 CFWL_ThemeBackground param; 243 param.m_pWidget = m_pInterface; 244 param.m_iPart = bLower ? FWL_PART_SCB_LowerTrack : FWL_PART_SCB_UpperTrack; 245 param.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) 246 ? FWL_PARTSTATE_SCB_Disabled 247 : (bLower ? m_iMinTrackState : m_iMaxTrackState); 248 param.m_pGraphics = pGraphics; 249 param.m_matrix.Concat(*pMatrix); 250 param.m_rtPart = bLower ? m_rtMinTrack : m_rtMaxTrack; 251 pTheme->DrawBackground(¶m); 252 } 253 void CFWL_ScrollBarImp::DrawArrowBtn(CFX_Graphics* pGraphics, 254 IFWL_ThemeProvider* pTheme, 255 FX_BOOL bMinBtn, 256 const CFX_Matrix* pMatrix) { 257 CFWL_ThemeBackground param; 258 param.m_pWidget = m_pInterface; 259 param.m_iPart = bMinBtn ? FWL_PART_SCB_ForeArrow : FWL_PART_SCB_BackArrow; 260 param.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) 261 ? FWL_PARTSTATE_SCB_Disabled 262 : (bMinBtn ? m_iMinButtonState : m_iMaxButtonState); 263 param.m_pGraphics = pGraphics; 264 param.m_matrix.Concat(*pMatrix); 265 param.m_rtPart = bMinBtn ? m_rtMinBtn : m_rtMaxBtn; 266 if (param.m_rtPart.height > 0 && param.m_rtPart.width > 0) { 267 pTheme->DrawBackground(¶m); 268 } 269 } 270 void CFWL_ScrollBarImp::DrawThumb(CFX_Graphics* pGraphics, 271 IFWL_ThemeProvider* pTheme, 272 const CFX_Matrix* pMatrix) { 273 if (!IsEnabled()) { 274 } 275 CFWL_ThemeBackground param; 276 param.m_pWidget = m_pInterface; 277 param.m_iPart = FWL_PART_SCB_Thumb; 278 param.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) 279 ? FWL_PARTSTATE_SCB_Disabled 280 : m_iThumbButtonState; 281 param.m_pGraphics = pGraphics; 282 param.m_matrix.Concat(*pMatrix); 283 param.m_rtPart = m_rtThumb; 284 pTheme->DrawBackground(¶m); 285 } 286 void CFWL_ScrollBarImp::Layout() { 287 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider; 288 CFWL_ThemePart part; 289 part.m_pWidget = m_pInterface; 290 m_fMinThumb = *static_cast<FX_FLOAT*>( 291 pTheme->GetCapacity(&part, FWL_CAPACITY_SCB_Size)); 292 m_bCustomLayout = pTheme->IsCustomizedLayout(m_pInterface); 293 GetClientRect(m_rtClient); 294 CalcButtonLen(); 295 CalcMinButtonRect(m_rtMinBtn); 296 CalcMaxButtonRect(m_rtMaxBtn); 297 CalcThumbButtonRect(m_rtThumb); 298 CalcMinTrackRect(m_rtMinTrack); 299 CalcMaxTrackRect(m_rtMaxTrack); 300 } 301 void CFWL_ScrollBarImp::CalcButtonLen() { 302 m_fButtonLen = IsVertical() ? m_rtClient.width : m_rtClient.height; 303 FX_FLOAT fLength = IsVertical() ? m_rtClient.height : m_rtClient.width; 304 if (fLength < m_fButtonLen * 2) { 305 m_fButtonLen = fLength / 2; 306 m_bMinSize = TRUE; 307 } else { 308 m_bMinSize = FALSE; 309 } 310 } 311 void CFWL_ScrollBarImp::CalcMinButtonRect(CFX_RectF& rect) { 312 if (m_bCustomLayout) { 313 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider; 314 CFWL_ThemePart pPart; 315 pPart.m_rtPart = m_rtMinBtn; 316 pPart.m_pWidget = m_pInterface; 317 pPart.m_iPart = FWL_PART_SCB_ForeArrow; 318 pPart.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) 319 ? FWL_PARTSTATE_SCB_Disabled 320 : m_iMinButtonState; 321 pTheme->GetPartRect(&pPart, rect); 322 } else { 323 rect.left = m_rtClient.left; 324 rect.top = m_rtClient.top; 325 rect.width = IsVertical() ? m_rtClient.width : m_fButtonLen; 326 rect.height = IsVertical() ? m_fButtonLen : m_rtClient.height; 327 } 328 } 329 void CFWL_ScrollBarImp::CalcMaxButtonRect(CFX_RectF& rect) { 330 if (m_bCustomLayout) { 331 IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider; 332 CFWL_ThemePart pPart; 333 pPart.m_rtPart = m_rtMaxBtn; 334 pPart.m_pWidget = m_pInterface; 335 pPart.m_iPart = FWL_PART_SCB_BackArrow; 336 pPart.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) 337 ? FWL_PARTSTATE_SCB_Disabled 338 : m_iMaxButtonState; 339 pTheme->GetPartRect(&pPart, rect); 340 } else { 341 rect.left = 342 IsVertical() ? m_rtClient.left : m_rtClient.right() - m_fButtonLen; 343 rect.top = 344 IsVertical() ? m_rtClient.bottom() - m_fButtonLen : m_rtClient.top; 345 rect.width = IsVertical() ? m_rtClient.width : m_fButtonLen; 346 rect.height = IsVertical() ? m_fButtonLen : m_rtClient.height; 347 } 348 } 349 void CFWL_ScrollBarImp::CalcThumbButtonRect(CFX_RectF& rect) { 350 if (!IsEnabled()) { 351 m_rtThumb.Reset(); 352 return; 353 } 354 if (m_bMinSize) { 355 m_rtThumb.Empty(); 356 return; 357 } 358 FX_FLOAT fRange = m_fRangeMax - m_fRangeMin; 359 memset(&rect, 0, sizeof(CFX_Rect)); 360 if (fRange < 0) { 361 if (IsVertical()) { 362 rect.Set(m_rtClient.left, m_rtMaxBtn.bottom(), m_rtClient.width, 0); 363 } else { 364 rect.Set(m_rtMaxBtn.right(), m_rtClient.top, 0, m_rtClient.height); 365 } 366 return; 367 } 368 CFX_RectF rtClient = m_rtClient; 369 FX_FLOAT fLength = IsVertical() ? rtClient.height : rtClient.width; 370 FX_FLOAT fSize = m_fButtonLen; 371 if (m_bCustomLayout) { 372 if (IsVertical()) { 373 fLength = fLength - m_rtMinBtn.height - m_rtMaxBtn.height; 374 if (fLength < m_rtMinBtn.height || fLength < m_rtMaxBtn.height) { 375 fLength = 0.0f; 376 } 377 } else { 378 fLength = fLength - m_rtMinBtn.width - m_rtMaxBtn.width; 379 if (fLength < m_rtMinBtn.width || fLength < m_rtMaxBtn.width) { 380 fLength = 0.0f; 381 } 382 } 383 } else { 384 fLength -= fSize * 2.0f; 385 if (fLength < fSize) { 386 fLength = 0.0f; 387 } 388 } 389 FX_FLOAT fThumbSize = fLength * fLength / (fRange + fLength); 390 if (fThumbSize < m_fMinThumb) { 391 fThumbSize = m_fMinThumb; 392 } 393 FX_FLOAT fDiff = fLength - fThumbSize; 394 if (fDiff < 0.0f) { 395 fDiff = 0.0f; 396 } 397 FX_FLOAT fTrackPos = m_fTrackPos; 398 if (fTrackPos > m_fRangeMax) { 399 fTrackPos = m_fRangeMax; 400 } 401 if (fTrackPos < m_fRangeMin) { 402 fTrackPos = m_fRangeMin; 403 } 404 if (!fRange) 405 return; 406 if (m_bCustomLayout) { 407 FX_FLOAT iPos = fDiff * (fTrackPos - m_fRangeMin) / fRange; 408 rect.left = rtClient.left; 409 if (!IsVertical()) { 410 if ((m_rtMinBtn.right() == m_rtMaxBtn.left && m_rtMinBtn.width > 0 && 411 m_rtMaxBtn.width > 0) || 412 (0 == m_rtMinBtn.width && 0 == m_rtMaxBtn.width)) { 413 rect.left += iPos; 414 } else { 415 rect.left += m_rtMinBtn.right() + iPos; 416 } 417 } 418 rect.top = rtClient.top; 419 if (IsVertical()) { 420 if ((m_rtMinBtn.bottom() == m_rtMaxBtn.top && m_rtMinBtn.height > 0 && 421 m_rtMaxBtn.height > 0) || 422 (0 == m_rtMinBtn.height && 0 == m_rtMaxBtn.height)) { 423 rect.top += iPos; 424 } else { 425 rect.top += m_rtMinBtn.bottom() + iPos; 426 } 427 } 428 rect.width = IsVertical() ? rtClient.width : fThumbSize; 429 rect.height = IsVertical() ? fThumbSize : rtClient.height; 430 } else { 431 FX_FLOAT iPos = fSize + fDiff * (fTrackPos - m_fRangeMin) / fRange; 432 rect.left = rtClient.left; 433 if (!IsVertical()) { 434 rect.left += iPos; 435 } 436 rect.top = rtClient.top; 437 if (IsVertical()) { 438 rect.top += iPos; 439 } 440 rect.width = IsVertical() ? rtClient.width : fThumbSize; 441 rect.height = IsVertical() ? fThumbSize : rtClient.height; 442 } 443 } 444 void CFWL_ScrollBarImp::CalcMinTrackRect(CFX_RectF& rect) { 445 if (m_bMinSize) { 446 rect.Empty(); 447 return; 448 } 449 FX_FLOAT fBottom = m_rtThumb.bottom(); 450 FX_FLOAT fRight = m_rtThumb.right(); 451 FX_FLOAT ix = (m_rtThumb.left + fRight) / 2; 452 FX_FLOAT iy = (m_rtThumb.top + fBottom) / 2; 453 rect.left = m_rtClient.left; 454 rect.top = m_rtClient.top; 455 FX_BOOL bVertical = IsVertical(); 456 rect.width = bVertical ? m_rtClient.width : ix; 457 rect.height = bVertical ? iy : m_rtClient.height; 458 if (m_bCustomLayout) { 459 if (bVertical) { 460 if (0 == m_rtMinBtn.height && 0 == m_rtMaxBtn.height) { 461 rect.top = m_rtClient.top; 462 } else if (m_rtMinBtn.top < m_rtThumb.top) { 463 rect.top = m_rtMinBtn.bottom(); 464 rect.height -= (m_rtMinBtn.bottom() - m_rtClient.top); 465 } 466 } else { 467 if (0 == m_rtMinBtn.width && 0 == m_rtMaxBtn.width) { 468 rect.left = m_rtClient.left; 469 } else if (m_rtMinBtn.left < m_rtThumb.left) { 470 rect.left = m_rtMinBtn.right(); 471 rect.width -= (m_rtMinBtn.right() - m_rtClient.left); 472 } 473 } 474 } 475 } 476 void CFWL_ScrollBarImp::CalcMaxTrackRect(CFX_RectF& rect) { 477 if (m_bMinSize) { 478 rect.Empty(); 479 return; 480 } 481 FX_FLOAT ix = (m_rtThumb.left + m_rtThumb.right()) / 2; 482 FX_FLOAT iy = (m_rtThumb.top + m_rtThumb.bottom()) / 2; 483 FX_BOOL bVertical = IsVertical(); 484 rect.left = bVertical ? m_rtClient.left : ix; 485 rect.top = bVertical ? iy : m_rtClient.top; 486 rect.width = bVertical ? m_rtClient.width : m_rtClient.right() - ix; 487 rect.height = bVertical ? m_rtClient.bottom() - iy : m_rtClient.height; 488 if (m_bCustomLayout) { 489 if (bVertical) { 490 if (m_rtMinBtn.top > m_rtThumb.top && m_rtMinBtn.height > 0 && 491 m_rtMaxBtn.height > 0) { 492 rect.height -= (m_rtClient.bottom() - m_rtMinBtn.top); 493 } else if (m_rtMinBtn.height > 0 && m_rtMaxBtn.height > 0) { 494 rect.height -= (m_rtClient.bottom() - m_rtMaxBtn.top); 495 } 496 } else { 497 if (m_rtMinBtn.left > m_rtThumb.left && m_rtMinBtn.width > 0 && 498 m_rtMaxBtn.width > 0) { 499 rect.width -= (m_rtClient.right() - m_rtMinBtn.left); 500 } else if (m_rtMinBtn.width > 0 && m_rtMaxBtn.width > 0) { 501 rect.width -= (m_rtClient.right() - m_rtMaxBtn.left); 502 } 503 } 504 } 505 } 506 FX_FLOAT CFWL_ScrollBarImp::GetTrackPointPos(FX_FLOAT fx, FX_FLOAT fy) { 507 FX_FLOAT fDiffX = fx - m_cpTrackPointX; 508 FX_FLOAT fDiffY = fy - m_cpTrackPointY; 509 FX_FLOAT fRange = m_fRangeMax - m_fRangeMin; 510 FX_FLOAT fPos; 511 if (m_bCustomLayout) { 512 if (IsVertical()) { 513 if (0 == m_rtMinBtn.height && 0 == m_rtMaxBtn.height) { 514 fPos = fRange * fDiffY / (m_rtClient.height - m_rtThumb.height); 515 } else if (m_rtMinBtn.bottom() == m_rtMaxBtn.top) { 516 fPos = fRange * fDiffY / 517 (m_rtMinBtn.top - m_rtClient.top - m_rtThumb.height); 518 } else { 519 fPos = fRange * fDiffY / 520 (m_rtMaxBtn.top - m_rtMinBtn.bottom() - m_rtThumb.height); 521 } 522 } else { 523 if (0 == m_rtMinBtn.width && 0 == m_rtMaxBtn.width) { 524 fPos = fRange * fDiffX / (m_rtClient.width - m_rtThumb.width); 525 } else if (m_rtMinBtn.right() == m_rtMaxBtn.left) { 526 fPos = fRange * fDiffX / 527 (m_rtMinBtn.left - m_rtClient.left - m_rtThumb.width); 528 } else { 529 fPos = fRange * fDiffX / 530 (m_rtMaxBtn.left - m_rtMinBtn.right() - m_rtThumb.width); 531 } 532 } 533 } else { 534 if (IsVertical()) { 535 fPos = fRange * fDiffY / 536 (m_rtMaxBtn.top - m_rtMinBtn.bottom() - m_rtThumb.height); 537 } else { 538 fPos = fRange * fDiffX / 539 (m_rtMaxBtn.left - m_rtMinBtn.right() - m_rtThumb.width); 540 } 541 } 542 fPos += m_fLastTrackPos; 543 if (fPos < m_fRangeMin) { 544 fPos = m_fRangeMin; 545 } 546 if (fPos > m_fRangeMax) { 547 fPos = m_fRangeMax; 548 } 549 return fPos; 550 } 551 void CFWL_ScrollBarImp::GetTrackRect(CFX_RectF& rect, FX_BOOL bLower) { 552 FX_BOOL bDisabled = m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled; 553 if (bDisabled || m_bCustomLayout) { 554 rect = bLower ? m_rtMinTrack : m_rtMaxTrack; 555 } else { 556 FX_FLOAT fW = m_rtThumb.width / 2; 557 FX_FLOAT fH = m_rtThumb.height / 2; 558 FX_BOOL bVert = IsVertical(); 559 if (bLower) { 560 if (bVert) { 561 FX_FLOAT fMinTrackHeight = m_rtMinTrack.height - fH - m_rtMinBtn.height; 562 fMinTrackHeight = (fMinTrackHeight >= 0.0f) ? fMinTrackHeight : 0.0f; 563 rect.Set(m_rtMinTrack.left, m_rtMinTrack.top + m_rtMinBtn.height, 564 m_rtMinTrack.width, fMinTrackHeight); 565 } else { 566 FX_FLOAT fMinTrackWidth = 567 m_rtMinTrack.width - fW - m_rtMinBtn.width + 2; 568 fMinTrackWidth = (fMinTrackWidth >= 0.0f) ? fMinTrackWidth : 0.0f; 569 rect.Set(m_rtMinTrack.left + m_rtMinBtn.width - 1, m_rtMinTrack.top, 570 fMinTrackWidth, m_rtMinTrack.height); 571 } 572 } else { 573 if (bVert) { 574 FX_FLOAT fMaxTrackHeight = m_rtMaxTrack.height - fH - m_rtMaxBtn.height; 575 fMaxTrackHeight = (fMaxTrackHeight >= 0.0f) ? fMaxTrackHeight : 0.0f; 576 rect.Set(m_rtMaxTrack.left, m_rtMaxTrack.top + fH, m_rtMaxTrack.width, 577 fMaxTrackHeight); 578 } else { 579 FX_FLOAT fMaxTrackWidth = 580 m_rtMaxTrack.width - fW - m_rtMaxBtn.width + 2; 581 fMaxTrackWidth = (fMaxTrackWidth >= 0.0f) ? fMaxTrackWidth : 0.0f; 582 rect.Set(m_rtMaxTrack.left + fW, m_rtMaxTrack.top, fMaxTrackWidth, 583 m_rtMaxTrack.height); 584 } 585 } 586 } 587 } 588 FX_BOOL CFWL_ScrollBarImp::SendEvent() { 589 if (m_iMinButtonState == FWL_PARTSTATE_SCB_Pressed) { 590 DoScroll(FWL_SCBCODE_StepBackward, m_fTrackPos); 591 return FALSE; 592 } 593 if (m_iMaxButtonState == FWL_PARTSTATE_SCB_Pressed) { 594 DoScroll(FWL_SCBCODE_StepForward, m_fTrackPos); 595 return FALSE; 596 } 597 if (m_iMinTrackState == FWL_PARTSTATE_SCB_Pressed) { 598 DoScroll(FWL_SCBCODE_PageBackward, m_fTrackPos); 599 return m_rtThumb.Contains(m_cpTrackPointX, m_cpTrackPointY); 600 } 601 if (m_iMaxTrackState == FWL_PARTSTATE_SCB_Pressed) { 602 DoScroll(FWL_SCBCODE_PageForward, m_fTrackPos); 603 return m_rtThumb.Contains(m_cpTrackPointX, m_cpTrackPointY); 604 } 605 if (m_iMouseWheel) { 606 FX_WORD dwCode = 607 m_iMouseWheel < 0 ? FWL_SCBCODE_StepForward : FWL_SCBCODE_StepBackward; 608 DoScroll(dwCode, m_fTrackPos); 609 } 610 return TRUE; 611 } 612 FX_BOOL CFWL_ScrollBarImp::OnScroll(FX_DWORD dwCode, FX_FLOAT fPos) { 613 FX_BOOL bRet = TRUE; 614 CFWL_EvtScroll ev; 615 ev.m_iScrollCode = dwCode; 616 ev.m_pSrcTarget = m_pInterface; 617 ev.m_fPos = fPos; 618 ev.m_pRet = &bRet; 619 DispatchEvent(&ev); 620 return bRet; 621 } 622 CFWL_ScrollBarImpDelegate::CFWL_ScrollBarImpDelegate(CFWL_ScrollBarImp* pOwner) 623 : m_pOwner(pOwner) {} 624 int32_t CFWL_ScrollBarImpDelegate::OnProcessMessage(CFWL_Message* pMessage) { 625 if (!pMessage) 626 return 0; 627 int32_t iRet = 1; 628 FX_DWORD dwMsgCode = pMessage->GetClassID(); 629 if (dwMsgCode == FWL_MSGHASH_Mouse) { 630 CFWL_MsgMouse* pMsg = static_cast<CFWL_MsgMouse*>(pMessage); 631 FX_DWORD dwCmd = pMsg->m_dwCmd; 632 switch (dwCmd) { 633 case FWL_MSGMOUSECMD_LButtonDown: { 634 OnLButtonDown(pMsg->m_dwFlags, pMsg->m_fx, pMsg->m_fy); 635 break; 636 } 637 case FWL_MSGMOUSECMD_LButtonUp: { 638 OnLButtonUp(pMsg->m_dwFlags, pMsg->m_fx, pMsg->m_fy); 639 break; 640 } 641 case FWL_MSGMOUSECMD_MouseMove: { 642 OnMouseMove(pMsg->m_dwFlags, pMsg->m_fx, pMsg->m_fy); 643 break; 644 } 645 case FWL_MSGMOUSECMD_MouseLeave: { 646 OnMouseLeave(); 647 break; 648 } 649 default: { iRet = 0; } 650 } 651 } else if (dwMsgCode == FWL_MSGHASH_MouseWheel) { 652 CFWL_MsgMouseWheel* pMsg = static_cast<CFWL_MsgMouseWheel*>(pMessage); 653 OnMouseWheel(pMsg->m_fx, pMsg->m_fy, pMsg->m_dwFlags, pMsg->m_fDeltaX, 654 pMsg->m_fDeltaY); 655 } else { 656 iRet = 0; 657 } 658 return iRet; 659 } 660 FWL_ERR CFWL_ScrollBarImpDelegate::OnDrawWidget(CFX_Graphics* pGraphics, 661 const CFX_Matrix* pMatrix) { 662 return m_pOwner->DrawWidget(pGraphics, pMatrix); 663 } 664 void CFWL_ScrollBarImpDelegate::OnLButtonDown(FX_DWORD dwFlags, 665 FX_FLOAT fx, 666 FX_FLOAT fy) { 667 if (!m_pOwner->IsEnabled()) { 668 return; 669 } 670 m_pOwner->m_bMouseDown = TRUE; 671 m_pOwner->SetGrab(TRUE); 672 m_pOwner->m_cpTrackPointX = fx; 673 m_pOwner->m_cpTrackPointY = fy; 674 m_pOwner->m_fLastTrackPos = m_pOwner->m_fTrackPos; 675 if (m_pOwner->m_rtMinBtn.Contains(fx, fy)) { 676 DoMouseDown(0, m_pOwner->m_rtMinBtn, m_pOwner->m_iMinButtonState, fx, fy); 677 } else { 678 if (m_pOwner->m_rtThumb.Contains(fx, fy)) { 679 DoMouseDown(1, m_pOwner->m_rtThumb, m_pOwner->m_iThumbButtonState, fx, 680 fy); 681 } else { 682 if (m_pOwner->m_rtMaxBtn.Contains(fx, fy)) { 683 DoMouseDown(2, m_pOwner->m_rtMaxBtn, m_pOwner->m_iMaxButtonState, fx, 684 fy); 685 } else { 686 if (m_pOwner->m_rtMinTrack.Contains(fx, fy)) { 687 DoMouseDown(3, m_pOwner->m_rtMinTrack, m_pOwner->m_iMinTrackState, fx, 688 fy); 689 } else { 690 DoMouseDown(4, m_pOwner->m_rtMaxTrack, m_pOwner->m_iMaxTrackState, fx, 691 fy); 692 } 693 } 694 } 695 } 696 if (!m_pOwner->SendEvent()) { 697 m_pOwner->m_hTimer = FWL_StartTimer(m_pOwner, FWL_SCROLLBAR_Elapse); 698 } 699 } 700 void CFWL_ScrollBarImpDelegate::OnLButtonUp(FX_DWORD dwFlags, 701 FX_FLOAT fx, 702 FX_FLOAT fy) { 703 FWL_StopTimer(m_pOwner->m_hTimer); 704 m_pOwner->m_bMouseDown = FALSE; 705 DoMouseUp(0, m_pOwner->m_rtMinBtn, m_pOwner->m_iMinButtonState, fx, fy); 706 DoMouseUp(1, m_pOwner->m_rtThumb, m_pOwner->m_iThumbButtonState, fx, fy); 707 DoMouseUp(2, m_pOwner->m_rtMaxBtn, m_pOwner->m_iMaxButtonState, fx, fy); 708 DoMouseUp(3, m_pOwner->m_rtMinTrack, m_pOwner->m_iMinTrackState, fx, fy); 709 DoMouseUp(4, m_pOwner->m_rtMaxTrack, m_pOwner->m_iMaxTrackState, fx, fy); 710 m_pOwner->SetGrab(FALSE); 711 } 712 void CFWL_ScrollBarImpDelegate::OnMouseMove(FX_DWORD dwFlags, 713 FX_FLOAT fx, 714 FX_FLOAT fy) { 715 DoMouseMove(0, m_pOwner->m_rtMinBtn, m_pOwner->m_iMinButtonState, fx, fy); 716 DoMouseMove(1, m_pOwner->m_rtThumb, m_pOwner->m_iThumbButtonState, fx, fy); 717 DoMouseMove(2, m_pOwner->m_rtMaxBtn, m_pOwner->m_iMaxButtonState, fx, fy); 718 DoMouseMove(3, m_pOwner->m_rtMinTrack, m_pOwner->m_iMinTrackState, fx, fy); 719 DoMouseMove(4, m_pOwner->m_rtMaxTrack, m_pOwner->m_iMaxTrackState, fx, fy); 720 } 721 void CFWL_ScrollBarImpDelegate::OnMouseLeave() { 722 DoMouseLeave(0, m_pOwner->m_rtMinBtn, m_pOwner->m_iMinButtonState); 723 DoMouseLeave(1, m_pOwner->m_rtThumb, m_pOwner->m_iThumbButtonState); 724 DoMouseLeave(2, m_pOwner->m_rtMaxBtn, m_pOwner->m_iMaxButtonState); 725 DoMouseLeave(3, m_pOwner->m_rtMinTrack, m_pOwner->m_iMinTrackState); 726 DoMouseLeave(4, m_pOwner->m_rtMaxTrack, m_pOwner->m_iMaxTrackState); 727 } 728 void CFWL_ScrollBarImpDelegate::OnMouseWheel(FX_FLOAT fx, 729 FX_FLOAT fy, 730 FX_DWORD dwFlags, 731 FX_FLOAT fDeltaX, 732 FX_FLOAT fDeltaY) { 733 m_pOwner->m_iMouseWheel = (int32_t)fDeltaX; 734 m_pOwner->SendEvent(); 735 m_pOwner->m_iMouseWheel = 0; 736 } 737 void CFWL_ScrollBarImpDelegate::DoMouseDown(int32_t iItem, 738 const CFX_RectF& rtItem, 739 int32_t& iState, 740 FX_FLOAT fx, 741 FX_FLOAT fy) { 742 if (!rtItem.Contains(fx, fy)) { 743 return; 744 } 745 if (iState == FWL_PARTSTATE_SCB_Pressed) { 746 return; 747 } 748 iState = FWL_PARTSTATE_SCB_Pressed; 749 m_pOwner->Repaint(&rtItem); 750 } 751 void CFWL_ScrollBarImpDelegate::DoMouseUp(int32_t iItem, 752 const CFX_RectF& rtItem, 753 int32_t& iState, 754 FX_FLOAT fx, 755 FX_FLOAT fy) { 756 int32_t iNewState = rtItem.Contains(fx, fy) ? FWL_PARTSTATE_SCB_Hovered 757 : FWL_PARTSTATE_SCB_Normal; 758 if (iState == iNewState) { 759 return; 760 } 761 iState = iNewState; 762 m_pOwner->Repaint(&rtItem); 763 m_pOwner->OnScroll(FWL_SCBCODE_EndScroll, m_pOwner->m_fTrackPos); 764 } 765 void CFWL_ScrollBarImpDelegate::DoMouseMove(int32_t iItem, 766 const CFX_RectF& rtItem, 767 int32_t& iState, 768 FX_FLOAT fx, 769 FX_FLOAT fy) { 770 if (!m_pOwner->m_bMouseDown) { 771 int32_t iNewState = rtItem.Contains(fx, fy) ? FWL_PARTSTATE_SCB_Hovered 772 : FWL_PARTSTATE_SCB_Normal; 773 if (iState == iNewState) { 774 return; 775 } 776 iState = iNewState; 777 m_pOwner->Repaint(&rtItem); 778 } else if ((2 == iItem) && 779 (m_pOwner->m_iThumbButtonState == FWL_PARTSTATE_SCB_Pressed)) { 780 FX_FLOAT fPos = m_pOwner->GetTrackPointPos(fx, fy); 781 m_pOwner->m_fTrackPos = fPos; 782 m_pOwner->OnScroll(FWL_SCBCODE_TrackPos, fPos); 783 } 784 } 785 void CFWL_ScrollBarImpDelegate::DoMouseLeave(int32_t iItem, 786 const CFX_RectF& rtItem, 787 int32_t& iState) { 788 if (iState == FWL_PARTSTATE_SCB_Normal) { 789 return; 790 } 791 iState = FWL_PARTSTATE_SCB_Normal; 792 m_pOwner->Repaint(&rtItem); 793 } 794 void CFWL_ScrollBarImpDelegate::DoMouseHover(int32_t iItem, 795 const CFX_RectF& rtItem, 796 int32_t& iState) { 797 if (iState == FWL_PARTSTATE_SCB_Hovered) { 798 return; 799 } 800 iState = FWL_PARTSTATE_SCB_Hovered; 801 m_pOwner->Repaint(&rtItem); 802 } 803