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