Radium Engine  1.5.20
Loading...
Searching...
No Matches
ParameterSetEditor.cpp
1#include <Gui/ParameterSetEditor/ParameterSetEditor.hpp>
2
3#include <Core/Containers/VariableSetEnumManagement.hpp>
4#include <Engine/Data/Material.hpp>
5#include <Gui/Widgets/ControlPanel.hpp>
6
7#include <QString>
8#include <QWidget>
9
10#include <limits>
11#include <memory>
12#include <type_traits>
13
14using json = nlohmann::json;
15
16namespace Ra {
17using namespace Engine;
18namespace Gui {
19
20namespace internal {
21class RenderParameterUiBuilder
22{
23 public:
25
26 RenderParameterUiBuilder( VariableSetEditor* pse, const json& constraints ) :
27 m_pse { pse }, m_constraints { constraints } {}
28
29 void operator()( const std::string& name, bool& p, Core::VariableSet&& /* params */ ) {
30 auto onBoolParameterChanged = [pse = this->m_pse, &p, nm = name]( bool val ) {
31 p = val;
32 emit pse->parameterModified( nm );
33 };
34 if ( m_constraints.contains( name ) ) {
35 if ( m_constraints[name]["editable"] ) {
36 const auto& m = m_constraints[name];
37 std::string description = m.contains( "description" ) ? m["description"] : "";
38 std::string nm = m.contains( "name" ) ? std::string { m["name"] } : name;
39 m_pse->addOption( nm, onBoolParameterChanged, p, description );
40 }
41 }
42 else if ( m_pse->showUnspecified() ) {
43 m_pse->addOption( name, onBoolParameterChanged, p );
44 }
45 }
46
47 template <typename TParam, std::enable_if_t<std::is_arithmetic<TParam>::value, bool> = true>
48 void operator()( const std::string& name, TParam& p, Core::VariableSet&& params ) {
49 using namespace Ra::Core::VariableSetEnumManagement;
50 if ( getEnumConverter<TParam>( params, name ) ) {
51 m_pse->addEnumWidget( name, p, params, m_constraints );
52 }
53 else {
54 // case number
55 m_pse->addNumberWidget( name, p, params, m_constraints );
56 }
57 }
58
59 template <typename TParam,
60 typename TAllocator,
61 std::enable_if_t<std::is_arithmetic<TParam>::value, bool> = true>
62 void operator()( const std::string& name,
64 Core::VariableSet&& params ) {
65 m_pse->addVectorWidget( name, p, params, m_constraints );
66 }
67
68 void
69 operator()( const std::string& name, Ra::Core::Utils::Color& p, Core::VariableSet&& params ) {
70 auto onColorParameterChanged =
71 [pse = this->m_pse, &params, nm = name]( const Ra::Core::Utils::Color& val ) {
72 params.setVariable( nm, val );
73 emit pse->parameterModified( nm );
74 };
75 if ( m_constraints.contains( name ) ) {
76 const auto& m = m_constraints[name];
77 std::string description = m.contains( "description" ) ? m["description"] : "";
78 std::string nm = m.contains( "name" ) ? std::string { m["name"] } : name;
79 m_pse->addColorInput( nm, onColorParameterChanged, p, m["maxItems"] == 4, description );
80 }
81 else if ( m_pse->showUnspecified() ) {
82 m_pse->addColorInput( name, onColorParameterChanged, p );
83 }
84 }
85
86 template <template <typename, int...> typename M, typename T, int... dim>
87 void operator()( const std::string& name, M<T, dim...>& p, Core::VariableSet&& params ) {
88 m_pse->addMatrixWidget( name, p, params, m_constraints );
89 }
90
91 void operator()( const std::string& /*name*/,
93 Core::VariableSet&& /*params*/ ) {
94 // textures are not yet editable
95 }
96
97 template <typename T>
98 void operator()( const std::string& name,
100 Core::VariableSet&& /*params*/ ) {
101 m_pse->addLabel( name );
102 if constexpr ( std::is_assignable_v<Core::VariableSet, typename std::decay<T>::type> ) {
103 if constexpr ( std::is_const_v<T> ) {
104 p.get().visit( *this,
105 const_cast<Core::VariableSet&>(
106 static_cast<const Core::VariableSet&>( p.get() ) ) );
107 }
108 else { p.get().visit( *this, static_cast<Core::VariableSet&>( p.get() ) ); }
109 }
110 }
111
112 private:
113 VariableSetEditor* m_pse { nullptr };
114 const json& m_constraints;
115};
116} // namespace internal
117
118VariableSetEditor::VariableSetEditor( const std::string& name, QWidget* parent ) :
119 ControlPanel( name, !name.empty(), parent ) {}
120
121template <typename T>
122void VariableSetEditor::addEnumWidget( const std::string& key,
123 T& initial,
124 Core::VariableSet& params,
125 const json& metadata ) {
126 using namespace Ra::Core::VariableSetEnumManagement;
127 auto m = metadata[key];
128
129 std::string description = m.contains( "description" ) ? m["description"] : "";
130 std::string nm = m.contains( "name" ) ? std::string { m["name"] } : key;
131 if ( auto ec = getEnumConverter<T>( params, key ) ) {
132 auto items = ( *ec )->getEnumerators();
133 auto onEnumParameterStringChanged = [this, &params, &key]( const QString& value ) {
134 params.setVariable( key, value.toStdString() );
135 emit parameterModified( key );
136 };
137 addComboBox( nm,
138 onEnumParameterStringChanged,
139 getEnumString( params, key, initial ),
140 items,
141 description );
142 }
143 else {
144 LOG( Core::Utils::logWARNING )
145 << "ParameterSet don't have converter for enum " << key << " use index<>int instead.";
146
147 auto items = std::vector<std::string>();
148 items.reserve( m["values"].size() );
149 for ( const auto& value : m["values"] ) {
150 items.push_back( value );
151 }
152
153 auto onEnumParameterIntChanged = [this, &params, &key]( T value ) {
154 params.setVariable( key, value );
155 emit parameterModified( key );
156 };
157 addComboBox( nm, onEnumParameterIntChanged, initial, items, description );
158 }
159}
160
161template <typename T>
162void VariableSetEditor::addNumberWidget( const std::string& key,
163 T& initial,
164 Core::VariableSet& /*params*/,
165 const json& metadata ) {
166
167 auto onNumberParameterChanged = [this, &initial, &key]( T value ) {
168 initial = value;
169 emit parameterModified( key );
170 };
171 if ( metadata.contains( key ) ) {
172 auto m = metadata[key];
174 auto max = std::numeric_limits<T>::max();
175
176 std::string description = m.contains( "description" ) ? m["description"] : "";
177 std::string nm = m.contains( "name" ) ? std::string { m["name"] } : key;
178
179 if ( m.contains( "oneOf" ) ) {
180 // the variable has multiple valid bounds
182 bounds.reserve( m["oneOf"].size() );
183 for ( const auto& bound : m["oneOf"] ) {
184 auto mini = bound.contains( "minimum" ) ? T( bound["minimum"] ) : min;
185 auto maxi = bound.contains( "maximum" ) ? T( bound["maximum"] ) : max;
186 bounds.emplace_back( mini, maxi );
187 }
188 auto predicate = [bounds]( T value ) {
189 bool valid = false;
190 auto it = bounds.begin();
191 while ( !valid && it != bounds.end() ) {
192 valid = value >= ( *it ).first && value <= ( *it ).second;
193 ++it;
194 }
195 return valid;
196 };
197
198 addConstrainedNumberInput<T>(
199 nm, onNumberParameterChanged, initial, predicate, description );
200 }
201 else if ( m.contains( "minimum" ) && m.contains( "maximum" ) ) {
202 min = T( m["minimum"] );
203 max = T( m["maximum"] );
204 if constexpr ( std::is_floating_point_v<T> ) {
205 addPowerSliderInput( nm, onNumberParameterChanged, initial, min, max, description );
206 }
207 else { addSliderInput( nm, onNumberParameterChanged, initial, min, max, description ); }
208 }
209 else {
210 min = m.contains( "minimum" ) ? T( m["minimum"] ) : min;
211 max = m.contains( "maximum" ) ? T( m["maximum"] ) : max;
212 addNumberInput<T>( nm, onNumberParameterChanged, initial, min, max, description );
213 }
214 }
215 else if ( m_showUnspecified ) { addNumberInput<T>( key, onNumberParameterChanged, initial ); }
216}
217
218template <typename T>
219void VariableSetEditor::addVectorWidget( const std::string& key,
220 std::vector<T>& initial,
221 Core::VariableSet& /*params*/,
222 const json& metadata ) {
223 auto onVectorParameterChanged = [this, &initial, &key]( const std::vector<T>& value ) {
224 initial = value;
225 emit parameterModified( key );
226 };
227
228 if ( metadata.contains( key ) ) {
229 auto m = metadata[key];
230 std::string description = m.contains( "description" ) ? m["description"] : "";
231 addVectorInput<T>( m["name"], onVectorParameterChanged, initial, description );
232 }
233 else if ( m_showUnspecified ) { addVectorInput<T>( key, onVectorParameterChanged, initial ); }
234}
235
236template <typename T>
237void VariableSetEditor::addMatrixWidget( const std::string& key,
238 T& initial,
239 Core::VariableSet& /*params*/,
240 const json& metadata ) {
241 auto onMatrixParameterChanged = [this, &initial, &key]( const Ra::Core::MatrixN& value ) {
242 initial = T( value );
243 emit parameterModified( key );
244 };
245
246 if ( metadata.contains( key ) ) {
247 auto m = metadata[key];
248 std::string description = m.contains( "description" ) ? m["description"] : "";
249 addMatrixInput( m["name"], onMatrixParameterChanged, initial, 3, description );
250 }
251 else if ( m_showUnspecified ) { addMatrixInput( key, onMatrixParameterChanged, initial ); }
252}
253
254void VariableSetEditor::setupUi( Core::VariableSet& params, const nlohmann::json& constraints ) {
255
256 internal::RenderParameterUiBuilder uiBuilder { this, constraints };
257 params.visit( uiBuilder, params );
258 addStretch( 0 );
259 setVisible( true );
260}
261
262} // namespace Gui
263} // namespace Ra
T begin(T... args)
Heterogeneous container storing "Variables", that maps a name (std::string) to a value (of any type T...
auto setVariable(const std::string &name, const T &value) -> std::pair< VariableHandle< T >, bool >
reset (or set if the variable does not exist yet) the value of the variable.
void visit(F &&visitor) const
Visit the container using a user defined visitor.
Core::Utils::TypeList< bool, Core::Utils::Color, int, uint, Scalar, TextureInfo, std::vector< int >, std::vector< uint >, std::vector< Scalar >, Core::Vector2, Core::Vector3, Core::Vector4, Core::Matrix2, Core::Matrix3, Core::Matrix4, std::reference_wrapper< RenderParameters >, std::reference_wrapper< const RenderParameters > > BindableTypes
List of bindable types, to be used with static visitors.
Simple Widget for RenderParameter editing The editor will expose a control panel containing all of th...
void addNumberWidget(const std::string &name, T &initial, Core::VariableSet &params, const nlohmann::json &metadata)
void addVectorWidget(const std::string &key, std::vector< T > &initial, Core::VariableSet &params, const nlohmann::json &metadata)
void addEnumWidget(const std::string &name, T &initial, Core::VariableSet &params, const nlohmann::json &paramMetadata)
Add a combobox allowing to chose the value of an enumerator.
void addMatrixWidget(const std::string &key, T &initial, Core::VariableSet &params, const nlohmann::json &metadata)
void addColorInput(const std::string &name, const std::function< void(const Ra::Core::Utils::Color &clr)> &callback, Ra::Core::Utils::Color color=Ra::Core::Utils::Color::Black(), bool withAlpha=true, const std::string &tooltip="")
void addLabel(const std::string &text)
void addOption(const std::string &name, std::function< void(bool)> callback, bool set=false, const std::string &tooltip="")
T emplace_back(T... args)
T end(T... args)
T internal(T... args)
T lowest(T... args)
T max(T... args)
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T reserve(T... args)