!XT (BREAK-16) (Sandbox) Remove double-newlines at the end of files.
[CRYENGINE.git] / Code / Sandbox / Plugins / MFCToolsPlugin / Controls / SliderCtrlEx.cpp
blob250e0825a1b480d8a809439f4701f9af1f0d20a4
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
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)
12 ON_WM_LBUTTONDOWN()
13 ON_WM_MOUSEMOVE()
14 ON_WM_LBUTTONUP()
15 END_MESSAGE_MAP()
17 //////////////////////////////////////////////////////////////////////////
18 CSliderCtrlEx::CSliderCtrlEx()
20 m_bDragging = false;
21 m_bDragChanged = false;
23 m_value = 0;
24 m_min = 0;
25 m_max = 100;
26 m_noNotify = false;
27 m_integer = false;
28 m_bUndoEnabled = false;
29 m_bDragged = false;
30 m_bUndoStarted = false;
31 m_bLocked = false;
32 m_bInNotifyCallback = false;
35 //////////////////////////////////////////////////////////////////////////
36 void CSliderCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
38 m_bUndoStarted = false;
39 // Start undo.
40 if (m_bUndoEnabled)
42 GetIEditor()->GetIUndoManager()->Begin();
43 m_bUndoStarted = true;
46 m_bDragging = true;
47 m_bDragChanged = false;
48 SetCapture();
49 SetFocus();
50 if (SetThumb(point))
52 m_bDragChanged = true;
53 PostMessageToParent(TB_THUMBTRACK);
57 //////////////////////////////////////////////////////////////////////////
58 void CSliderCtrlEx::OnMouseMove(UINT nFlags, CPoint point)
60 if (m_bDragging)
62 if (SetThumb(point))
64 m_bDragChanged = true;
65 PostMessageToParent(TB_THUMBTRACK);
68 else
70 CSliderCtrl::OnMouseMove(nFlags, point);
74 //////////////////////////////////////////////////////////////////////////
75 void CSliderCtrlEx::OnLButtonUp(UINT nFlags, CPoint point)
77 if (m_bDragging)
79 ::ReleaseCapture();
80 if (SetThumb(point))
82 PostMessageToParent(TB_THUMBTRACK);
83 m_bDragChanged = true;
85 if (m_bDragChanged)
87 PostMessageToParent(TB_THUMBPOSITION);
88 m_bDragChanged = false;
90 m_bDragging = false;
92 if (m_bUndoStarted)
94 if (CUndo::IsRecording())
95 GetIEditor()->GetIUndoManager()->Accept(m_undoText.GetString());
96 m_bUndoStarted = false;
99 else
101 CSliderCtrl::OnLButtonUp(nFlags, point);
105 //////////////////////////////////////////////////////////////////////////
106 bool CSliderCtrlEx::SetThumb(const CPoint& point)
108 const int nMin = GetRangeMin();
109 const int nMax = GetRangeMax() + 1;
110 CRect rc;
111 GetChannelRect(rc);
112 double dPos;
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);
119 else
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());
128 if (bChanged)
130 SetPos(nNewPos);
131 float dt = ((float)(nNewPos - nMin) / (nMax - nMin));
132 SetValue(dt * (m_max - m_min) + m_min);
134 return bChanged;
137 //////////////////////////////////////////////////////////////////////////
138 void CSliderCtrlEx::PostMessageToParent(const int nTBCode)
140 if (m_noNotify)
141 return;
143 m_bInNotifyCallback = true;
145 if (nTBCode == TB_THUMBTRACK && m_bUndoEnabled && CUndo::IsRecording())
147 m_bLocked = true;
148 GetIEditor()->GetIUndoManager()->Restore();
149 m_bLocked = false;
152 if (m_updateCallback)
153 m_updateCallback(this);
155 m_lastUpdateValue = m_value;
157 CWnd* pWnd = GetParent();
158 if (pWnd)
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)
177 if (m_bLocked)
178 return;
179 m_min = min;
180 m_max = max;
182 // Set internal slider range.
183 float range = FLOAT_SCALE;
184 if (step != 0.f)
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)
189 Invalidate();
192 //////////////////////////////////////////////////////////////////////////
193 void CSliderCtrlEx::SetValue(float val)
195 if (m_bLocked)
196 return;
197 m_value = val;
198 if (m_value < m_min)
199 m_value = m_min;
200 if (m_value > m_max)
201 m_value = m_max;
203 if (!m_bDragging)
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)
212 Invalidate();
215 //////////////////////////////////////////////////////////////////////////
216 float CSliderCtrlEx::GetValue() const
218 return m_value;
221 //////////////////////////////////////////////////////////////////////////
222 CString CSliderCtrlEx::GetValueAsString() const
224 CString str;
225 str.Format("%g", m_value);
226 return str;
229 //////////////////////////////////////////////////////////////////////////
230 // CSliderCtrlCustomDraw
231 //////////////////////////////////////////////////////////////////////////
233 BEGIN_MESSAGE_MAP(CSliderCtrlCustomDraw, CSliderCtrlEx)
234 ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
235 END_MESSAGE_MAP()
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;
244 break;
245 case CDDS_POSTPAINT: // After the painting cycle is complete.
246 *pResult = CDRF_DODEFAULT;
247 break;
248 case CDDS_PREERASE: // Before the erasing cycle begins.
249 *pResult = CDRF_DODEFAULT;
250 break;
251 case CDDS_PREPAINT: // Before the painting cycle begins.
252 *pResult = CDRF_NOTIFYITEMDRAW;
253 break;
254 case CDDS_ITEMPOSTPAINT: // After an item is drawn.
255 DrawTicks(CDC::FromHandle(pCD->hdc));
256 *pResult = CDRF_DODEFAULT;
257 break;
258 case CDDS_ITEMPREPAINT: // Before an item is drawn.
259 switch (pCD->dwItemSpec)
261 case TBCD_CHANNEL:
262 m_channelRc = pCD->rc;
263 *pResult = CDRF_NOTIFYPOSTPAINT;
264 break;
265 case TBCD_TICS:
266 //DrawTicks( CDC::FromHandle(pCD->hdc) );
267 *pResult = CDRF_SKIPDEFAULT;
268 break;
269 case TBCD_THUMB:
270 *pResult = CDRF_DODEFAULT;
271 break;
272 default:
273 *pResult = CDRF_DODEFAULT;
274 break;
276 break;
277 default:
278 *pResult = CDRF_DODEFAULT;
279 break;
283 //////////////////////////////////////////////////////////////////////////
284 int CSliderCtrlCustomDraw::ValueToPos(int x)
286 CRect trc;
287 GetThumbRect(trc);
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)
303 CPen pen;
304 pen.CreatePen(PS_SOLID, 1, RGB(128, 128, 128));
305 CPen* pPrevPen = pDC->SelectObject(&pen);
307 int sel1 = 0;
308 int sel2 = 0;
309 if (m_selMax != m_selMin)
311 sel1 = ValueToPos(m_selMin);
312 sel2 = ValueToPos(m_selMax);
314 if (sel1 != sel2)
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);
326 else
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();
337 if (m_tickFreq < 1)
338 m_tickFreq = 1;
339 for (int i = r0; i < r1; i += m_tickFreq)
341 if (bBottom)
343 int x = ValueToPos(i);
344 DrawTick(pDC, x);
347 if (bBottom)
349 if (GetRangeMin() < 0 && GetRangeMax() > 0)
351 // Draw tick at 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)
367 m_selMin = nMin;
368 m_selMax = nMax;
369 InvalidateRect(m_channelRc);
371 // Simulate resize of the window, to force redraw of the control subitem.
372 CRect rc;
373 GetClientRect(rc);
374 int cx = rc.Width();
375 int cy = rc.Height();
376 SendMessage(WM_SIZE, (WPARAM)SIZE_RESTORED, MAKELPARAM(cx, cy));
378 // CRect rc;
379 GetWindowRect(rc);
380 GetParent()->ScreenToClient(rc);
381 rc.right += 1;
382 //MoveWindow(rc,FALSE);
383 rc.right -= 1;
384 //MoveWindow(rc,FALSE);