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