• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PWL_FLOATRANGE()14 PWL_FLOATRANGE::PWL_FLOATRANGE() {
15   Default();
16 }
17 
PWL_FLOATRANGE(FX_FLOAT min,FX_FLOAT max)18 PWL_FLOATRANGE::PWL_FLOATRANGE(FX_FLOAT min, FX_FLOAT max) {
19   Set(min, max);
20 }
21 
Default()22 void PWL_FLOATRANGE::Default() {
23   fMin = 0;
24   fMax = 0;
25 }
26 
Set(FX_FLOAT min,FX_FLOAT max)27 void 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 
In(FX_FLOAT x) const37 bool PWL_FLOATRANGE::In(FX_FLOAT x) const {
38   return (IsFloatBigger(x, fMin) || IsFloatEqual(x, fMin)) &&
39          (IsFloatSmaller(x, fMax) || IsFloatEqual(x, fMax));
40 }
41 
GetWidth() const42 FX_FLOAT PWL_FLOATRANGE::GetWidth() const {
43   return fMax - fMin;
44 }
45 
PWL_SCROLL_PRIVATEDATA()46 PWL_SCROLL_PRIVATEDATA::PWL_SCROLL_PRIVATEDATA() {
47   Default();
48 }
49 
Default()50 void PWL_SCROLL_PRIVATEDATA::Default() {
51   ScrollRange.Default();
52   fScrollPos = ScrollRange.fMin;
53   fClientWidth = 0;
54   fBigStep = 10;
55   fSmallStep = 1;
56 }
57 
SetScrollRange(FX_FLOAT min,FX_FLOAT max)58 void 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 
SetClientWidth(FX_FLOAT width)67 void PWL_SCROLL_PRIVATEDATA::SetClientWidth(FX_FLOAT width) {
68   fClientWidth = width;
69 }
70 
SetSmallStep(FX_FLOAT step)71 void PWL_SCROLL_PRIVATEDATA::SetSmallStep(FX_FLOAT step) {
72   fSmallStep = step;
73 }
74 
SetBigStep(FX_FLOAT step)75 void PWL_SCROLL_PRIVATEDATA::SetBigStep(FX_FLOAT step) {
76   fBigStep = step;
77 }
78 
SetPos(FX_FLOAT pos)79 bool PWL_SCROLL_PRIVATEDATA::SetPos(FX_FLOAT pos) {
80   if (ScrollRange.In(pos)) {
81     fScrollPos = pos;
82     return true;
83   }
84   return false;
85 }
86 
AddSmall()87 void PWL_SCROLL_PRIVATEDATA::AddSmall() {
88   if (!SetPos(fScrollPos + fSmallStep))
89     SetPos(ScrollRange.fMax);
90 }
91 
SubSmall()92 void PWL_SCROLL_PRIVATEDATA::SubSmall() {
93   if (!SetPos(fScrollPos - fSmallStep))
94     SetPos(ScrollRange.fMin);
95 }
96 
AddBig()97 void PWL_SCROLL_PRIVATEDATA::AddBig() {
98   if (!SetPos(fScrollPos + fBigStep))
99     SetPos(ScrollRange.fMax);
100 }
101 
SubBig()102 void PWL_SCROLL_PRIVATEDATA::SubBig() {
103   if (!SetPos(fScrollPos - fBigStep))
104     SetPos(ScrollRange.fMin);
105 }
106 
CPWL_SBButton(PWL_SCROLLBAR_TYPE eScrollBarType,PWL_SBBUTTON_TYPE eButtonType)107 CPWL_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 
~CPWL_SBButton()115 CPWL_SBButton::~CPWL_SBButton() {}
116 
GetClassName() const117 CFX_ByteString CPWL_SBButton::GetClassName() const {
118   return "CPWL_SBButton";
119 }
120 
OnCreate(PWL_CREATEPARAM & cp)121 void CPWL_SBButton::OnCreate(PWL_CREATEPARAM& cp) {
122   cp.eCursorType = FXCT_ARROW;
123 }
124 
GetThisAppearanceStream(CFX_ByteTextBuf & sAppStream)125 void 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 
DrawThisAppearance(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device)234 void 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 
OnLButtonDown(const CFX_PointF & point,uint32_t nFlag)525 bool 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 
OnLButtonUp(const CFX_PointF & point,uint32_t nFlag)537 bool 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 
OnMouseMove(const CFX_PointF & point,uint32_t nFlag)549 bool 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 
CPWL_ScrollBar(PWL_SCROLLBAR_TYPE sbType)559 CPWL_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 
~CPWL_ScrollBar()568 CPWL_ScrollBar::~CPWL_ScrollBar() {}
569 
GetClassName() const570 CFX_ByteString CPWL_ScrollBar::GetClassName() const {
571   return "CPWL_ScrollBar";
572 }
573 
OnCreate(PWL_CREATEPARAM & cp)574 void CPWL_ScrollBar::OnCreate(PWL_CREATEPARAM& cp) {
575   cp.eCursorType = FXCT_ARROW;
576 }
577 
RePosChildWnd()578 void 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 
GetThisAppearanceStream(CFX_ByteTextBuf & sAppStream)644 void 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 
DrawThisAppearance(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device)662 void 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 
OnLButtonDown(const CFX_PointF & point,uint32_t nFlag)684 bool 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 
OnLButtonUp(const CFX_PointF & point,uint32_t nFlag)739 bool 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 
OnNotify(CPWL_Wnd * pWnd,uint32_t msg,intptr_t wParam,intptr_t lParam)755 void 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 
CreateButtons(const PWL_CREATEPARAM & cp)827 void 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 
GetScrollBarWidth() const853 FX_FLOAT CPWL_ScrollBar::GetScrollBarWidth() const {
854   if (!IsVisible())
855     return 0;
856 
857   return PWL_SCROLLBAR_WIDTH;
858 }
859 
SetScrollRange(FX_FLOAT fMin,FX_FLOAT fMax,FX_FLOAT fClientWidth)860 void 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 
SetScrollPos(FX_FLOAT fPos)876 void 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 
SetScrollStep(FX_FLOAT fBigStep,FX_FLOAT fSmallStep)885 void CPWL_ScrollBar::SetScrollStep(FX_FLOAT fBigStep, FX_FLOAT fSmallStep) {
886   m_sData.SetBigStep(fBigStep);
887   m_sData.SetSmallStep(fSmallStep);
888 }
889 
MovePosButton(bool bRefresh)890 void 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 
OnMinButtonLBDown(const CFX_PointF & point)942 void 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 
OnMinButtonLBUp(const CFX_PointF & point)953 void CPWL_ScrollBar::OnMinButtonLBUp(const CFX_PointF& point) {}
954 
OnMinButtonMouseMove(const CFX_PointF & point)955 void CPWL_ScrollBar::OnMinButtonMouseMove(const CFX_PointF& point) {}
956 
OnMaxButtonLBDown(const CFX_PointF & point)957 void 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 
OnMaxButtonLBUp(const CFX_PointF & point)968 void CPWL_ScrollBar::OnMaxButtonLBUp(const CFX_PointF& point) {}
969 
OnMaxButtonMouseMove(const CFX_PointF & point)970 void CPWL_ScrollBar::OnMaxButtonMouseMove(const CFX_PointF& point) {}
971 
OnPosButtonLBDown(const CFX_PointF & point)972 void 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 
OnPosButtonLBUp(const CFX_PointF & point)991 void CPWL_ScrollBar::OnPosButtonLBUp(const CFX_PointF& point) {
992   if (m_bMouseDown) {
993     if (!m_bNotifyForever)
994       NotifyScrollWindow();
995   }
996   m_bMouseDown = false;
997 }
998 
OnPosButtonMouseMove(const CFX_PointF & point)999 void 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 
NotifyScrollWindow()1056 void 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 
GetScrollArea() const1072 CFX_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 
TrueToFace(FX_FLOAT fTrue)1114 FX_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 
FaceToTrue(FX_FLOAT fFace)1137 FX_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 
CreateChildWnd(const PWL_CREATEPARAM & cp)1160 void CPWL_ScrollBar::CreateChildWnd(const PWL_CREATEPARAM& cp) {
1161   CreateButtons(cp);
1162 }
1163 
TimerProc()1164 void 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