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 
PWL_FLOATRANGE()16 PWL_FLOATRANGE::PWL_FLOATRANGE() {
17   Default();
18 }
19 
PWL_FLOATRANGE(FX_FLOAT min,FX_FLOAT max)20 PWL_FLOATRANGE::PWL_FLOATRANGE(FX_FLOAT min, FX_FLOAT max) {
21   Set(min, max);
22 }
23 
Default()24 void PWL_FLOATRANGE::Default() {
25   fMin = 0;
26   fMax = 0;
27 }
28 
Set(FX_FLOAT min,FX_FLOAT max)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 
In(FX_FLOAT x) const39 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 
GetWidth() const44 FX_FLOAT PWL_FLOATRANGE::GetWidth() const {
45   return fMax - fMin;
46 }
47 
PWL_SCROLL_PRIVATEDATA()48 PWL_SCROLL_PRIVATEDATA::PWL_SCROLL_PRIVATEDATA() {
49   Default();
50 }
51 
Default()52 void PWL_SCROLL_PRIVATEDATA::Default() {
53   ScrollRange.Default();
54   fScrollPos = ScrollRange.fMin;
55   fClientWidth = 0;
56   fBigStep = 10;
57   fSmallStep = 1;
58 }
59 
SetScrollRange(FX_FLOAT min,FX_FLOAT max)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 
SetClientWidth(FX_FLOAT width)69 void PWL_SCROLL_PRIVATEDATA::SetClientWidth(FX_FLOAT width) {
70   fClientWidth = width;
71 }
72 
SetSmallStep(FX_FLOAT step)73 void PWL_SCROLL_PRIVATEDATA::SetSmallStep(FX_FLOAT step) {
74   fSmallStep = step;
75 }
76 
SetBigStep(FX_FLOAT step)77 void PWL_SCROLL_PRIVATEDATA::SetBigStep(FX_FLOAT step) {
78   fBigStep = step;
79 }
80 
SetPos(FX_FLOAT pos)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 
AddSmall()89 void PWL_SCROLL_PRIVATEDATA::AddSmall() {
90   if (!SetPos(fScrollPos + fSmallStep))
91     SetPos(ScrollRange.fMax);
92 }
93 
SubSmall()94 void PWL_SCROLL_PRIVATEDATA::SubSmall() {
95   if (!SetPos(fScrollPos - fSmallStep))
96     SetPos(ScrollRange.fMin);
97 }
98 
AddBig()99 void PWL_SCROLL_PRIVATEDATA::AddBig() {
100   if (!SetPos(fScrollPos + fBigStep))
101     SetPos(ScrollRange.fMax);
102 }
103 
SubBig()104 void PWL_SCROLL_PRIVATEDATA::SubBig() {
105   if (!SetPos(fScrollPos - fBigStep))
106     SetPos(ScrollRange.fMin);
107 }
108 
CPWL_SBButton(PWL_SCROLLBAR_TYPE eScrollBarType,PWL_SBBUTTON_TYPE eButtonType)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 
~CPWL_SBButton()117 CPWL_SBButton::~CPWL_SBButton() {}
118 
GetClassName() const119 CFX_ByteString CPWL_SBButton::GetClassName() const {
120   return "CPWL_SBButton";
121 }
122 
OnCreate(PWL_CREATEPARAM & cp)123 void CPWL_SBButton::OnCreate(PWL_CREATEPARAM& cp) {
124   cp.eCursorType = FXCT_ARROW;
125 }
126 
GetThisAppearanceStream(CFX_ByteTextBuf & sAppStream)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 
DrawThisAppearance(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device)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 
OnLButtonDown(const CPDF_Point & point,FX_DWORD nFlag)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 
OnLButtonUp(const CPDF_Point & point,FX_DWORD nFlag)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 
OnMouseMove(const CPDF_Point & point,FX_DWORD nFlag)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 
CPWL_ScrollBar(PWL_SCROLLBAR_TYPE sbType)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 
~CPWL_ScrollBar()577 CPWL_ScrollBar::~CPWL_ScrollBar() {}
578 
GetClassName() const579 CFX_ByteString CPWL_ScrollBar::GetClassName() const {
580   return "CPWL_ScrollBar";
581 }
582 
OnCreate(PWL_CREATEPARAM & cp)583 void CPWL_ScrollBar::OnCreate(PWL_CREATEPARAM& cp) {
584   cp.eCursorType = FXCT_ARROW;
585 }
586 
RePosChildWnd()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 
GetThisAppearanceStream(CFX_ByteTextBuf & sAppStream)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 
DrawThisAppearance(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device)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 
OnLButtonDown(const CPDF_Point & point,FX_DWORD nFlag)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 
OnLButtonUp(const CPDF_Point & point,FX_DWORD nFlag)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 
OnNotify(CPWL_Wnd * pWnd,FX_DWORD msg,intptr_t wParam,intptr_t lParam)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 
CreateButtons(const PWL_CREATEPARAM & cp)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 
GetScrollBarWidth() const857 FX_FLOAT CPWL_ScrollBar::GetScrollBarWidth() const {
858   if (!IsVisible())
859     return 0;
860 
861   return PWL_SCROLLBAR_WIDTH;
862 }
863 
SetScrollRange(FX_FLOAT fMin,FX_FLOAT fMax,FX_FLOAT fClientWidth)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 
SetScrollPos(FX_FLOAT fPos)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 
SetScrollStep(FX_FLOAT fBigStep,FX_FLOAT fSmallStep)889 void CPWL_ScrollBar::SetScrollStep(FX_FLOAT fBigStep, FX_FLOAT fSmallStep) {
890   m_sData.SetBigStep(fBigStep);
891   m_sData.SetSmallStep(fSmallStep);
892 }
893 
MovePosButton(FX_BOOL bRefresh)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 
OnMinButtonLBDown(const CPDF_Point & point)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 
OnMinButtonLBUp(const CPDF_Point & point)955 void CPWL_ScrollBar::OnMinButtonLBUp(const CPDF_Point& point) {}
956 
OnMinButtonMouseMove(const CPDF_Point & point)957 void CPWL_ScrollBar::OnMinButtonMouseMove(const CPDF_Point& point) {}
958 
OnMaxButtonLBDown(const CPDF_Point & point)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 
OnMaxButtonLBUp(const CPDF_Point & point)970 void CPWL_ScrollBar::OnMaxButtonLBUp(const CPDF_Point& point) {}
971 
OnMaxButtonMouseMove(const CPDF_Point & point)972 void CPWL_ScrollBar::OnMaxButtonMouseMove(const CPDF_Point& point) {}
973 
OnPosButtonLBDown(const CPDF_Point & point)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 
OnPosButtonLBUp(const CPDF_Point & point)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 
OnPosButtonMouseMove(const CPDF_Point & point)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 
NotifyScrollWindow()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 
GetScrollArea() const1074 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 
TrueToFace(FX_FLOAT fTrue)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 
FaceToTrue(FX_FLOAT fFace)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 
CreateChildWnd(const PWL_CREATEPARAM & cp)1161 void CPWL_ScrollBar::CreateChildWnd(const PWL_CREATEPARAM& cp) {
1162   CreateButtons(cp);
1163 }
1164 
TimerProc()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