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