1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #if !defined(AFX_EDITABLE_RANGE_H__0B1EFF2B_FA0E_4AC8_88B8_416605043BF9__INCLUDED_)
22 #define AFX_EDITABLE_RANGE_H__0B1EFF2B_FA0E_4AC8_88B8_416605043BF9__INCLUDED_
26 #endif // _MSC_VER > 1000
27 // editable_range.h : header file
31 #include "edit_attrib_dlg.h"
32 #include "range_manager.h"
33 #include "range_selector.h"
34 #include "ps_wrapper.h"
35 #include "bound_checker.h"
36 #include "particle_workspace.h"
38 /////////////////////////////////////////////////////////////////////////////
39 // CEditableRange dialog
41 class CEditableRange
: public CEditAttribDlg
45 * Construct the dialog by giving it an Id. It will be used to save the user preference.
46 * Each dialog of this type must have its own id in the app.
48 CEditableRange(const std::string
&id
, CParticleWorkspace::CNode
*node
); // standard constructor
50 //{{AFX_DATA(CEditableRange)
51 enum { IDD
= IDD_EDITABLE_RANGE
};
52 CSliderCtrl m_SliderCtrl
;
54 CButton m_UpdateValue
;
55 CButton m_SelectRange
;
64 // ClassWizard generated virtual function overrides
65 //{{AFX_VIRTUAL(CEditableRange)
67 virtual void DoDataExchange(CDataExchange
* pDX
); // DDX/DDV support
71 // init the dialog at the given position
73 virtual void init(uint32 x
, uint32 y
, CWnd
*pParent
);
74 BOOL
EnableWindow( BOOL bEnable
= TRUE
);
76 /// for derivers : this must querries the value to the desired manager and set the dialog values
77 virtual void updateRange(void) = 0;
78 /** for derivers : value update from a linked object (reader). See examples in subclasses
80 virtual void updateValueFromReader(void) = 0;
81 // empty the values and the slider
82 void emptyDialog(void);
83 // validate the lower an upper bound of a range from their string representation
84 virtual bool editableRangeValueValidator(const CString
&lo
, const CString
&up
) = 0;
85 // update the dialog display
89 /** for derivers : value update : this is call with a float ranging from 0.f to 1.f (from the slider)
90 * And it must convert it to the desired value, changing the value of this dialog
92 virtual void updateValueFromSlider(double sliderValue
) = 0;
93 /// the text has changed, and the user has pressed update
94 virtual void updateValueFromText(void) = 0;
95 // the range tune button was pressed. It muist show a dialog that allows the user to choose the range he wants
96 virtual void selectRange(void) = 0;
97 // the unique id of this dialog
99 CParticleWorkspace::CNode
*_Node
; // Node that owns the value
100 // Generated message map functions
101 //{{AFX_MSG(CEditableRange)
102 virtual BOOL
OnInitDialog();
103 afx_msg
void OnReleasedcaptureSlider(NMHDR
* pNMHDR
, LRESULT
* pResult
);
104 afx_msg
void OnSelectRange();
105 afx_msg
void OnSetfocusValue();
106 afx_msg
void OnUpdateValue();
107 afx_msg
void OnKillfocusValue();
108 afx_msg
void OnChangeValue();
109 afx_msg
void OnHScroll(UINT nSBCode
, UINT nPos
, CScrollBar
* pScrollBar
);
111 DECLARE_MESSAGE_MAP()
114 /** here, we define a template for editable ranges EditableRanges, that help to instanciate it
115 * Derivers have just to specialize 2 static methods : value2CString and string2value
118 template <typename T
>
119 class CEditableRangeT
: public CEditableRange
, public CBoundChecker
<T
>
122 /// ctor, it gives the range for the values
123 CEditableRangeT(const std::string
&id
, CParticleWorkspace::CNode
*node
, T defaultMin
, T defaultMax
)
124 : CEditableRange(id
, node
), _Range(defaultMin
, defaultMax
), _Wrapper(NULL
)
128 /** set an interface of a wrapper to read / write values in the particle system
129 * NB : The 'OwnerNode' field of the wrapper if set to the value given when to 'node' when this object was constructed
131 void setWrapper(IPSWrapper
<T
> *wrapper
) { _Wrapper
= wrapper
; _Wrapper
->OwnerNode
= _Node
; }
136 // SPECIALIZE THAT. write value into the given CString
137 static void value2CString(T value
, CString
&dest
);
138 // SPECIALIZE THAT. convert a CString into a value, return NULL if ok, or a pointer to an error message
139 static const TCHAR
*string2value(const CString
&value
, T
&result
);
143 void updateRange(void)
145 // retrieve our range
146 _Range
= CRangeManager
<T
>::GetRange(_Id
, _Range
.first
, _Range
.second
);
147 value2CString(_Range
.first
, m_MinRange
);
148 value2CString(_Range
.second
, m_MaxRange
);
151 setValue(_Wrapper->get());
155 void updateValueFromReader(void)
159 setValue(_Wrapper
->get());
165 void updateValueFromText(void)
168 const TCHAR
*message
= string2value(m_Value
, value
);
171 const TCHAR
*mess
= validateUpperBound(value
), *mess2
= validateLowerBound(value
);
174 MessageBox(mess
? mess
: mess2
, _T("error"));
179 _Wrapper
->setAndUpdateModifiedFlag(value
);
184 MessageBox(message
, _T("error"));
187 void selectRange(void)
189 CString lowerBound
, upperBound
;
190 value2CString(_Range
.first
, lowerBound
);
191 value2CString(_Range
.second
, upperBound
);
193 CRangeSelector
rs(lowerBound
, upperBound
, this);
195 if (rs
.DoModal() == IDOK
)
197 string2value(rs
.getLowerBound(), _Range
.first
);
198 string2value(rs
.getUpperBound(), _Range
.second
);
199 CRangeManager
<T
>::SetRange(_Id
, _Range
.first
, _Range
.second
);
203 void updateValueFromSlider(double sliderValue
)
207 T value
= _Range
.first
+ (T
) ((_Range
.second
- _Range
.first
) * sliderValue
);
208 value2CString(value
, m_Value
);
212 _Wrapper
->setAndUpdateModifiedFlag(value
);
218 /// set a new value that will affect both slider and value display
219 void setValue(T value
)
221 value2CString(value
, m_Value
);
223 // _Wrapper->set(value);
225 if (value
< _Range
.first
)
227 m_SliderPos
= (uint
) (m_SliderCtrl
.GetRangeMin());
230 if (value
> _Range
.second
)
232 m_SliderPos
= (uint
) (m_SliderCtrl
.GetRangeMax());
236 if (_Range
.second
!= _Range
.first
)
238 m_SliderPos
= (uint
) ((double) (value
- _Range
.first
) / (_Range
.second
- _Range
.first
) * (m_SliderCtrl
.GetRangeMax() - m_SliderCtrl
.GetRangeMin())
239 + m_SliderCtrl
.GetRangeMin());
243 m_SliderPos
= m_SliderCtrl
.GetRangeMin();
250 virtual bool editableRangeValueValidator(const CString
&lo
, const CString
&up
)
254 const TCHAR
*message
= string2value(lo
, loT
);
257 ::MessageBox(NULL
, message
, _T("Range selection error"), MB_OK
);
260 const TCHAR
*mess
= validateUpperBound(loT
), *mess2
= validateLowerBound(loT
);
263 MessageBox(mess
? mess
: mess2
, _T("error"));
267 message
= string2value(up
, upT
);
270 ::MessageBox(NULL
, message
, _T("Range selection error"), MB_OK
);
274 mess
= validateUpperBound(upT
);
275 mess2
= validateLowerBound(upT
);
278 MessageBox(mess
? mess
: mess2
, _T("error"));
285 ::MessageBox(NULL
, _T("upper bound must be strictly greater than lower bound"), _T("Range selection error"), MB_OK
);
293 std::pair
<T
, T
> _Range
;
295 // wrapper to the particle system
296 IPSWrapper
<T
> *_Wrapper
;
302 ///////////////////////////////////////////////////////
303 // IMPLEMENTATION OF TEMPLATE METHOD SPECIALIZATIONS //
304 ///////////////////////////////////////////////////////
307 ////////////////////////////////////////////////////////
308 // float specialization. //
309 ////////////////////////////////////////////////////////
311 CEditableRangeT
<float>::CEditableRangeT(const std::string
&id
, CParticleWorkspace::CNode
*node
, float defaultMin
, float defaultMax
)
312 : CEditableRange(id
, node
), _Range(defaultMin
, defaultMax
), _Wrapper(NULL
)
316 inline void CEditableRangeT
<float>::value2CString(float value
, CString
&dest
)
318 dest
.Format(_T("%g"), (double) value
);
321 inline const TCHAR
*CEditableRangeT
<float>::string2value(const CString
&value
, float &result
)
323 if (NLMISC::fromString(NLMISC::tStrToUtf8(value
), result
))
329 return _T("invalid value");
333 ////////////////////////////////////////////////////////
334 // uint32 specialization. //
335 ////////////////////////////////////////////////////////
337 CEditableRangeT
<uint32
>::CEditableRangeT(const std::string
&id
, CParticleWorkspace::CNode
*node
, uint32 defaultMin
, uint32 defaultMax
)
338 : CEditableRange(id
, node
), _Range(defaultMin
, defaultMax
), _Wrapper(NULL
)
342 inline void CEditableRangeT
<uint32
>::value2CString(uint32 value
, CString
&dest
)
344 dest
.Format(_T("%d"), value
);
347 inline const TCHAR
*CEditableRangeT
<uint32
>::string2value(const CString
&value
, uint32
&result
)
350 if (NLMISC::fromString(NLMISC::tStrToUtf8(value
), tmp
))
352 if (value
.Find(_T("-")) > -1)
354 return _T("negative values not allowed");
364 return _T("invalid value");
369 ////////////////////////////////////////////////////////
370 // sint32 specialization. //
371 ////////////////////////////////////////////////////////
373 CEditableRangeT
<sint32
>::CEditableRangeT(const std::string
&id
, CParticleWorkspace::CNode
*node
, sint32 defaultMin
, sint32 defaultMax
)
374 : CEditableRange(id
, node
), _Range(defaultMin
, defaultMax
), _Wrapper(NULL
)
378 inline void CEditableRangeT
<sint32
>::value2CString(sint32 value
, CString
&dest
)
380 dest
.Format(_T("%d"), value
);
383 inline const TCHAR
*CEditableRangeT
<sint32
>::string2value(const CString
&value
, sint32
&result
)
386 if (NLMISC::fromString(NLMISC::tStrToUtf8(value
), tmp
))
393 return _T("invalid value");
401 typedef CEditableRangeT
<float> CEditableRangeFloat
;
402 typedef CEditableRangeT
<uint32
> CEditableRangeUInt
;
403 typedef CEditableRangeT
<sint32
> CEditableRangeInt
;
407 //{{AFX_INSERT_LOCATION}}
408 // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
412 #endif // !defined(AFX_EDITABLE_RANGE_H__0B1EFF2B_FA0E_4AC8_88B8_416605043BF9__INCLUDED_)