1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "SliderCtrlEx.h"
6 #define FLOAT_SCALE 100
8 IMPLEMENT_DYNAMIC(CSliderCtrlEx
, CSliderCtrl
)
9 IMPLEMENT_DYNAMIC(CSliderCtrlCustomDraw
, CSliderCtrlEx
)
11 BEGIN_MESSAGE_MAP(CSliderCtrlEx
, CSliderCtrl
)
17 //////////////////////////////////////////////////////////////////////////
18 CSliderCtrlEx::CSliderCtrlEx()
21 m_bDragChanged
= false;
28 m_bUndoEnabled
= false;
30 m_bUndoStarted
= false;
32 m_bInNotifyCallback
= false;
35 //////////////////////////////////////////////////////////////////////////
36 void CSliderCtrlEx::OnLButtonDown(UINT nFlags
, CPoint point
)
38 m_bUndoStarted
= false;
42 GetIEditor()->GetIUndoManager()->Begin();
43 m_bUndoStarted
= true;
47 m_bDragChanged
= false;
52 m_bDragChanged
= true;
53 PostMessageToParent(TB_THUMBTRACK
);
57 //////////////////////////////////////////////////////////////////////////
58 void CSliderCtrlEx::OnMouseMove(UINT nFlags
, CPoint point
)
64 m_bDragChanged
= true;
65 PostMessageToParent(TB_THUMBTRACK
);
70 CSliderCtrl::OnMouseMove(nFlags
, point
);
74 //////////////////////////////////////////////////////////////////////////
75 void CSliderCtrlEx::OnLButtonUp(UINT nFlags
, CPoint point
)
82 PostMessageToParent(TB_THUMBTRACK
);
83 m_bDragChanged
= true;
87 PostMessageToParent(TB_THUMBPOSITION
);
88 m_bDragChanged
= false;
94 if (CUndo::IsRecording())
95 GetIEditor()->GetIUndoManager()->Accept(m_undoText
.GetString());
96 m_bUndoStarted
= false;
101 CSliderCtrl::OnLButtonUp(nFlags
, point
);
105 //////////////////////////////////////////////////////////////////////////
106 bool CSliderCtrlEx::SetThumb(const CPoint
& point
)
108 const int nMin
= GetRangeMin();
109 const int nMax
= GetRangeMax() + 1;
113 double dCorrectionFactor
= 0.0;
114 if (GetStyle() & TBS_VERT
)
116 // note: there is a bug in GetChannelRect, it gets the orientation of the rectangle mixed up
117 dPos
= (double)(point
.y
- rc
.left
) / (rc
.right
- rc
.left
);
121 dPos
= (double)(point
.x
- rc
.left
) / (rc
.right
- rc
.left
);
123 // This correction factor is needed when you click inbetween tick marks
124 // so that the thumb will move to the nearest one
125 dCorrectionFactor
= 0.5 * (1 - dPos
) - 0.5 * dPos
;
126 int nNewPos
= (int)(nMin
+ (nMax
- nMin
) * dPos
+ dCorrectionFactor
);
127 const bool bChanged
= (nNewPos
!= GetPos());
131 float dt
= ((float)(nNewPos
- nMin
) / (nMax
- nMin
));
132 SetValue(dt
* (m_max
- m_min
) + m_min
);
137 //////////////////////////////////////////////////////////////////////////
138 void CSliderCtrlEx::PostMessageToParent(const int nTBCode
)
143 m_bInNotifyCallback
= true;
145 if (nTBCode
== TB_THUMBTRACK
&& m_bUndoEnabled
&& CUndo::IsRecording())
148 GetIEditor()->GetIUndoManager()->Restore();
152 if (m_updateCallback
)
153 m_updateCallback(this);
155 m_lastUpdateValue
= m_value
;
157 CWnd
* pWnd
= GetParent();
160 int nMsg
= (GetStyle() & TBS_VERT
) ? WM_VSCROLL
: WM_HSCROLL
;
161 pWnd
->PostMessage(nMsg
, (WPARAM
)((GetPos() << 16) | nTBCode
), (LPARAM
)GetSafeHwnd());
164 m_bInNotifyCallback
= false;
167 //////////////////////////////////////////////////////////////////////////
168 void CSliderCtrlEx::EnableUndo(const CString
& undoText
)
170 m_undoText
= undoText
;
171 m_bUndoEnabled
= true;
174 //////////////////////////////////////////////////////////////////////////
175 void CSliderCtrlEx::SetRangeFloat(float min
, float max
, float step
)
182 // Set internal slider range.
183 float range
= FLOAT_SCALE
;
185 range
= pow(0.1f
, floor(log(step
) / log(10.f
)));
186 SetRange(int_round(min
* range
), int_round(max
* range
));
188 if (m_hWnd
&& !m_bInNotifyCallback
)
192 //////////////////////////////////////////////////////////////////////////
193 void CSliderCtrlEx::SetValue(float val
)
205 const int nMin
= GetRangeMin();
206 const int nMax
= GetRangeMax() + 1;
207 float pos
= (m_value
- m_min
) / (m_max
- m_min
) * (nMax
- nMin
) + nMin
;
208 SetPos(int_round(pos
));
211 if (m_hWnd
&& !m_bInNotifyCallback
)
215 //////////////////////////////////////////////////////////////////////////
216 float CSliderCtrlEx::GetValue() const
221 //////////////////////////////////////////////////////////////////////////
222 CString
CSliderCtrlEx::GetValueAsString() const
225 str
.Format("%g", m_value
);
229 //////////////////////////////////////////////////////////////////////////
230 // CSliderCtrlCustomDraw
231 //////////////////////////////////////////////////////////////////////////
233 BEGIN_MESSAGE_MAP(CSliderCtrlCustomDraw
, CSliderCtrlEx
)
234 ON_NOTIFY_REFLECT(NM_CUSTOMDRAW
, OnCustomDraw
)
237 void CSliderCtrlCustomDraw::OnCustomDraw(NMHDR
* pNMHDR
, LRESULT
* pResult
)
239 NMCUSTOMDRAW
* pCD
= (NMCUSTOMDRAW
*)pNMHDR
;
240 switch (pCD
->dwDrawStage
)
242 case CDDS_POSTERASE
: // After the erasing cycle is complete.
243 *pResult
= CDRF_DODEFAULT
;
245 case CDDS_POSTPAINT
: // After the painting cycle is complete.
246 *pResult
= CDRF_DODEFAULT
;
248 case CDDS_PREERASE
: // Before the erasing cycle begins.
249 *pResult
= CDRF_DODEFAULT
;
251 case CDDS_PREPAINT
: // Before the painting cycle begins.
252 *pResult
= CDRF_NOTIFYITEMDRAW
;
254 case CDDS_ITEMPOSTPAINT
: // After an item is drawn.
255 DrawTicks(CDC::FromHandle(pCD
->hdc
));
256 *pResult
= CDRF_DODEFAULT
;
258 case CDDS_ITEMPREPAINT
: // Before an item is drawn.
259 switch (pCD
->dwItemSpec
)
262 m_channelRc
= pCD
->rc
;
263 *pResult
= CDRF_NOTIFYPOSTPAINT
;
266 //DrawTicks( CDC::FromHandle(pCD->hdc) );
267 *pResult
= CDRF_SKIPDEFAULT
;
270 *pResult
= CDRF_DODEFAULT
;
273 *pResult
= CDRF_DODEFAULT
;
278 *pResult
= CDRF_DODEFAULT
;
283 //////////////////////////////////////////////////////////////////////////
284 int CSliderCtrlCustomDraw::ValueToPos(int x
)
288 double pixelsPerStep
= (double)(m_channelRc
.Width() - trc
.Width()) / (GetRangeMax() - GetRangeMin());
289 return m_channelRc
.left
+ pixelsPerStep
* (x
- GetRangeMin()) + trc
.Width() / 2;
292 //////////////////////////////////////////////////////////////////////////
293 void CSliderCtrlCustomDraw::DrawTick(CDC
* pDC
, int x
, bool bMajor
)
295 int s
= (bMajor
) ? 10 : 6;
296 pDC
->MoveTo(x
, m_channelRc
.bottom
+ 4);
297 pDC
->LineTo(x
, m_channelRc
.bottom
+ s
);
300 //////////////////////////////////////////////////////////////////////////
301 void CSliderCtrlCustomDraw::DrawTicks(CDC
* pDC
)
304 pen
.CreatePen(PS_SOLID
, 1, RGB(128, 128, 128));
305 CPen
* pPrevPen
= pDC
->SelectObject(&pen
);
309 if (m_selMax
!= m_selMin
)
311 sel1
= ValueToPos(m_selMin
);
312 sel2
= ValueToPos(m_selMax
);
316 if (m_selMin
== 0 && m_selMax
> 0)
318 XTPPaintManager()->GradientFill(pDC
, CRect(sel1
, m_channelRc
.top
+ 1, sel2
, m_channelRc
.bottom
- 1),
319 RGB(0, 160, 0), RGB(100, 255, 100), TRUE
);
321 else if (m_selMax
== 0 && m_selMin
< 0)
323 XTPPaintManager()->GradientFill(pDC
, CRect(sel1
, m_channelRc
.top
+ 1, sel2
, m_channelRc
.bottom
- 1),
324 RGB(255, 100, 100), RGB(160, 0, 0), TRUE
);
327 pDC
->Rectangle(CRect(sel1
, m_channelRc
.top
+ 1, sel2
, m_channelRc
.bottom
- 1));
330 if (GetStyle() & TBS_AUTOTICKS
)
332 bool bTop
= ((GetStyle() & TBS_BOTH
) == TBS_BOTH
) || ((GetStyle() & TBS_TOP
) == TBS_TOP
);
333 bool bBottom
= ((GetStyle() & TBS_BOTH
) == TBS_BOTH
) || ((GetStyle() & TBS_BOTTOM
) == TBS_BOTTOM
);
335 int r0
= GetRangeMin();
336 int r1
= GetRangeMax();
339 for (int i
= r0
; i
< r1
; i
+= m_tickFreq
)
343 int x
= ValueToPos(i
);
349 if (GetRangeMin() < 0 && GetRangeMax() > 0)
352 DrawTick(pDC
, ValueToPos(0), true);
354 DrawTick(pDC
, ValueToPos(GetRangeMin()), true);
355 DrawTick(pDC
, ValueToPos(GetRangeMax()), true);
359 pDC
->SelectObject(pPrevPen
);
362 //////////////////////////////////////////////////////////////////////////
363 void CSliderCtrlCustomDraw::SetSelection(int nMin
, int nMax
)
365 if (nMin
!= m_selMin
|| nMax
!= m_selMax
)
369 InvalidateRect(m_channelRc
);
371 // Simulate resize of the window, to force redraw of the control subitem.
375 int cy
= rc
.Height();
376 SendMessage(WM_SIZE
, (WPARAM
)SIZE_RESTORED
, MAKELPARAM(cx
, cy
));
380 GetParent()->ScreenToClient(rc
);
382 //MoveWindow(rc,FALSE);
384 //MoveWindow(rc,FALSE);