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 "fpdfsdk/pdfwindow/PWL_ScrollBar.h" 8 9#include "core/fxge/cfx_pathdata.h" 10#include "core/fxge/cfx_renderdevice.h" 11#include "fpdfsdk/pdfwindow/PWL_Utils.h" 12#include "fpdfsdk/pdfwindow/PWL_Wnd.h" 13 14PWL_FLOATRANGE::PWL_FLOATRANGE() { 15 Default(); 16} 17 18PWL_FLOATRANGE::PWL_FLOATRANGE(FX_FLOAT min, FX_FLOAT max) { 19 Set(min, max); 20} 21 22void PWL_FLOATRANGE::Default() { 23 fMin = 0; 24 fMax = 0; 25} 26 27void PWL_FLOATRANGE::Set(FX_FLOAT min, FX_FLOAT max) { 28 if (min > max) { 29 fMin = max; 30 fMax = min; 31 } else { 32 fMin = min; 33 fMax = max; 34 } 35} 36 37bool PWL_FLOATRANGE::In(FX_FLOAT x) const { 38 return (IsFloatBigger(x, fMin) || IsFloatEqual(x, fMin)) && 39 (IsFloatSmaller(x, fMax) || IsFloatEqual(x, fMax)); 40} 41 42FX_FLOAT PWL_FLOATRANGE::GetWidth() const { 43 return fMax - fMin; 44} 45 46PWL_SCROLL_PRIVATEDATA::PWL_SCROLL_PRIVATEDATA() { 47 Default(); 48} 49 50void PWL_SCROLL_PRIVATEDATA::Default() { 51 ScrollRange.Default(); 52 fScrollPos = ScrollRange.fMin; 53 fClientWidth = 0; 54 fBigStep = 10; 55 fSmallStep = 1; 56} 57 58void PWL_SCROLL_PRIVATEDATA::SetScrollRange(FX_FLOAT min, FX_FLOAT max) { 59 ScrollRange.Set(min, max); 60 61 if (IsFloatSmaller(fScrollPos, ScrollRange.fMin)) 62 fScrollPos = ScrollRange.fMin; 63 if (IsFloatBigger(fScrollPos, ScrollRange.fMax)) 64 fScrollPos = ScrollRange.fMax; 65} 66 67void PWL_SCROLL_PRIVATEDATA::SetClientWidth(FX_FLOAT width) { 68 fClientWidth = width; 69} 70 71void PWL_SCROLL_PRIVATEDATA::SetSmallStep(FX_FLOAT step) { 72 fSmallStep = step; 73} 74 75void PWL_SCROLL_PRIVATEDATA::SetBigStep(FX_FLOAT step) { 76 fBigStep = step; 77} 78 79bool PWL_SCROLL_PRIVATEDATA::SetPos(FX_FLOAT pos) { 80 if (ScrollRange.In(pos)) { 81 fScrollPos = pos; 82 return true; 83 } 84 return false; 85} 86 87void PWL_SCROLL_PRIVATEDATA::AddSmall() { 88 if (!SetPos(fScrollPos + fSmallStep)) 89 SetPos(ScrollRange.fMax); 90} 91 92void PWL_SCROLL_PRIVATEDATA::SubSmall() { 93 if (!SetPos(fScrollPos - fSmallStep)) 94 SetPos(ScrollRange.fMin); 95} 96 97void PWL_SCROLL_PRIVATEDATA::AddBig() { 98 if (!SetPos(fScrollPos + fBigStep)) 99 SetPos(ScrollRange.fMax); 100} 101 102void PWL_SCROLL_PRIVATEDATA::SubBig() { 103 if (!SetPos(fScrollPos - fBigStep)) 104 SetPos(ScrollRange.fMin); 105} 106 107CPWL_SBButton::CPWL_SBButton(PWL_SCROLLBAR_TYPE eScrollBarType, 108 PWL_SBBUTTON_TYPE eButtonType) { 109 m_eScrollBarType = eScrollBarType; 110 m_eSBButtonType = eButtonType; 111 112 m_bMouseDown = false; 113} 114 115CPWL_SBButton::~CPWL_SBButton() {} 116 117CFX_ByteString CPWL_SBButton::GetClassName() const { 118 return "CPWL_SBButton"; 119} 120 121void CPWL_SBButton::OnCreate(PWL_CREATEPARAM& cp) { 122 cp.eCursorType = FXCT_ARROW; 123} 124 125void CPWL_SBButton::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) { 126 CPWL_Wnd::GetThisAppearanceStream(sAppStream); 127 128 if (!IsVisible()) 129 return; 130 131 CFX_ByteTextBuf sButton; 132 133 CFX_FloatRect rectWnd = GetWindowRect(); 134 135 if (rectWnd.IsEmpty()) 136 return; 137 138 sAppStream << "q\n"; 139 140 CFX_PointF ptCenter = GetCenterPoint(); 141 142 switch (m_eScrollBarType) { 143 case SBT_HSCROLL: 144 switch (m_eSBButtonType) { 145 case PSBT_MIN: { 146 CFX_PointF pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f, ptCenter.y); 147 CFX_PointF pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f, 148 ptCenter.y + PWL_TRIANGLE_HALFLEN); 149 CFX_PointF pt3(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f, 150 ptCenter.y - PWL_TRIANGLE_HALFLEN); 151 152 if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 && 153 rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) { 154 sButton << "0 g\n"; 155 sButton << pt1.x << " " << pt1.y << " m\n"; 156 sButton << pt2.x << " " << pt2.y << " l\n"; 157 sButton << pt3.x << " " << pt3.y << " l\n"; 158 sButton << pt1.x << " " << pt1.y << " l f\n"; 159 160 sAppStream << sButton; 161 } 162 } break; 163 case PSBT_MAX: { 164 CFX_PointF pt1(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f, ptCenter.y); 165 CFX_PointF pt2(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f, 166 ptCenter.y + PWL_TRIANGLE_HALFLEN); 167 CFX_PointF pt3(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f, 168 ptCenter.y - PWL_TRIANGLE_HALFLEN); 169 170 if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 && 171 rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) { 172 sButton << "0 g\n"; 173 sButton << pt1.x << " " << pt1.y << " m\n"; 174 sButton << pt2.x << " " << pt2.y << " l\n"; 175 sButton << pt3.x << " " << pt3.y << " l\n"; 176 sButton << pt1.x << " " << pt1.y << " l f\n"; 177 178 sAppStream << sButton; 179 } 180 } break; 181 default: 182 break; 183 } 184 break; 185 case SBT_VSCROLL: 186 switch (m_eSBButtonType) { 187 case PSBT_MIN: { 188 CFX_PointF pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN, 189 ptCenter.y - PWL_TRIANGLE_HALFLEN * 0.5f); 190 CFX_PointF pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN, 191 ptCenter.y - PWL_TRIANGLE_HALFLEN * 0.5f); 192 CFX_PointF pt3(ptCenter.x, ptCenter.y + PWL_TRIANGLE_HALFLEN * 0.5f); 193 194 if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 && 195 rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) { 196 sButton << "0 g\n"; 197 sButton << pt1.x << " " << pt1.y << " m\n"; 198 sButton << pt2.x << " " << pt2.y << " l\n"; 199 sButton << pt3.x << " " << pt3.y << " l\n"; 200 sButton << pt1.x << " " << pt1.y << " l f\n"; 201 202 sAppStream << sButton; 203 } 204 } break; 205 case PSBT_MAX: { 206 CFX_PointF pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN, 207 ptCenter.y + PWL_TRIANGLE_HALFLEN * 0.5f); 208 CFX_PointF pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN, 209 ptCenter.y + PWL_TRIANGLE_HALFLEN * 0.5f); 210 CFX_PointF pt3(ptCenter.x, ptCenter.y - PWL_TRIANGLE_HALFLEN * 0.5f); 211 212 if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 && 213 rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) { 214 sButton << "0 g\n"; 215 sButton << pt1.x << " " << pt1.y << " m\n"; 216 sButton << pt2.x << " " << pt2.y << " l\n"; 217 sButton << pt3.x << " " << pt3.y << " l\n"; 218 sButton << pt1.x << " " << pt1.y << " l f\n"; 219 220 sAppStream << sButton; 221 } 222 } break; 223 default: 224 break; 225 } 226 break; 227 default: 228 break; 229 } 230 231 sAppStream << "Q\n"; 232} 233 234void CPWL_SBButton::DrawThisAppearance(CFX_RenderDevice* pDevice, 235 CFX_Matrix* pUser2Device) { 236 if (!IsVisible()) 237 return; 238 239 CFX_FloatRect rectWnd = GetWindowRect(); 240 if (rectWnd.IsEmpty()) 241 return; 242 243 CFX_PointF ptCenter = GetCenterPoint(); 244 int32_t nTransparency = GetTransparency(); 245 246 switch (m_eScrollBarType) { 247 case SBT_HSCROLL: 248 CPWL_Wnd::DrawThisAppearance(pDevice, pUser2Device); 249 switch (m_eSBButtonType) { 250 case PSBT_MIN: { 251 CFX_PointF pt1(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f, ptCenter.y); 252 CFX_PointF pt2(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f, 253 ptCenter.y + PWL_TRIANGLE_HALFLEN); 254 CFX_PointF pt3(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f, 255 ptCenter.y - PWL_TRIANGLE_HALFLEN); 256 257 if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 && 258 rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) { 259 CFX_PathData path; 260 path.AppendPoint(pt1, FXPT_TYPE::MoveTo, false); 261 path.AppendPoint(pt2, FXPT_TYPE::LineTo, false); 262 path.AppendPoint(pt3, FXPT_TYPE::LineTo, false); 263 path.AppendPoint(pt1, FXPT_TYPE::LineTo, false); 264 265 pDevice->DrawPath(&path, pUser2Device, nullptr, 266 PWL_DEFAULT_BLACKCOLOR.ToFXColor(nTransparency), 267 0, FXFILL_ALTERNATE); 268 } 269 } break; 270 case PSBT_MAX: { 271 CFX_PointF pt1(ptCenter.x + PWL_TRIANGLE_HALFLEN * 0.5f, ptCenter.y); 272 CFX_PointF pt2(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f, 273 ptCenter.y + PWL_TRIANGLE_HALFLEN); 274 CFX_PointF pt3(ptCenter.x - PWL_TRIANGLE_HALFLEN * 0.5f, 275 ptCenter.y - PWL_TRIANGLE_HALFLEN); 276 277 if (rectWnd.right - rectWnd.left > PWL_TRIANGLE_HALFLEN * 2 && 278 rectWnd.top - rectWnd.bottom > PWL_TRIANGLE_HALFLEN) { 279 CFX_PathData path; 280 path.AppendPoint(pt1, FXPT_TYPE::MoveTo, false); 281 path.AppendPoint(pt2, FXPT_TYPE::LineTo, false); 282 path.AppendPoint(pt3, FXPT_TYPE::LineTo, false); 283 path.AppendPoint(pt1, FXPT_TYPE::LineTo, false); 284 285 pDevice->DrawPath(&path, pUser2Device, nullptr, 286 PWL_DEFAULT_BLACKCOLOR.ToFXColor(nTransparency), 287 0, FXFILL_ALTERNATE); 288 } 289 } break; 290 default: 291 break; 292 } 293 break; 294 case SBT_VSCROLL: 295 switch (m_eSBButtonType) { 296 case PSBT_MIN: { 297 // draw border 298 CFX_FloatRect rcDraw = rectWnd; 299 CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw, 300 ArgbEncode(nTransparency, 100, 100, 100), 301 0.0f); 302 303 // draw inner border 304 rcDraw = CPWL_Utils::DeflateRect(rectWnd, 0.5f); 305 CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw, 306 ArgbEncode(nTransparency, 255, 255, 255), 307 1.0f); 308 309 // draw background 310 311 rcDraw = CPWL_Utils::DeflateRect(rectWnd, 1.0f); 312 313 if (IsEnabled()) 314 CPWL_Utils::DrawShadow(pDevice, pUser2Device, true, false, rcDraw, 315 nTransparency, 80, 220); 316 else 317 CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcDraw, 318 ArgbEncode(255, 255, 255, 255)); 319 320 // draw arrow 321 322 if (rectWnd.top - rectWnd.bottom > 6.0f) { 323 FX_FLOAT fX = rectWnd.left + 1.5f; 324 FX_FLOAT fY = rectWnd.bottom; 325 CFX_PointF pts[7] = {CFX_PointF(fX + 2.5f, fY + 4.0f), 326 CFX_PointF(fX + 2.5f, fY + 3.0f), 327 CFX_PointF(fX + 4.5f, fY + 5.0f), 328 CFX_PointF(fX + 6.5f, fY + 3.0f), 329 CFX_PointF(fX + 6.5f, fY + 4.0f), 330 CFX_PointF(fX + 4.5f, fY + 6.0f), 331 CFX_PointF(fX + 2.5f, fY + 4.0f)}; 332 333 if (IsEnabled()) 334 CPWL_Utils::DrawFillArea( 335 pDevice, pUser2Device, pts, 7, 336 ArgbEncode(nTransparency, 255, 255, 255)); 337 else 338 CPWL_Utils::DrawFillArea( 339 pDevice, pUser2Device, pts, 7, 340 PWL_DEFAULT_HEAVYGRAYCOLOR.ToFXColor(255)); 341 } 342 } break; 343 case PSBT_MAX: { 344 // draw border 345 CFX_FloatRect rcDraw = rectWnd; 346 CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw, 347 ArgbEncode(nTransparency, 100, 100, 100), 348 0.0f); 349 350 // draw inner border 351 rcDraw = CPWL_Utils::DeflateRect(rectWnd, 0.5f); 352 CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw, 353 ArgbEncode(nTransparency, 255, 255, 255), 354 1.0f); 355 356 // draw background 357 rcDraw = CPWL_Utils::DeflateRect(rectWnd, 1.0f); 358 if (IsEnabled()) 359 CPWL_Utils::DrawShadow(pDevice, pUser2Device, true, false, rcDraw, 360 nTransparency, 80, 220); 361 else 362 CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcDraw, 363 ArgbEncode(255, 255, 255, 255)); 364 365 // draw arrow 366 367 if (rectWnd.top - rectWnd.bottom > 6.0f) { 368 FX_FLOAT fX = rectWnd.left + 1.5f; 369 FX_FLOAT fY = rectWnd.bottom; 370 371 CFX_PointF pts[7] = {CFX_PointF(fX + 2.5f, fY + 5.0f), 372 CFX_PointF(fX + 2.5f, fY + 6.0f), 373 CFX_PointF(fX + 4.5f, fY + 4.0f), 374 CFX_PointF(fX + 6.5f, fY + 6.0f), 375 CFX_PointF(fX + 6.5f, fY + 5.0f), 376 CFX_PointF(fX + 4.5f, fY + 3.0f), 377 CFX_PointF(fX + 2.5f, fY + 5.0f)}; 378 379 if (IsEnabled()) 380 CPWL_Utils::DrawFillArea( 381 pDevice, pUser2Device, pts, 7, 382 ArgbEncode(nTransparency, 255, 255, 255)); 383 else 384 CPWL_Utils::DrawFillArea( 385 pDevice, pUser2Device, pts, 7, 386 PWL_DEFAULT_HEAVYGRAYCOLOR.ToFXColor(255)); 387 } 388 } break; 389 case PSBT_POS: { 390 // draw border 391 CFX_FloatRect rcDraw = rectWnd; 392 CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw, 393 ArgbEncode(nTransparency, 100, 100, 100), 394 0.0f); 395 396 // draw inner border 397 rcDraw = CPWL_Utils::DeflateRect(rectWnd, 0.5f); 398 CPWL_Utils::DrawStrokeRect(pDevice, pUser2Device, rcDraw, 399 ArgbEncode(nTransparency, 255, 255, 255), 400 1.0f); 401 402 if (IsEnabled()) { 403 // draw shadow effect 404 405 CFX_PointF ptTop = CFX_PointF(rectWnd.left, rectWnd.top - 1.0f); 406 CFX_PointF ptBottom = 407 CFX_PointF(rectWnd.left, rectWnd.bottom + 1.0f); 408 409 ptTop.x += 1.5f; 410 ptBottom.x += 1.5f; 411 412 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom, 413 ArgbEncode(nTransparency, 210, 210, 210), 414 1.0f); 415 416 ptTop.x += 1.0f; 417 ptBottom.x += 1.0f; 418 419 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom, 420 ArgbEncode(nTransparency, 220, 220, 220), 421 1.0f); 422 423 ptTop.x += 1.0f; 424 ptBottom.x += 1.0f; 425 426 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom, 427 ArgbEncode(nTransparency, 240, 240, 240), 428 1.0f); 429 430 ptTop.x += 1.0f; 431 ptBottom.x += 1.0f; 432 433 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom, 434 ArgbEncode(nTransparency, 240, 240, 240), 435 1.0f); 436 437 ptTop.x += 1.0f; 438 ptBottom.x += 1.0f; 439 440 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom, 441 ArgbEncode(nTransparency, 210, 210, 210), 442 1.0f); 443 444 ptTop.x += 1.0f; 445 ptBottom.x += 1.0f; 446 447 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom, 448 ArgbEncode(nTransparency, 180, 180, 180), 449 1.0f); 450 451 ptTop.x += 1.0f; 452 ptBottom.x += 1.0f; 453 454 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom, 455 ArgbEncode(nTransparency, 150, 150, 150), 456 1.0f); 457 458 ptTop.x += 1.0f; 459 ptBottom.x += 1.0f; 460 461 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom, 462 ArgbEncode(nTransparency, 150, 150, 150), 463 1.0f); 464 465 ptTop.x += 1.0f; 466 ptBottom.x += 1.0f; 467 468 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom, 469 ArgbEncode(nTransparency, 180, 180, 180), 470 1.0f); 471 472 ptTop.x += 1.0f; 473 ptBottom.x += 1.0f; 474 475 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptTop, ptBottom, 476 ArgbEncode(nTransparency, 210, 210, 210), 477 1.0f); 478 } else { 479 CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcDraw, 480 ArgbEncode(255, 255, 255, 255)); 481 } 482 483 // draw friction 484 485 if (rectWnd.Height() > 8.0f) { 486 FX_COLORREF crStroke = ArgbEncode(nTransparency, 120, 120, 120); 487 if (!IsEnabled()) 488 crStroke = PWL_DEFAULT_HEAVYGRAYCOLOR.ToFXColor(255); 489 490 FX_FLOAT nFrictionWidth = 5.0f; 491 FX_FLOAT nFrictionHeight = 5.5f; 492 493 CFX_PointF ptLeft = 494 CFX_PointF(ptCenter.x - nFrictionWidth / 2.0f, 495 ptCenter.y - nFrictionHeight / 2.0f + 0.5f); 496 CFX_PointF ptRight = 497 CFX_PointF(ptCenter.x + nFrictionWidth / 2.0f, 498 ptCenter.y - nFrictionHeight / 2.0f + 0.5f); 499 500 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptLeft, ptRight, 501 crStroke, 1.0f); 502 503 ptLeft.y += 2.0f; 504 ptRight.y += 2.0f; 505 506 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptLeft, ptRight, 507 crStroke, 1.0f); 508 509 ptLeft.y += 2.0f; 510 ptRight.y += 2.0f; 511 512 CPWL_Utils::DrawStrokeLine(pDevice, pUser2Device, ptLeft, ptRight, 513 crStroke, 1.0f); 514 } 515 } break; 516 default: 517 break; 518 } 519 break; 520 default: 521 break; 522 } 523} 524 525bool CPWL_SBButton::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) { 526 CPWL_Wnd::OnLButtonDown(point, nFlag); 527 528 if (CPWL_Wnd* pParent = GetParentWindow()) 529 pParent->OnNotify(this, PNM_LBUTTONDOWN, 0, (intptr_t)&point); 530 531 m_bMouseDown = true; 532 SetCapture(); 533 534 return true; 535} 536 537bool CPWL_SBButton::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) { 538 CPWL_Wnd::OnLButtonUp(point, nFlag); 539 540 if (CPWL_Wnd* pParent = GetParentWindow()) 541 pParent->OnNotify(this, PNM_LBUTTONUP, 0, (intptr_t)&point); 542 543 m_bMouseDown = false; 544 ReleaseCapture(); 545 546 return true; 547} 548 549bool CPWL_SBButton::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) { 550 CPWL_Wnd::OnMouseMove(point, nFlag); 551 552 if (CPWL_Wnd* pParent = GetParentWindow()) { 553 pParent->OnNotify(this, PNM_MOUSEMOVE, 0, (intptr_t)&point); 554 } 555 556 return true; 557} 558 559CPWL_ScrollBar::CPWL_ScrollBar(PWL_SCROLLBAR_TYPE sbType) 560 : m_sbType(sbType), 561 m_pMinButton(nullptr), 562 m_pMaxButton(nullptr), 563 m_pPosButton(nullptr), 564 m_bMouseDown(false), 565 m_bMinOrMax(false), 566 m_bNotifyForever(true) {} 567 568CPWL_ScrollBar::~CPWL_ScrollBar() {} 569 570CFX_ByteString CPWL_ScrollBar::GetClassName() const { 571 return "CPWL_ScrollBar"; 572} 573 574void CPWL_ScrollBar::OnCreate(PWL_CREATEPARAM& cp) { 575 cp.eCursorType = FXCT_ARROW; 576} 577 578void CPWL_ScrollBar::RePosChildWnd() { 579 CFX_FloatRect rcClient = GetClientRect(); 580 CFX_FloatRect rcMinButton, rcMaxButton; 581 FX_FLOAT fBWidth = 0; 582 583 switch (m_sbType) { 584 case SBT_HSCROLL: 585 if (rcClient.right - rcClient.left > 586 PWL_SCROLLBAR_BUTTON_WIDTH * 2 + PWL_SCROLLBAR_POSBUTTON_MINWIDTH + 587 2) { 588 rcMinButton = CFX_FloatRect(rcClient.left, rcClient.bottom, 589 rcClient.left + PWL_SCROLLBAR_BUTTON_WIDTH, 590 rcClient.top); 591 rcMaxButton = 592 CFX_FloatRect(rcClient.right - PWL_SCROLLBAR_BUTTON_WIDTH, 593 rcClient.bottom, rcClient.right, rcClient.top); 594 } else { 595 fBWidth = (rcClient.right - rcClient.left - 596 PWL_SCROLLBAR_POSBUTTON_MINWIDTH - 2) / 597 2; 598 599 if (fBWidth > 0) { 600 rcMinButton = CFX_FloatRect(rcClient.left, rcClient.bottom, 601 rcClient.left + fBWidth, rcClient.top); 602 rcMaxButton = CFX_FloatRect(rcClient.right - fBWidth, rcClient.bottom, 603 rcClient.right, rcClient.top); 604 } else { 605 SetVisible(false); 606 } 607 } 608 break; 609 case SBT_VSCROLL: 610 if (IsFloatBigger(rcClient.top - rcClient.bottom, 611 PWL_SCROLLBAR_BUTTON_WIDTH * 2 + 612 PWL_SCROLLBAR_POSBUTTON_MINWIDTH + 2)) { 613 rcMinButton = CFX_FloatRect(rcClient.left, 614 rcClient.top - PWL_SCROLLBAR_BUTTON_WIDTH, 615 rcClient.right, rcClient.top); 616 rcMaxButton = 617 CFX_FloatRect(rcClient.left, rcClient.bottom, rcClient.right, 618 rcClient.bottom + PWL_SCROLLBAR_BUTTON_WIDTH); 619 } else { 620 fBWidth = (rcClient.top - rcClient.bottom - 621 PWL_SCROLLBAR_POSBUTTON_MINWIDTH - 2) / 622 2; 623 624 if (IsFloatBigger(fBWidth, 0)) { 625 rcMinButton = CFX_FloatRect(rcClient.left, rcClient.top - fBWidth, 626 rcClient.right, rcClient.top); 627 rcMaxButton = 628 CFX_FloatRect(rcClient.left, rcClient.bottom, rcClient.right, 629 rcClient.bottom + fBWidth); 630 } else { 631 SetVisible(false); 632 } 633 } 634 break; 635 } 636 637 if (m_pMinButton) 638 m_pMinButton->Move(rcMinButton, true, false); 639 if (m_pMaxButton) 640 m_pMaxButton->Move(rcMaxButton, true, false); 641 MovePosButton(false); 642} 643 644void CPWL_ScrollBar::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) { 645 CFX_FloatRect rectWnd = GetWindowRect(); 646 647 if (IsVisible() && !rectWnd.IsEmpty()) { 648 CFX_ByteTextBuf sButton; 649 650 sButton << "q\n"; 651 sButton << "0 w\n" 652 << CPWL_Utils::GetColorAppStream(GetBackgroundColor(), true) 653 .AsStringC(); 654 sButton << rectWnd.left << " " << rectWnd.bottom << " " 655 << rectWnd.right - rectWnd.left << " " 656 << rectWnd.top - rectWnd.bottom << " re b Q\n"; 657 658 sAppStream << sButton; 659 } 660} 661 662void CPWL_ScrollBar::DrawThisAppearance(CFX_RenderDevice* pDevice, 663 CFX_Matrix* pUser2Device) { 664 CFX_FloatRect rectWnd = GetWindowRect(); 665 666 if (IsVisible() && !rectWnd.IsEmpty()) { 667 CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rectWnd, 668 GetBackgroundColor(), GetTransparency()); 669 670 CPWL_Utils::DrawStrokeLine( 671 pDevice, pUser2Device, 672 CFX_PointF(rectWnd.left + 2.0f, rectWnd.top - 2.0f), 673 CFX_PointF(rectWnd.left + 2.0f, rectWnd.bottom + 2.0f), 674 ArgbEncode(GetTransparency(), 100, 100, 100), 1.0f); 675 676 CPWL_Utils::DrawStrokeLine( 677 pDevice, pUser2Device, 678 CFX_PointF(rectWnd.right - 2.0f, rectWnd.top - 2.0f), 679 CFX_PointF(rectWnd.right - 2.0f, rectWnd.bottom + 2.0f), 680 ArgbEncode(GetTransparency(), 100, 100, 100), 1.0f); 681 } 682} 683 684bool CPWL_ScrollBar::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) { 685 CPWL_Wnd::OnLButtonDown(point, nFlag); 686 687 if (HasFlag(PWS_AUTOTRANSPARENT)) { 688 if (GetTransparency() != 255) { 689 SetTransparency(255); 690 InvalidateRect(); 691 } 692 } 693 694 CFX_FloatRect rcMinArea, rcMaxArea; 695 696 if (m_pPosButton && m_pPosButton->IsVisible()) { 697 CFX_FloatRect rcClient = GetClientRect(); 698 CFX_FloatRect rcPosButton = m_pPosButton->GetWindowRect(); 699 700 switch (m_sbType) { 701 case SBT_HSCROLL: 702 rcMinArea = 703 CFX_FloatRect(rcClient.left + PWL_SCROLLBAR_BUTTON_WIDTH, 704 rcClient.bottom, rcPosButton.left, rcClient.top); 705 rcMaxArea = CFX_FloatRect(rcPosButton.right, rcClient.bottom, 706 rcClient.right - PWL_SCROLLBAR_BUTTON_WIDTH, 707 rcClient.top); 708 709 break; 710 case SBT_VSCROLL: 711 rcMinArea = 712 CFX_FloatRect(rcClient.left, rcPosButton.top, rcClient.right, 713 rcClient.top - PWL_SCROLLBAR_BUTTON_WIDTH); 714 rcMaxArea = CFX_FloatRect(rcClient.left, 715 rcClient.bottom + PWL_SCROLLBAR_BUTTON_WIDTH, 716 rcClient.right, rcPosButton.bottom); 717 break; 718 } 719 720 rcMinArea.Normalize(); 721 rcMaxArea.Normalize(); 722 723 if (rcMinArea.Contains(point)) { 724 m_sData.SubBig(); 725 MovePosButton(true); 726 NotifyScrollWindow(); 727 } 728 729 if (rcMaxArea.Contains(point)) { 730 m_sData.AddBig(); 731 MovePosButton(true); 732 NotifyScrollWindow(); 733 } 734 } 735 736 return true; 737} 738 739bool CPWL_ScrollBar::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) { 740 CPWL_Wnd::OnLButtonUp(point, nFlag); 741 742 if (HasFlag(PWS_AUTOTRANSPARENT)) { 743 if (GetTransparency() != PWL_SCROLLBAR_TRANSPARENCY) { 744 SetTransparency(PWL_SCROLLBAR_TRANSPARENCY); 745 InvalidateRect(); 746 } 747 } 748 749 EndTimer(); 750 m_bMouseDown = false; 751 752 return true; 753} 754 755void CPWL_ScrollBar::OnNotify(CPWL_Wnd* pWnd, 756 uint32_t msg, 757 intptr_t wParam, 758 intptr_t lParam) { 759 CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam); 760 761 switch (msg) { 762 case PNM_LBUTTONDOWN: 763 if (pWnd == m_pMinButton) { 764 OnMinButtonLBDown(*(CFX_PointF*)lParam); 765 } 766 767 if (pWnd == m_pMaxButton) { 768 OnMaxButtonLBDown(*(CFX_PointF*)lParam); 769 } 770 771 if (pWnd == m_pPosButton) { 772 OnPosButtonLBDown(*(CFX_PointF*)lParam); 773 } 774 break; 775 case PNM_LBUTTONUP: 776 if (pWnd == m_pMinButton) { 777 OnMinButtonLBUp(*(CFX_PointF*)lParam); 778 } 779 780 if (pWnd == m_pMaxButton) { 781 OnMaxButtonLBUp(*(CFX_PointF*)lParam); 782 } 783 784 if (pWnd == m_pPosButton) { 785 OnPosButtonLBUp(*(CFX_PointF*)lParam); 786 } 787 break; 788 case PNM_MOUSEMOVE: 789 if (pWnd == m_pMinButton) { 790 OnMinButtonMouseMove(*(CFX_PointF*)lParam); 791 } 792 793 if (pWnd == m_pMaxButton) { 794 OnMaxButtonMouseMove(*(CFX_PointF*)lParam); 795 } 796 797 if (pWnd == m_pPosButton) { 798 OnPosButtonMouseMove(*(CFX_PointF*)lParam); 799 } 800 break; 801 case PNM_SETSCROLLINFO: { 802 PWL_SCROLL_INFO* pInfo = reinterpret_cast<PWL_SCROLL_INFO*>(lParam); 803 if (pInfo && *pInfo != m_OriginInfo) { 804 m_OriginInfo = *pInfo; 805 FX_FLOAT fMax = 806 pInfo->fContentMax - pInfo->fContentMin - pInfo->fPlateWidth; 807 fMax = fMax > 0.0f ? fMax : 0.0f; 808 SetScrollRange(0, fMax, pInfo->fPlateWidth); 809 SetScrollStep(pInfo->fBigStep, pInfo->fSmallStep); 810 } 811 } break; 812 case PNM_SETSCROLLPOS: { 813 FX_FLOAT fPos = *(FX_FLOAT*)lParam; 814 switch (m_sbType) { 815 case SBT_HSCROLL: 816 fPos = fPos - m_OriginInfo.fContentMin; 817 break; 818 case SBT_VSCROLL: 819 fPos = m_OriginInfo.fContentMax - fPos; 820 break; 821 } 822 SetScrollPos(fPos); 823 } break; 824 } 825} 826 827void CPWL_ScrollBar::CreateButtons(const PWL_CREATEPARAM& cp) { 828 PWL_CREATEPARAM scp = cp; 829 scp.pParentWnd = this; 830 scp.dwBorderWidth = 2; 831 scp.nBorderStyle = BorderStyle::BEVELED; 832 833 scp.dwFlags = 834 PWS_VISIBLE | PWS_CHILD | PWS_BORDER | PWS_BACKGROUND | PWS_NOREFRESHCLIP; 835 836 if (!m_pMinButton) { 837 m_pMinButton = new CPWL_SBButton(m_sbType, PSBT_MIN); 838 m_pMinButton->Create(scp); 839 } 840 841 if (!m_pMaxButton) { 842 m_pMaxButton = new CPWL_SBButton(m_sbType, PSBT_MAX); 843 m_pMaxButton->Create(scp); 844 } 845 846 if (!m_pPosButton) { 847 m_pPosButton = new CPWL_SBButton(m_sbType, PSBT_POS); 848 m_pPosButton->SetVisible(false); 849 m_pPosButton->Create(scp); 850 } 851} 852 853FX_FLOAT CPWL_ScrollBar::GetScrollBarWidth() const { 854 if (!IsVisible()) 855 return 0; 856 857 return PWL_SCROLLBAR_WIDTH; 858} 859 860void CPWL_ScrollBar::SetScrollRange(FX_FLOAT fMin, 861 FX_FLOAT fMax, 862 FX_FLOAT fClientWidth) { 863 if (m_pPosButton) { 864 m_sData.SetScrollRange(fMin, fMax); 865 m_sData.SetClientWidth(fClientWidth); 866 867 if (IsFloatSmaller(m_sData.ScrollRange.GetWidth(), 0.0f)) { 868 m_pPosButton->SetVisible(false); 869 } else { 870 m_pPosButton->SetVisible(true); 871 MovePosButton(true); 872 } 873 } 874} 875 876void CPWL_ScrollBar::SetScrollPos(FX_FLOAT fPos) { 877 FX_FLOAT fOldPos = m_sData.fScrollPos; 878 879 m_sData.SetPos(fPos); 880 881 if (!IsFloatEqual(m_sData.fScrollPos, fOldPos)) 882 MovePosButton(true); 883} 884 885void CPWL_ScrollBar::SetScrollStep(FX_FLOAT fBigStep, FX_FLOAT fSmallStep) { 886 m_sData.SetBigStep(fBigStep); 887 m_sData.SetSmallStep(fSmallStep); 888} 889 890void CPWL_ScrollBar::MovePosButton(bool bRefresh) { 891 ASSERT(m_pMinButton); 892 ASSERT(m_pMaxButton); 893 894 if (m_pPosButton->IsVisible()) { 895 CFX_FloatRect rcClient; 896 CFX_FloatRect rcPosArea, rcPosButton; 897 898 rcClient = GetClientRect(); 899 rcPosArea = GetScrollArea(); 900 901 FX_FLOAT fLeft, fRight, fTop, fBottom; 902 903 switch (m_sbType) { 904 case SBT_HSCROLL: 905 fLeft = TrueToFace(m_sData.fScrollPos); 906 fRight = TrueToFace(m_sData.fScrollPos + m_sData.fClientWidth); 907 908 if (fRight - fLeft < PWL_SCROLLBAR_POSBUTTON_MINWIDTH) 909 fRight = fLeft + PWL_SCROLLBAR_POSBUTTON_MINWIDTH; 910 911 if (fRight > rcPosArea.right) { 912 fRight = rcPosArea.right; 913 fLeft = fRight - PWL_SCROLLBAR_POSBUTTON_MINWIDTH; 914 } 915 916 rcPosButton = 917 CFX_FloatRect(fLeft, rcPosArea.bottom, fRight, rcPosArea.top); 918 919 break; 920 case SBT_VSCROLL: 921 fBottom = TrueToFace(m_sData.fScrollPos + m_sData.fClientWidth); 922 fTop = TrueToFace(m_sData.fScrollPos); 923 924 if (IsFloatSmaller(fTop - fBottom, PWL_SCROLLBAR_POSBUTTON_MINWIDTH)) 925 fBottom = fTop - PWL_SCROLLBAR_POSBUTTON_MINWIDTH; 926 927 if (IsFloatSmaller(fBottom, rcPosArea.bottom)) { 928 fBottom = rcPosArea.bottom; 929 fTop = fBottom + PWL_SCROLLBAR_POSBUTTON_MINWIDTH; 930 } 931 932 rcPosButton = 933 CFX_FloatRect(rcPosArea.left, fBottom, rcPosArea.right, fTop); 934 935 break; 936 } 937 938 m_pPosButton->Move(rcPosButton, true, bRefresh); 939 } 940} 941 942void CPWL_ScrollBar::OnMinButtonLBDown(const CFX_PointF& point) { 943 m_sData.SubSmall(); 944 MovePosButton(true); 945 NotifyScrollWindow(); 946 947 m_bMinOrMax = true; 948 949 EndTimer(); 950 BeginTimer(100); 951} 952 953void CPWL_ScrollBar::OnMinButtonLBUp(const CFX_PointF& point) {} 954 955void CPWL_ScrollBar::OnMinButtonMouseMove(const CFX_PointF& point) {} 956 957void CPWL_ScrollBar::OnMaxButtonLBDown(const CFX_PointF& point) { 958 m_sData.AddSmall(); 959 MovePosButton(true); 960 NotifyScrollWindow(); 961 962 m_bMinOrMax = false; 963 964 EndTimer(); 965 BeginTimer(100); 966} 967 968void CPWL_ScrollBar::OnMaxButtonLBUp(const CFX_PointF& point) {} 969 970void CPWL_ScrollBar::OnMaxButtonMouseMove(const CFX_PointF& point) {} 971 972void CPWL_ScrollBar::OnPosButtonLBDown(const CFX_PointF& point) { 973 m_bMouseDown = true; 974 975 if (m_pPosButton) { 976 CFX_FloatRect rcPosButton = m_pPosButton->GetWindowRect(); 977 978 switch (m_sbType) { 979 case SBT_HSCROLL: 980 m_nOldPos = point.x; 981 m_fOldPosButton = rcPosButton.left; 982 break; 983 case SBT_VSCROLL: 984 m_nOldPos = point.y; 985 m_fOldPosButton = rcPosButton.top; 986 break; 987 } 988 } 989} 990 991void CPWL_ScrollBar::OnPosButtonLBUp(const CFX_PointF& point) { 992 if (m_bMouseDown) { 993 if (!m_bNotifyForever) 994 NotifyScrollWindow(); 995 } 996 m_bMouseDown = false; 997} 998 999void CPWL_ScrollBar::OnPosButtonMouseMove(const CFX_PointF& point) { 1000 FX_FLOAT fOldScrollPos = m_sData.fScrollPos; 1001 1002 FX_FLOAT fNewPos = 0; 1003 1004 switch (m_sbType) { 1005 case SBT_HSCROLL: 1006 if (FXSYS_fabs(point.x - m_nOldPos) < 1) 1007 return; 1008 fNewPos = FaceToTrue(m_fOldPosButton + point.x - m_nOldPos); 1009 break; 1010 case SBT_VSCROLL: 1011 if (FXSYS_fabs(point.y - m_nOldPos) < 1) 1012 return; 1013 fNewPos = FaceToTrue(m_fOldPosButton + point.y - m_nOldPos); 1014 break; 1015 } 1016 1017 if (m_bMouseDown) { 1018 switch (m_sbType) { 1019 case SBT_HSCROLL: 1020 1021 if (IsFloatSmaller(fNewPos, m_sData.ScrollRange.fMin)) { 1022 fNewPos = m_sData.ScrollRange.fMin; 1023 } 1024 1025 if (IsFloatBigger(fNewPos, m_sData.ScrollRange.fMax)) { 1026 fNewPos = m_sData.ScrollRange.fMax; 1027 } 1028 1029 m_sData.SetPos(fNewPos); 1030 1031 break; 1032 case SBT_VSCROLL: 1033 1034 if (IsFloatSmaller(fNewPos, m_sData.ScrollRange.fMin)) { 1035 fNewPos = m_sData.ScrollRange.fMin; 1036 } 1037 1038 if (IsFloatBigger(fNewPos, m_sData.ScrollRange.fMax)) { 1039 fNewPos = m_sData.ScrollRange.fMax; 1040 } 1041 1042 m_sData.SetPos(fNewPos); 1043 1044 break; 1045 } 1046 1047 if (!IsFloatEqual(fOldScrollPos, m_sData.fScrollPos)) { 1048 MovePosButton(true); 1049 1050 if (m_bNotifyForever) 1051 NotifyScrollWindow(); 1052 } 1053 } 1054} 1055 1056void CPWL_ScrollBar::NotifyScrollWindow() { 1057 if (CPWL_Wnd* pParent = GetParentWindow()) { 1058 FX_FLOAT fPos; 1059 switch (m_sbType) { 1060 case SBT_HSCROLL: 1061 fPos = m_OriginInfo.fContentMin + m_sData.fScrollPos; 1062 break; 1063 case SBT_VSCROLL: 1064 fPos = m_OriginInfo.fContentMax - m_sData.fScrollPos; 1065 break; 1066 } 1067 pParent->OnNotify(this, PNM_SCROLLWINDOW, (intptr_t)m_sbType, 1068 (intptr_t)&fPos); 1069 } 1070} 1071 1072CFX_FloatRect CPWL_ScrollBar::GetScrollArea() const { 1073 CFX_FloatRect rcClient = GetClientRect(); 1074 CFX_FloatRect rcArea; 1075 1076 if (!m_pMinButton || !m_pMaxButton) 1077 return rcClient; 1078 1079 CFX_FloatRect rcMin = m_pMinButton->GetWindowRect(); 1080 CFX_FloatRect rcMax = m_pMaxButton->GetWindowRect(); 1081 1082 FX_FLOAT fMinWidth = rcMin.right - rcMin.left; 1083 FX_FLOAT fMinHeight = rcMin.top - rcMin.bottom; 1084 FX_FLOAT fMaxWidth = rcMax.right - rcMax.left; 1085 FX_FLOAT fMaxHeight = rcMax.top - rcMax.bottom; 1086 1087 switch (m_sbType) { 1088 case SBT_HSCROLL: 1089 if (rcClient.right - rcClient.left > fMinWidth + fMaxWidth + 2) { 1090 rcArea = CFX_FloatRect(rcClient.left + fMinWidth + 1, rcClient.bottom, 1091 rcClient.right - fMaxWidth - 1, rcClient.top); 1092 } else { 1093 rcArea = CFX_FloatRect(rcClient.left + fMinWidth + 1, rcClient.bottom, 1094 rcClient.left + fMinWidth + 1, rcClient.top); 1095 } 1096 break; 1097 case SBT_VSCROLL: 1098 if (rcClient.top - rcClient.bottom > fMinHeight + fMaxHeight + 2) { 1099 rcArea = CFX_FloatRect(rcClient.left, rcClient.bottom + fMinHeight + 1, 1100 rcClient.right, rcClient.top - fMaxHeight - 1); 1101 } else { 1102 rcArea = 1103 CFX_FloatRect(rcClient.left, rcClient.bottom + fMinHeight + 1, 1104 rcClient.right, rcClient.bottom + fMinHeight + 1); 1105 } 1106 break; 1107 } 1108 1109 rcArea.Normalize(); 1110 1111 return rcArea; 1112} 1113 1114FX_FLOAT CPWL_ScrollBar::TrueToFace(FX_FLOAT fTrue) { 1115 CFX_FloatRect rcPosArea; 1116 rcPosArea = GetScrollArea(); 1117 1118 FX_FLOAT fFactWidth = m_sData.ScrollRange.GetWidth() + m_sData.fClientWidth; 1119 fFactWidth = fFactWidth == 0 ? 1 : fFactWidth; 1120 1121 FX_FLOAT fFace = 0; 1122 1123 switch (m_sbType) { 1124 case SBT_HSCROLL: 1125 fFace = rcPosArea.left + 1126 fTrue * (rcPosArea.right - rcPosArea.left) / fFactWidth; 1127 break; 1128 case SBT_VSCROLL: 1129 fFace = rcPosArea.top - 1130 fTrue * (rcPosArea.top - rcPosArea.bottom) / fFactWidth; 1131 break; 1132 } 1133 1134 return fFace; 1135} 1136 1137FX_FLOAT CPWL_ScrollBar::FaceToTrue(FX_FLOAT fFace) { 1138 CFX_FloatRect rcPosArea; 1139 rcPosArea = GetScrollArea(); 1140 1141 FX_FLOAT fFactWidth = m_sData.ScrollRange.GetWidth() + m_sData.fClientWidth; 1142 fFactWidth = fFactWidth == 0 ? 1 : fFactWidth; 1143 1144 FX_FLOAT fTrue = 0; 1145 1146 switch (m_sbType) { 1147 case SBT_HSCROLL: 1148 fTrue = (fFace - rcPosArea.left) * fFactWidth / 1149 (rcPosArea.right - rcPosArea.left); 1150 break; 1151 case SBT_VSCROLL: 1152 fTrue = (rcPosArea.top - fFace) * fFactWidth / 1153 (rcPosArea.top - rcPosArea.bottom); 1154 break; 1155 } 1156 1157 return fTrue; 1158} 1159 1160void CPWL_ScrollBar::CreateChildWnd(const PWL_CREATEPARAM& cp) { 1161 CreateButtons(cp); 1162} 1163 1164void CPWL_ScrollBar::TimerProc() { 1165 PWL_SCROLL_PRIVATEDATA sTemp = m_sData; 1166 if (m_bMinOrMax) 1167 m_sData.SubSmall(); 1168 else 1169 m_sData.AddSmall(); 1170 1171 if (sTemp != m_sData) { 1172 MovePosButton(true); 1173 NotifyScrollWindow(); 1174 } 1175} 1176