fw4spl
SParameters.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2018.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "guiQt/editor/SParameters.hpp"
8 
9 #include <fwCom/Signal.hxx>
10 #include <fwCom/Slots.hxx>
11 
12 #include <fwDataTools/Color.hpp>
13 
14 #include <fwGuiQt/container/QtContainer.hpp>
15 
16 #include <fwServices/macros.hpp>
17 
18 #include <fwTools/Object.hpp>
19 
20 #include <boost/foreach.hpp>
21 #include <boost/tokenizer.hpp>
22 
23 #include <QCheckBox>
24 #include <QColorDialog>
25 #include <QComboBox>
26 #include <QFormLayout>
27 #include <QSpinBox>
28 #include <QString>
29 #include <QStyle>
30 
31 namespace guiQt
32 {
33 
34 namespace editor
35 {
36 
37 //-----------------------------------------------------------------------------
38 
39 fwServicesRegisterMacro( ::fwGui::editor::IEditor, ::guiQt::editor::SParameters );
40 
41 static const ::fwCom::Signals::SignalKeyType BOOLEAN_CHANGED_SIG = "boolChanged";
42 static const ::fwCom::Signals::SignalKeyType COLOR_CHANGED_SIG = "colorChanged";
43 static const ::fwCom::Signals::SignalKeyType DOUBLE_CHANGED_SIG = "doubleChanged";
44 static const ::fwCom::Signals::SignalKeyType DOUBLE2_CHANGED_SIG = "double2Changed";
45 static const ::fwCom::Signals::SignalKeyType DOUBLE3_CHANGED_SIG = "double3Changed";
46 static const ::fwCom::Signals::SignalKeyType INTEGER_CHANGED_SIG = "intChanged";
47 static const ::fwCom::Signals::SignalKeyType INTEGER2_CHANGED_SIG = "int2Changed";
48 static const ::fwCom::Signals::SignalKeyType INTEGER3_CHANGED_SIG = "int3Changed";
49 static const ::fwCom::Signals::SignalKeyType ENUM_CHANGED_SIG = "enumChanged";
50 static const ::fwCom::Signals::SignalKeyType ENUM_INDEX_CHANGED_SIG = "enumIndexChanged";
51 
52 static const ::fwCom::Slots::SlotKeyType s_SET_BOOL_PARAMETER_SLOT = "setBoolParameter";
53 static const ::fwCom::Slots::SlotKeyType s_SET_COLOR_PARAMETER_SLOT = "setColorParameter";
54 static const ::fwCom::Slots::SlotKeyType s_SET_DOUBLE_PARAMETER_SLOT = "setDoubleParameter";
55 static const ::fwCom::Slots::SlotKeyType s_SET_DOUBLE2_PARAMETER_SLOT = "setDouble2Parameter";
56 static const ::fwCom::Slots::SlotKeyType s_SET_DOUBLE3_PARAMETER_SLOT = "setDouble3Parameter";
57 static const ::fwCom::Slots::SlotKeyType s_SET_INT_PARAMETER_SLOT = "setIntParameter";
58 static const ::fwCom::Slots::SlotKeyType s_SET_INT2_PARAMETER_SLOT = "setInt2Parameter";
59 static const ::fwCom::Slots::SlotKeyType s_SET_INT3_PARAMETER_SLOT = "setInt3Parameter";
60 static const ::fwCom::Slots::SlotKeyType s_SET_ENUM_PARAMETER_SLOT = "setEnumParameter";
61 static const ::fwCom::Slots::SlotKeyType s_SET_INT_MIN_PARAMETER_SLOT = "setIntMinParameter";
62 static const ::fwCom::Slots::SlotKeyType s_SET_INT_MAX_PARAMETER_SLOT = "setIntMaxParameter";
63 static const ::fwCom::Slots::SlotKeyType s_SET_DOUBLE_MIN_PARAMETER_SLOT = "setDoubleMinParameter";
64 static const ::fwCom::Slots::SlotKeyType s_SET_DOUBLE_MAX_PARAMETER_SLOT = "setDoubleMaxParameter";
65 
66 //-----------------------------------------------------------------------------
67 
69  m_blockSignals(false)
70 {
71  newSignal< BooleanChangedSignalType>(BOOLEAN_CHANGED_SIG);
72  newSignal< ColorChangedSignalType>(COLOR_CHANGED_SIG);
73  newSignal< DoubleChangedSignalType>(DOUBLE_CHANGED_SIG);
74  newSignal< Double2ChangedSignalType>(DOUBLE2_CHANGED_SIG);
75  newSignal< Double3ChangedSignalType>(DOUBLE3_CHANGED_SIG);
76  newSignal< IntegerChangedSignalType>(INTEGER_CHANGED_SIG);
77  newSignal< Integer2ChangedSignalType>(INTEGER2_CHANGED_SIG);
78  newSignal< Integer3ChangedSignalType>(INTEGER3_CHANGED_SIG);
79  newSignal< EnumChangedSignalType >(ENUM_CHANGED_SIG);
80  newSignal< EnumChangedIndexSignalType >(ENUM_INDEX_CHANGED_SIG);
81 
82  newSlot(s_SET_BOOL_PARAMETER_SLOT, &SParameters::setBoolParameter, this);
83  newSlot(s_SET_COLOR_PARAMETER_SLOT, &SParameters::setColorParameter, this);
84  newSlot(s_SET_DOUBLE_PARAMETER_SLOT, &SParameters::setDoubleParameter, this);
85  newSlot(s_SET_DOUBLE2_PARAMETER_SLOT, &SParameters::setDouble2Parameter, this);
86  newSlot(s_SET_DOUBLE3_PARAMETER_SLOT, &SParameters::setDouble3Parameter, this);
87  newSlot(s_SET_INT_PARAMETER_SLOT, &SParameters::setIntParameter, this);
88  newSlot(s_SET_INT2_PARAMETER_SLOT, &SParameters::setInt2Parameter, this);
89  newSlot(s_SET_INT3_PARAMETER_SLOT, &SParameters::setInt3Parameter, this);
90  newSlot(s_SET_ENUM_PARAMETER_SLOT, &SParameters::setEnumParameter, this);
91  newSlot(s_SET_INT_MIN_PARAMETER_SLOT, &SParameters::setIntMinParameter, this);
92  newSlot(s_SET_INT_MAX_PARAMETER_SLOT, &SParameters::setIntMaxParameter, this);
93  newSlot(s_SET_DOUBLE_MIN_PARAMETER_SLOT, &SParameters::setDoubleMinParameter, this);
94  newSlot(s_SET_DOUBLE_MAX_PARAMETER_SLOT, &SParameters::setDoubleMaxParameter, this);
95 }
96 
97 //-----------------------------------------------------------------------------
98 
100 {
101 }
102 
103 //-----------------------------------------------------------------------------
104 
106 {
107  this->initialize();
108 }
109 
110 //-----------------------------------------------------------------------------
111 
113 {
114  this->create();
115 
116  auto qtContainer = ::fwGuiQt::container::QtContainer::dynamicCast(this->getContainer());
117 
118  QGridLayout* layout = new QGridLayout();
119 
120  ::fwServices::IService::ConfigType config = this->getConfigTree();
121  const ::fwServices::IService::ConfigType& parametersCfg = config.get_child("parameters");
122 
123  int row = 0;
124 
125  this->blockSignals(true);
126 
127  // Create widgets
128  BOOST_FOREACH( const auto& param, parametersCfg.equal_range("param") )
129  {
130  const ::fwServices::IService::ConfigType& cfg = param.second;
131 
132  const std::string name = cfg.get< std::string >("<xmlattr>.name");
133  const std::string key = cfg.get< std::string >("<xmlattr>.key");
134  const std::string type = cfg.get< std::string >("<xmlattr>.type");
135  const std::string defaultValue = cfg.get< std::string >("<xmlattr>.defaultValue");
136 
137  layout->addWidget(new QLabel(QString(name.c_str())), row, 0);
138 
139  if(type == "bool")
140  {
141  this->createBoolWidget(*layout, row, key, defaultValue);
142  }
143  else if(type == "color")
144  {
145  this->createColorWidget(*layout, row, key, defaultValue);
146  }
147  else if(type == "double" || type == "double2" || type == "double3")
148  {
149  const std::string widget = cfg.get< std::string >("<xmlattr>.widget", "spin");
150 
151  const double min = cfg.get<double>("<xmlattr>.min", 0.);
152  const double max = cfg.get<double>("<xmlattr>.max", 1.);
153  const double defaultValue = cfg.get<double>("<xmlattr>.defaultValue", 0.5);
154 
155  const int count = (type == "double3") ? 3 : (type == "double2" ? 2 : 1);
156 
157  if(widget == "spin")
158  {
159  this->createDoubleWidget(*layout, row, key, defaultValue, min, max, count);
160  }
161  else if(widget == "slider")
162  {
163  // We don't support multiple sliders because we will not have the room in a single row
164  SLM_ASSERT("Count > 1 is not supported with sliders", count == 1);
165 
166  const std::uint8_t decimals = cfg.get< std::uint8_t >("<xmlattr>.decimals", 2);
167  this->createDoubleSliderWidget(*layout, row, key, defaultValue, min, max, decimals);
168  }
169  else
170  {
171  SLM_ERROR("Unknown widget type : '" + widget + "' for " + name + ". Must be 'spin' or 'slider'.");
172  }
173  }
174  else if(type == "int" || type == "int2" || type == "int3")
175  {
176  const std::string widget = cfg.get< std::string >("<xmlattr>.widget", "slider");
177 
178  const int min = cfg.get<int>("<xmlattr>.min", 0);
179  const int max = cfg.get<int>("<xmlattr>.max", 100);
180  const int defaultValue = cfg.get<int>("<xmlattr>.defaultValue", 50);
181 
182  const int count = (type == "int3") ? 3 : (type == "int2" ? 2 : 1);
183 
184  if(widget == "spin")
185  {
186  this->createIntegerSpinWidget(*layout, row, key, defaultValue, min, max, count);
187  }
188  else if(widget == "slider")
189  {
190  // We don't support multiple sliders because we will not have the room in a single row
191  SLM_ASSERT("Count > 1 is not supported with sliders", count == 1);
192 
193  this->createIntegerSliderWidget(*layout, row, key, defaultValue, min, max);
194  }
195  else
196  {
197  SLM_ERROR("Unknown widget type : '" + widget + "' for " + name + ". Must be 'spin' or 'slider'.");
198  }
199  }
200  else if(type == "enum")
201  {
202  const std::string options = cfg.get<std::string>("<xmlattr>.values");
203 
204  //split values separated by ',', ' ', ';'
205  std::vector<std::string> values;
206  std::vector<std::string> data;
207 
208  const ::boost::char_separator<char> sep(", ;");
209  const ::boost::tokenizer< ::boost::char_separator<char> > tokens {options, sep};
210 
211  for(const auto& token : tokens)
212  {
213  //split again values separated by '='
214  const ::boost::char_separator<char> subsep("=");
215  const ::boost::tokenizer< ::boost::char_separator<char> > subtokens {token, subsep};
216  auto it = subtokens.begin();
217 
218  if(it != subtokens.end() )
219  {
220  values.push_back(*it);
221  ++it;
222  }
223 
224  if(it != subtokens.end() )
225  {
226  data.push_back(*it);
227  ++it;
228  }
229  else
230  {
231  data.push_back(values.back());
232  }
233  }
234 
235  this->createEnumWidget(*layout, row, key, defaultValue, values, data);
236 
237  }
238  ++row;
239  }
240 
241  qtContainer->setLayout(layout);
242 
243  this->blockSignals(false);
244 
245  this->updating(); // emits the signals with the default values
246 }
247 
248 //-----------------------------------------------------------------------------
249 
251 {
252  auto qtContainer = ::fwGuiQt::container::QtContainer::dynamicCast(this->getContainer());
253  QWidget* widget = qtContainer->getQtContainer();
254 
255  ::fwServices::IService::ConfigType config = this->getConfigTree();
256  const ::fwServices::IService::ConfigType& parametersCfg = config.get_child("parameters");
257 
258  // emit signal for each widget
259  BOOST_FOREACH( const auto& param, parametersCfg.equal_range("param") )
260  {
261  const ::fwServices::IService::ConfigType& cfg = param.second;
262 
263  const std::string key = cfg.get< std::string >("<xmlattr>.key");
264  const std::string type = cfg.get< std::string >("<xmlattr>.type");
265 
266  QWidget* child = widget->findChild<QWidget*>(QString::fromStdString(key));
267  if (child)
268  {
269  if(type == "bool")
270  {
271  const QCheckBox* box = dynamic_cast<QCheckBox* >(child);
272  SLM_ASSERT("Widget must be a QCheckBox", box);
273 
274  const bool state = (box->checkState() == Qt::Checked);
275 
276  if (!m_blockSignals)
277  {
278  this->signal<BooleanChangedSignalType>(BOOLEAN_CHANGED_SIG)->asyncEmit(state, key);
279  OSLM_DEBUG("[EMIT] " << BOOLEAN_CHANGED_SIG << "(" << (state ? "true" : "false") << ", " << key <<
280  ")" );
281 
282  }
283  }
284  else if(type == "color")
285  {
286  const QColor colorQt = child->property("color").value<QColor>();
287  this->emitColorSignal(colorQt, key);
288  }
289  else if(type == "double" || type == "double2" || type == "double3")
290  {
291  this->emitDoubleSignal(child);
292  }
293  else if(type == "int" || type == "int2" || type == "int3")
294  {
295  this->emitIntegerSignal(child);
296  }
297  else if(type == "enum")
298  {
299  QComboBox* box = qobject_cast<QComboBox*>(child);
300 
301  SLM_ASSERT("Widget must be a QComboBox", box);
302 
303  const QString data = box->itemData(box->currentIndex()).toString();
304 
305  if (!m_blockSignals)
306  {
307  this->signal<EnumChangedSignalType>(ENUM_CHANGED_SIG)->asyncEmit(data.toStdString(), key);
308  OSLM_DEBUG("[EMIT] " << ENUM_CHANGED_SIG << "(" << data.toStdString() << ", " << key << ")" );
309  this->signal<EnumChangedIndexSignalType>(ENUM_INDEX_CHANGED_SIG)->asyncEmit(box->currentIndex(),
310  key);
311  OSLM_DEBUG("[EMIT] " << ENUM_INDEX_CHANGED_SIG << "(" << box->currentIndex() << ", " << key << ")");
312  }
313  }
314  }
315  }
316 }
317 
318 //-----------------------------------------------------------------------------
319 
321 {
322  this->destroy();
323 }
324 
325 //-----------------------------------------------------------------------------
326 
327 void SParameters::onChangeEnum(int value)
328 {
329  const QObject* sender = this->sender();
330  const QString key = sender->property("key").toString();
331 
332  const QComboBox* box = dynamic_cast<const QComboBox*>(sender);
333 
334  SLM_ASSERT("Wrong widget type", box);
335 
336  const QString data = box->itemData(value).toString();
337 
338  if (!m_blockSignals)
339  {
340  this->signal<EnumChangedSignalType>(ENUM_CHANGED_SIG)->asyncEmit(data.toStdString(), key.toStdString());
341  OSLM_DEBUG("[EMIT] " << ENUM_CHANGED_SIG << "(" << data.toStdString() << ", " << key.toStdString() << ")" );
342  this->signal<EnumChangedIndexSignalType>(ENUM_INDEX_CHANGED_SIG)->asyncEmit(value, key.toStdString());
343  OSLM_DEBUG("[EMIT] " << ENUM_INDEX_CHANGED_SIG << "(" << value << ", " << key.toStdString() << ")" );
344  }
345 }
346 
347 //-----------------------------------------------------------------------------
348 
349 void SParameters::onChangeBoolean(int value)
350 {
351  const QObject* sender = this->sender();
352  const QString key = sender->property("key").toString();
353  const bool checked = value == Qt::Checked;
354 
355  if (!m_blockSignals)
356  {
357  this->signal<BooleanChangedSignalType>(BOOLEAN_CHANGED_SIG)->asyncEmit(checked, key.toStdString());
358  OSLM_DEBUG("[EMIT] " << BOOLEAN_CHANGED_SIG << "(" << (checked ? "true" : "false") << ", " << key.toStdString()
359  << ")" );
360  }
361 }
362 
363 //------------------------------------------------------------------------------
364 
365 void SParameters::onColorButton()
366 {
367  QObject* sender = this->sender();
368 
369  // Create Color choice dialog.
370  auto qtContainer = ::fwGuiQt::container::QtContainer::dynamicCast( this->getContainer() );
371  QWidget* const container = qtContainer->getQtContainer();
372  SLM_ASSERT("container not instanced", container);
373 
374  const QColor oldColor = sender->property("color").value<QColor>();
375  const QColor colorQt = QColorDialog::getColor(oldColor, container);
376  if(colorQt.isValid())
377  {
378  const QString key = sender->property("key").toString();
379 
380  QPushButton* colourButton = dynamic_cast<QPushButton*>(sender);
381  colourButton->setProperty("color", colorQt);
382 
383  int iconSize = colourButton->style()->pixelMetric(QStyle::PM_LargeIconSize);
384  QPixmap pix(iconSize, iconSize);
385  pix.fill(colorQt);
386 
387  colourButton->setIcon(QIcon(pix));
388 
389  this->emitColorSignal(colorQt, key.toStdString());
390  }
391 }
392 
393 //-----------------------------------------------------------------------------
394 
395 void SParameters::onChangeInteger(int )
396 {
397  QObject* sender = this->sender();
398  this->emitIntegerSignal(sender);
399 }
400 
401 //------------------------------------------------------------------------------
402 
403 void SParameters::emitIntegerSignal(QObject* widget)
404 {
405  if (!m_blockSignals)
406  {
407  const QString key = widget->property("key").toString();
408  const int count = widget->property("count").toInt();
409 
410  SLM_ASSERT("Invalid widgets count, must be <= 3", count <= 3);
411 
412  const QSpinBox* spinbox = dynamic_cast<const QSpinBox*>(widget);
413  const QSlider* slider = dynamic_cast<const QSlider*>(widget);
414  SLM_ASSERT("Wrong widget type", spinbox || slider);
415 
416  if(count == 1)
417  {
418  int value;
419  if (spinbox)
420  {
421  value = spinbox->value();
422  }
423  else
424  {
425  value = slider->value();
426  }
427  this->signal<IntegerChangedSignalType>(INTEGER_CHANGED_SIG)->asyncEmit(value, key.toStdString());
428  OSLM_DEBUG("[EMIT] " << INTEGER_CHANGED_SIG << "(" <<value << ", " << key.toStdString() << ")" );
429  }
430  else
431  {
432  int value1;
433  int value2;
434 
435  if(spinbox)
436  {
437  const QSpinBox* spin1 = widget->property("widget#0").value< QSpinBox*>();
438  const QSpinBox* spin2 = widget->property("widget#1").value< QSpinBox*>();
439 
440  value1 = spin1->value();
441  value2 = spin2->value();
442  }
443  else
444  {
445  const QSlider* spin1 = widget->property("widget#0").value< QSlider*>();
446  const QSlider* spin2 = widget->property("widget#1").value< QSlider*>();
447 
448  value1 = spin1->value();
449  value2 = spin2->value();
450 
451  }
452  if(count == 2)
453  {
454  this->signal<Integer2ChangedSignalType>(INTEGER2_CHANGED_SIG)->asyncEmit(value1, value2,
455  key.toStdString());
456  OSLM_DEBUG("[EMIT] " << INTEGER2_CHANGED_SIG << "(" << value1 << ", " << value2 << ", " <<
457  key.toStdString() << ")" );
458  }
459  else
460  {
461  int value3;
462  if(spinbox)
463  {
464  const QSpinBox* spin3 = widget->property("widget#2").value< QSpinBox*>();
465  value3 = spin3->value();
466  }
467  else
468  {
469  const QSlider* spin3 = widget->property("widget#2").value< QSlider*>();
470  value3 = spin3->value();
471  }
472 
473  this->signal<Integer3ChangedSignalType>(INTEGER3_CHANGED_SIG)->asyncEmit(value1, value2, value3,
474  key.toStdString());
475  OSLM_DEBUG("[EMIT] " << INTEGER3_CHANGED_SIG << "(" << value1 << ", " << value2 << ", " << value3 <<
476  ", " << key.toStdString() << ")" );
477  }
478  }
479  }
480 }
481 
482 //-----------------------------------------------------------------------------
483 
484 void SParameters::onChangeDouble(double)
485 {
486  QObject* sender = this->sender();
487  this->emitDoubleSignal(sender);
488 }
489 
490 //------------------------------------------------------------------------------
491 
492 void SParameters::emitDoubleSignal(QObject* widget)
493 {
494  if (!m_blockSignals)
495  {
496  const QString key = widget->property("key").toString();
497  const int count = widget->property("count").toInt();
498 
499  QDoubleSpinBox* spinbox = qobject_cast<QDoubleSpinBox*>(widget);
500  QSlider* slider = qobject_cast<QSlider*>(widget);
501 
502  if (slider)
503  {
504  const double value = this->getDoubleSliderValue(slider);
505  this->signal<DoubleChangedSignalType>(DOUBLE_CHANGED_SIG)->asyncEmit(value, key.toStdString());
506  OSLM_DEBUG("[EMIT] " << DOUBLE_CHANGED_SIG << "(" << value << ", " << key.toStdString() << ")" );
507  }
508  else if (spinbox)
509  {
510  SLM_ASSERT("Invalid widgets count, must be <= 3", count <= 3);
511 
512  if(count == 1)
513  {
514  this->signal<DoubleChangedSignalType>(DOUBLE_CHANGED_SIG)->asyncEmit(spinbox->value(),
515  key.toStdString());
516  OSLM_DEBUG("[EMIT] " << DOUBLE_CHANGED_SIG << "(" << spinbox->value() << ", "
517  << key.toStdString() << ")" );
518 
519  }
520  else
521  {
522  const QDoubleSpinBox* spin1 = spinbox->property("widget#0").value< QDoubleSpinBox*>();
523  const QDoubleSpinBox* spin2 = spinbox->property("widget#1").value< QDoubleSpinBox*>();
524 
525  const double value1 = spin1->value();
526  const double value2 = spin2->value();
527 
528  if(count == 2)
529  {
530  this->signal<Double2ChangedSignalType>(DOUBLE2_CHANGED_SIG)->asyncEmit(value1, value2,
531  key.toStdString());
532  OSLM_DEBUG("[EMIT] " << DOUBLE2_CHANGED_SIG << "(" << value1 << ", " << value2
533  << ", " << key.toStdString() << ")" );
534 
535  }
536  else
537  {
538  const QDoubleSpinBox* spin3 = spinbox->property("widget#2").value< QDoubleSpinBox*>();
539  const double value3 = spin3->value();
540 
541  this->signal<Double3ChangedSignalType>(DOUBLE3_CHANGED_SIG)->asyncEmit(value1, value2, value3,
542  key.toStdString());
543  OSLM_DEBUG("[EMIT] " << DOUBLE3_CHANGED_SIG << "(" << value1 << ", " << value2
544  << ", " << value3 << ", " << key.toStdString() << ")" );
545  }
546  }
547  }
548  }
549 }
550 
551 //-----------------------------------------------------------------------------
552 
553 void SParameters::onChangeDoubleSlider(int)
554 {
555  QSlider* sender = qobject_cast<QSlider*>(this->sender());
556  this->emitDoubleSignal(sender);
557 }
558 
559 //-----------------------------------------------------------------------------
560 
561 void SParameters::onSliderMapped(QLabel* label, QSlider* slider)
562 {
563  label->setText(QString::number(slider->value()));
564 }
565 
566 //-----------------------------------------------------------------------------
567 
568 void SParameters::onSliderRangeMapped(QLabel* minLabel, QLabel* maxLabel, QSlider* slider)
569 {
570  const int min = slider->minimum();
571  const int max = slider->maximum();
572 
573  minLabel->setText(QString::number(min));
574  maxLabel->setText(QString::number(max));
575 }
576 
577 //-----------------------------------------------------------------------------
578 
579 void SParameters::onDoubleSliderMapped(QLabel* label, QSlider* slider)
580 {
581  const double newValue = getDoubleSliderValue(slider);
582  const int decimals = slider->property("decimals").toInt();
583 
584  label->setText(QString::number(newValue, 'f', decimals));
585 }
586 
587 //-----------------------------------------------------------------------------
588 
589 void SParameters::onDoubleSliderRangeMapped(QLabel* minLabel, QLabel* maxLabel, QSlider* slider)
590 {
591  const double min = slider->property("min").toDouble();
592  const double max = slider->property("max").toDouble();
593  const int decimals = slider->property("decimals").toInt();
594 
595  minLabel->setText(QString::number(min, 'g', decimals));
596  maxLabel->setText(QString::number(max, 'g', decimals));
597 }
598 
599 //-----------------------------------------------------------------------------
600 
601 void SParameters::onResetBooleanMapped(QWidget* widget)
602 {
603  QCheckBox* checkbox = qobject_cast<QCheckBox*>(widget);
604  if (checkbox)
605  {
606  int value = checkbox->property("defaultValue").toInt();
607  checkbox->setCheckState(::Qt::CheckState(value));
608 
609  const QString key = checkbox->property("key").toString();
610  if (!m_blockSignals)
611  {
612  this->signal<BooleanChangedSignalType>(BOOLEAN_CHANGED_SIG)->asyncEmit(value, key.toStdString());
613  OSLM_DEBUG("[EMIT] " << BOOLEAN_CHANGED_SIG << "(" << (value ? "true" : "false") << ", "
614  << key.toStdString() << ")" );
615  }
616  }
617 }
618 
619 //-----------------------------------------------------------------------------
620 
621 void SParameters::onResetColorMapped(QWidget* widget)
622 {
623  QPushButton* colourButton = qobject_cast<QPushButton*>(widget);
624  if (colourButton)
625  {
626  const QColor color = colourButton->property("defaultValue").value<QColor>();
627  const QString key = colourButton->property("key").toString();
628 
629  int iconSize = colourButton->style()->pixelMetric(QStyle::PM_LargeIconSize);
630  QPixmap pix(iconSize, iconSize);
631  pix.fill(color);
632 
633  colourButton->setIcon(QIcon(pix));
634  colourButton->setProperty("color", color);
635 
636  const std::array<std::uint8_t, 4> newColor = {{ static_cast<std::uint8_t>(color.red()),
637  static_cast<std::uint8_t>(color.green()),
638  static_cast<std::uint8_t>(color.blue()),
639  static_cast<std::uint8_t>(color.alpha()) }};
640  if (!m_blockSignals)
641  {
642  this->signal<ColorChangedSignalType>(COLOR_CHANGED_SIG)->asyncEmit(newColor, key.toStdString());
643  OSLM_DEBUG("[EMIT] " << COLOR_CHANGED_SIG << "(" << int(newColor[0]) << ", "
644  << int(newColor[1]) << ", " << int(newColor[2]) << ", " << int(newColor[3]) << ", "
645  << key.toStdString() << ")" );
646  }
647  }
648 }
649 
650 //-----------------------------------------------------------------------------
651 
652 void SParameters::onResetIntegerMapped(QWidget* widget)
653 {
654  QSlider* slider = dynamic_cast<QSlider*>(widget);
655  QSpinBox* spinbox = dynamic_cast<QSpinBox*>(widget);
656  this->blockSignals(true);
657  if (slider)
658  {
659  const int value = slider->property("defaultValue").toInt();
660  slider->setValue(value);
661  }
662  else if (spinbox)
663  {
664  const QString key = spinbox->property("key").toString();
665  const int value = spinbox->property("defaultValue").toInt();
666  const int count = spinbox->property("count").toInt();
667  SLM_ASSERT("Invalid widgets count, must be <= 3", count <= 3);
668 
669  QSpinBox* spin1 = spinbox->property("widget#0").value< QSpinBox*>();
670  spin1->setValue(value);
671 
672  if(count > 1)
673  {
674  QSpinBox* spin2 = spinbox->property("widget#1").value< QSpinBox*>();
675  spin2->setValue(value);
676 
677  if(count == 3)
678  {
679 
680  QSpinBox* spin3 = spinbox->property("widget#2").value< QSpinBox*>();
681  spin3->setValue(value);
682  }
683  }
684  }
685  this->blockSignals(false);
686  this->emitIntegerSignal(widget);
687 }
688 
689 //-----------------------------------------------------------------------------
690 
691 void SParameters::onResetDoubleMapped(QWidget* widget)
692 {
693  QDoubleSpinBox* spinbox = qobject_cast<QDoubleSpinBox*>(widget);
694  QSlider* slider = qobject_cast<QSlider*>(widget);
695 
696  this->blockSignals(true);
697  if (slider)
698  {
699  const double value = slider->property("defaultValue").toDouble();
700  const double min = slider->property("min").toDouble();
701  const double max = slider->property("max").toDouble();
702  const double valueRange = max - min;
703  const int sliderVal = int(std::round(((value - min) / valueRange) * double(slider->maximum())));
704  slider->setValue(sliderVal);
705  }
706  else if (spinbox)
707  {
708  const QString key = spinbox->property("key").toString();
709  const double value = spinbox->property("defaultValue").toDouble();
710  const int count = spinbox->property("count").toInt();
711  SLM_ASSERT("Invalid widgets count, must be <= 3", count <= 3);
712 
713  QDoubleSpinBox* spin1 = spinbox->property("widget#0").value< QDoubleSpinBox*>();
714  spin1->setValue(value);
715 
716  if(count > 1)
717  {
718  QDoubleSpinBox* spin2 = spinbox->property("widget#1").value< QDoubleSpinBox*>();
719  spin2->setValue(value);
720 
721  if(count == 3)
722  {
723 
724  QDoubleSpinBox* spin3 = spinbox->property("widget#2").value< QDoubleSpinBox*>();
725  spin3->setValue(value);
726  }
727  }
728  }
729  this->blockSignals(false);
730  this->emitDoubleSignal(widget);
731 
732 }
733 
734 //-----------------------------------------------------------------------------
735 
736 QPushButton* SParameters::createResetButton()
737 {
738  QPushButton* resetButton = new QPushButton( "R" );
739  resetButton->setFocusPolicy(Qt::NoFocus);
740  resetButton->setToolTip("Reset to the default value.");
741  resetButton->setMaximumWidth(20);
742 
743  return resetButton;
744 }
745 
746 //-----------------------------------------------------------------------------
747 
748 void SParameters::createBoolWidget(QGridLayout& layout, int row,
749  const std::string& key,
750  const std::string& defaultValue)
751 {
752  QCheckBox* checkbox = new QCheckBox();
753  checkbox->setTristate(false);
754  checkbox->setObjectName(QString::fromStdString(key));
755 
756  if(defaultValue == "true")
757  {
758  checkbox->setCheckState(Qt::Checked);
759  }
760 
761  checkbox->setProperty("key", QString(key.c_str()));
762  checkbox->setProperty("defaultValue", checkbox->checkState());
763 
764  // Reset button
765  QPushButton* resetButton = this->createResetButton();
766 
767  layout.addWidget(checkbox, row, 2);
768  layout.addWidget(resetButton, row, 5);
769 
770  QObject::connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(onChangeBoolean(int)));
771 
772  // Connect reset button to the slider
773  QObject::connect(resetButton, &QPushButton::clicked, this, [ = ] { onResetBooleanMapped(checkbox); });
774 }
775 
776 //-----------------------------------------------------------------------------
777 
778 void SParameters::createColorWidget(QGridLayout& layout, int row, const std::string& key,
779  const std::string& defaultValue)
780 {
781  // Reset button
782  QPushButton* resetButton = this->createResetButton();
783 
784  QPushButton* colourButton = new QPushButton("Color");
785  colourButton->setObjectName(QString::fromStdString(key));
786  colourButton->setToolTip(tr("Selected color"));
787  colourButton->setMinimumSize(120, 35);
788 
789  std::string colorStr = "#ffffffff";
790  if(!defaultValue.empty())
791  {
792  std::uint8_t color[4];
793 
794  ::fwDataTools::Color::hexaStringToRGBA(defaultValue, color);
795 
796  colorStr = defaultValue;
797  }
798 
799  std::uint8_t color[4];
801 
802  const int iconSize = colourButton->style()->pixelMetric(QStyle::PM_LargeIconSize);
803  QPixmap pix(iconSize, iconSize);
804 
805  QColor colorQt(color[0], color[1], color[2], color[3]);
806  pix.fill(colorQt);
807 
808  colourButton->setIcon(QIcon(pix));
809 
810  colourButton->setProperty("key", QString(key.c_str()));
811  colourButton->setProperty("defaultValue", colorQt);
812  colourButton->setProperty("color", colorQt);
813 
814  layout.addWidget(colourButton, row, 2);
815  layout.addWidget(resetButton, row, 5);
816 
817  QObject::connect(colourButton, SIGNAL(clicked()), this, SLOT(onColorButton()));
818 
819  // Connect reset button to the button
820  QObject::connect(resetButton, &QPushButton::clicked, this, [ = ] { onResetColorMapped(colourButton); });
821 }
822 
823 //-----------------------------------------------------------------------------
824 
825 void SParameters::createDoubleWidget(QGridLayout& layout, int row, const std::string& key,
826  double defaultValue, double min, double max, int count)
827 {
828  // Reset button
829  QPushButton* resetButton = this->createResetButton();
830 
831  layout.addWidget(resetButton, row, 5);
832 
833  QDoubleSpinBox* spinboxes[3];
834 
835  // Spinboxes
836  for(int i = 0; i < count; ++i)
837  {
838  QDoubleSpinBox* spinbox = new QDoubleSpinBox();
839  spinboxes[i] = spinbox;
840 
841  auto countDecimals = [](double _num) -> int
842  {
843  std::stringstream out;
844  out << _num;
845  const std::string s = out.str();
846  const std::string t = s.substr(s.find(".") + 1);
847  return static_cast<int>(t.length());
848  };
849 
850  spinbox->setDecimals(std::max( std::max(countDecimals(min), countDecimals(max)), 2));
851 
852  spinbox->setRange(min, max);
853 
854  // Beware, set setSingleStep after setRange() and setDecimals() otherwise it may fail
855  spinbox->setSingleStep(std::abs(spinbox->maximum() - spinbox->minimum()) / 100.);
856 
857  // Set value last only after setting range and decimals, otherwise the value may be truncated
858  spinbox->setValue(defaultValue);
859 
860  spinbox->setProperty("key", QString(key.c_str()));
861  spinbox->setProperty("count", count);
862  spinbox->setProperty("defaultValue", spinbox->value());
863 
864  layout.addWidget(spinbox, row, 2 + i);
865 
866  QObject::connect(spinbox, SIGNAL(valueChanged(double)), this, SLOT(onChangeDouble(double)));
867  }
868 
869  QDoubleSpinBox* spinbox = spinboxes[0];
870  spinbox->setObjectName(QString::fromStdString(key));
871 
872  // Connect reset button to the slider
873  QObject::connect(resetButton, &QPushButton::clicked, this, [ = ] { onResetDoubleMapped(spinbox); });
874 
875  // Set a property with a pointer on each member of the group
876  for(int i = 0; i < count; ++i)
877  {
878  for(int j = 0; j < count; ++j)
879  {
880  const std::string propName = std::string("widget#") + std::to_string(j);
881  spinboxes[i]->setProperty(propName.c_str(), QVariant::fromValue< QDoubleSpinBox*>(spinboxes[j]));
882  }
883  }
884 }
885 
886 //-----------------------------------------------------------------------------
887 
888 void SParameters::createDoubleSliderWidget(QGridLayout& layout, int row, const std::string& key,
889  double defaultValue, double min, double max, std::uint8_t decimals)
890 {
891  // Reset button
892  QPushButton* resetButton = this->createResetButton();
893 
894  layout.addWidget(resetButton, row, 5);
895 
896  const double valueRange = max - min;
897 
898  QSlider* slider = new QSlider(Qt::Horizontal);
899  slider->setObjectName(QString::fromStdString(key));
900 
901  slider->setProperty("key", QString::fromStdString(key));
902  slider->setProperty("count", 1);
903  slider->setProperty("defaultValue", defaultValue);
904  slider->setProperty("decimals", decimals);
905  slider->setProperty("min", min);
906  slider->setProperty("max", max);
907 
908  setDoubleSliderRange(slider, defaultValue);
909 
910  const int defaultSliderValue = int(std::round(((defaultValue - min) / valueRange) * double(slider->maximum())));
911  slider->setValue(defaultSliderValue);
912 
913  QFont font;
914  font.setPointSize(7);
915  font.setItalic(true);
916 
917  QLabel* minValueLabel = new QLabel();
918  minValueLabel->setFont(font);
919  minValueLabel->setText(QString::number(min, 'g', decimals));
920  minValueLabel->setToolTip("Minimum value.");
921 
922  QLabel* maxValueLabel = new QLabel();
923  maxValueLabel->setFont(font);
924  maxValueLabel->setText(QString::number(max, 'g', decimals));
925  maxValueLabel->setToolTip("Maximum value.");
926 
927  QLabel* valueLabel = new QLabel();
928  valueLabel->setStyleSheet("QLabel { font: bold; }");
929  valueLabel->setText(QString::number(defaultValue, 'f', decimals));
930  valueLabel->setToolTip("Current value.");
931  this->setLabelMinimumSize(valueLabel, min, max, decimals);
932 
933  layout.addWidget( minValueLabel, row, 1 );
934  layout.addWidget( slider, row, 2 );
935  layout.addWidget( maxValueLabel, row, 3 );
936  layout.addWidget( valueLabel, row, 4);
937  layout.addWidget( resetButton, row, 5);
938 
939  // Connect slider value with our editor
940  QObject::connect(slider, SIGNAL(valueChanged(int)), this, SLOT(onChangeDoubleSlider(int)));
941 
942  // Connect slider value to the label
943  QObject::connect(slider, &QSlider::valueChanged, this, [ = ] {onDoubleSliderMapped(valueLabel, slider); });
944  QObject::connect(slider, &QSlider::rangeChanged, this, [ = ]
945  {
946  onDoubleSliderRangeMapped(minValueLabel,
947  maxValueLabel, slider);
948  });
949 
950  QObject::connect(resetButton, &QPushButton::clicked, this, [ = ] { onResetDoubleMapped(slider); });
951 
952  const std::string propName = std::string("widget#0");
953  slider->setProperty(propName.c_str(), QVariant::fromValue< QSlider*>(slider));
954 }
955 
956 //-----------------------------------------------------------------------------
957 
958 void SParameters::createIntegerSliderWidget(QGridLayout& layout, int row, const std::string& key,
959  int defaultValue, int min, int max)
960 {
961  // Reset button
962  QPushButton* resetButton = this->createResetButton();
963 
964  QSlider* slider = new QSlider(Qt::Horizontal);
965  slider->setObjectName(QString::fromStdString(key));
966  slider->setMinimum(min);
967  slider->setMaximum(max);
968  slider->setValue(defaultValue);
969 
970  QFont font;
971  font.setPointSize(7);
972  font.setItalic(true);
973 
974  QLabel* minValueLabel = new QLabel();
975  minValueLabel->setFont(font);
976  minValueLabel->setText(QString::number(slider->minimum()));
977  minValueLabel->setToolTip("Minimum value.");
978 
979  QLabel* maxValueLabel = new QLabel();
980  maxValueLabel->setFont(font);
981  maxValueLabel->setText(QString::number(slider->maximum()));
982  maxValueLabel->setToolTip("Maximum value.");
983 
984  QLabel* valueLabel = new QLabel();
985  valueLabel->setStyleSheet("QLabel { font: bold; }");
986  valueLabel->setText(QString("%1").arg(slider->value()));
987  valueLabel->setToolTip("Current value.");
988  this->setLabelMinimumSize(valueLabel, min, max);
989 
990  layout.addWidget( minValueLabel, row, 1 );
991  layout.addWidget( slider, row, 2 );
992  layout.addWidget( maxValueLabel, row, 3 );
993  layout.addWidget( valueLabel, row, 4);
994  layout.addWidget( resetButton, row, 5);
995 
996  slider->setProperty("key", QString(key.c_str()));
997  slider->setProperty("count", 1);
998  slider->setProperty("defaultValue", slider->value());
999 
1000  // Connect slider value with our editor
1001  QObject::connect(slider, SIGNAL(valueChanged(int)), this, SLOT(onChangeInteger(int)));
1002 
1003  // Connect slider value to the label
1004  QObject::connect(slider, &QSlider::valueChanged, this, [ = ] {onSliderMapped(valueLabel, slider); });
1005  QObject::connect(slider, &QSlider::rangeChanged, this, [ = ]
1006  {
1007  onSliderRangeMapped(minValueLabel, maxValueLabel,
1008  slider);
1009  });
1010 
1011  QObject::connect(resetButton, &QPushButton::clicked, this, [ = ] { onResetIntegerMapped(slider); });
1012 
1013  const std::string propName = std::string("widget#0");
1014  slider->setProperty(propName.c_str(), QVariant::fromValue< QSlider*>(slider));
1015 }
1016 
1017 //-----------------------------------------------------------------------------
1018 
1019 void SParameters::createIntegerSpinWidget(QGridLayout& layout, int row, const std::string& key,
1020  int defaultValue, int min, int max, int count)
1021 {
1022  // Reset button
1023  QPushButton* resetButton = this->createResetButton();
1024 
1025  layout.addWidget(resetButton, row, 5);
1026 
1027  QSpinBox* spinboxes[3];
1028 
1029  // Spinboxes
1030  for(int i = 0; i < count; ++i)
1031  {
1032  QSpinBox* spinbox = new QSpinBox();
1033  spinboxes[i] = spinbox;
1034 
1035  spinbox->setMinimum(min);
1036  spinbox->setMaximum(max);
1037  spinbox->setValue(defaultValue);
1038 
1039  spinbox->setProperty("key", QString(key.c_str()));
1040  spinbox->setProperty("count", count);
1041  spinbox->setProperty("defaultValue", spinbox->value());
1042 
1043  layout.addWidget(spinbox, row, i + 2);
1044 
1045  // Connect spinbox value with our editor
1046  QObject::connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(onChangeInteger(int)));
1047  }
1048 
1049  QSpinBox* spinbox = spinboxes[0];
1050  spinbox->setObjectName(QString::fromStdString(key));
1051  QObject::connect(resetButton, &QPushButton::clicked, this, [ = ] { onResetIntegerMapped(spinbox); });
1052 
1053  // Set a property with a pointer on each member of the group
1054  for(int i = 0; i < count; ++i)
1055  {
1056  for(int j = 0; j < count; ++j)
1057  {
1058  const std::string propName = std::string("widget#") + std::to_string(j);
1059  spinboxes[i]->setProperty(propName.c_str(), QVariant::fromValue< QSpinBox*>(spinboxes[j]));
1060  }
1061  }
1062 }
1063 
1064 //-----------------------------------------------------------------------------
1065 
1066 void SParameters::createEnumWidget(QGridLayout& layout, int row, const std::string& key,
1067  const std::string& defaultValue,
1068  const std::vector<std::string>& values,
1069  const std::vector<std::string>& data)
1070 {
1071  QComboBox* menu = new QComboBox();
1072  menu->setObjectName(QString::fromStdString(key));
1073 
1074  menu->setProperty("key", QString(key.c_str()));
1075  int idx = 0;
1076  for(const auto& value : values)
1077  {
1078  menu->insertItem(idx, QString::fromStdString(value));
1079  ++idx;
1080  }
1081 
1082  // Add optional data
1083  idx = 0;
1084  for(const auto& choice : data)
1085  {
1086  menu->setItemData(idx, QString::fromStdString(choice));
1087  ++idx;
1088  }
1089 
1090  layout.addWidget(menu, row, 2);
1091 
1092  QObject::connect(menu, SIGNAL(currentIndexChanged(int)), this, SLOT(onChangeEnum(int)));
1093 
1094  //Set the comboBox to the default value
1095  menu->setCurrentText(QString::fromStdString(defaultValue));
1096 }
1097 
1098 //-----------------------------------------------------------------------------
1099 
1100 double SParameters::getDoubleSliderValue(const QSlider* slider)
1101 {
1102  const double min = slider->property("min").toDouble();
1103  const double max = slider->property("max").toDouble();
1104 
1105  const double valueRange = max - min;
1106  double doubleValue = min;
1107  if (slider->maximum() != 0)
1108  {
1109  doubleValue = (double(slider->value()) / slider->maximum()) * valueRange + min;
1110  }
1111 
1112  return doubleValue;
1113 }
1114 
1115 //------------------------------------------------------------------------------
1116 
1117 void SParameters::setBoolParameter(bool val, std::string key)
1118 {
1119  this->blockSignals(true);
1120  QWidget* child = this->getParamWidget(key);
1121  QCheckBox* checkbox = qobject_cast<QCheckBox*>(child);
1122 
1123  if (checkbox)
1124  {
1125  checkbox->setCheckState(val ? Qt::Checked : Qt::Unchecked);
1126  }
1127  this->blockSignals(false);
1128 }
1129 
1130 //------------------------------------------------------------------------------
1131 
1132 void SParameters::setColorParameter(std::array<std::uint8_t, 4> color, std::string key)
1133 {
1134  this->blockSignals(true);
1135  QWidget* child = this->getParamWidget(key);
1136  QPushButton* colorButton = qobject_cast<QPushButton* >(child);
1137 
1138  if (colorButton)
1139  {
1140  const int iconSize = colorButton->style()->pixelMetric(QStyle::PM_LargeIconSize);
1141  QPixmap pix(iconSize, iconSize);
1142  QColor colorQt(color[0], color[1], color[2], color[3]);
1143  pix.fill(colorQt);
1144 
1145  colorButton->setIcon(QIcon(pix));
1146  colorButton->setProperty("color", colorQt);
1147  }
1148  this->blockSignals(false);
1149 }
1150 //------------------------------------------------------------------------------
1151 
1152 void SParameters::setDoubleParameter(double val, std::string key)
1153 {
1154  this->blockSignals(true);
1155  QWidget* child = this->getParamWidget(key);
1156 
1157  QDoubleSpinBox* spinbox = qobject_cast<QDoubleSpinBox*>(child);
1158  QSlider* slider = qobject_cast<QSlider*>(child);
1159 
1160  if (spinbox)
1161  {
1162  spinbox->setValue(val);
1163  }
1164  else if (slider)
1165  {
1166  const double min = slider->property("min").toDouble();
1167  const double max = slider->property("max").toDouble();
1168  const double valueRange = max - min;
1169  const int sliderVal = int(std::round(((val - min) / valueRange) * double(slider->maximum())));
1170  slider->setValue(sliderVal);
1171  }
1172  else
1173  {
1174  SLM_ERROR("Widget '" + key + "' must be a QSlider or a QDoubleSpinBox");
1175  }
1176  this->blockSignals(false);
1177 }
1178 //------------------------------------------------------------------------------
1179 
1180 void SParameters::setDouble2Parameter(double val0, double val1, std::string key)
1181 {
1182  this->blockSignals(true);
1183  QWidget* child = this->getParamWidget(key);
1184 
1185  if (child)
1186  {
1187  QDoubleSpinBox* spin0 = child->property("widget#0").value< QDoubleSpinBox*>();
1188  QDoubleSpinBox* spin1 = child->property("widget#1").value< QDoubleSpinBox*>();
1189 
1190  spin0->setValue(val0);
1191  spin1->setValue(val1);
1192  }
1193  this->blockSignals(false);
1194 }
1195 //------------------------------------------------------------------------------
1196 
1197 void SParameters::setDouble3Parameter(double val0, double val1, double val2, std::string key)
1198 {
1199  this->blockSignals(true);
1200  QWidget* child = this->getParamWidget(key);
1201 
1202  if (child)
1203  {
1204  QDoubleSpinBox* spin0 = child->property("widget#0").value< QDoubleSpinBox*>();
1205  QDoubleSpinBox* spin1 = child->property("widget#1").value< QDoubleSpinBox*>();
1206  QDoubleSpinBox* spin2 = child->property("widget#2").value< QDoubleSpinBox*>();
1207 
1208  spin0->setValue(val0);
1209  spin1->setValue(val1);
1210  spin2->setValue(val2);
1211  }
1212  this->blockSignals(false);
1213 }
1214 
1215 //------------------------------------------------------------------------------
1216 
1217 void SParameters::setIntParameter(int val, std::string key)
1218 {
1219  this->blockSignals(true);
1220  QWidget* child = this->getParamWidget(key);
1221 
1222  QSpinBox* spinbox = qobject_cast<QSpinBox*>(child);
1223  QSlider* slider = qobject_cast<QSlider*>(child);
1224 
1225  if (spinbox)
1226  {
1227  spinbox->setValue(val);
1228  }
1229  else if (slider)
1230  {
1231  slider->setValue(val);
1232  }
1233  else
1234  {
1235  SLM_ERROR("Widget '" + key + "' must be a QSlider or a QDoubleSpinBox");
1236  }
1237  this->blockSignals(false);
1238 }
1239 //------------------------------------------------------------------------------
1240 
1241 void SParameters::setInt2Parameter(int val0, int val1, std::string key)
1242 {
1243  this->blockSignals(true);
1244  QWidget* child = this->getParamWidget(key);
1245 
1246  if (child)
1247  {
1248  QSpinBox* spin0 = child->property("widget#0").value< QSpinBox*>();
1249  QSpinBox* spin1 = child->property("widget#1").value< QSpinBox*>();
1250 
1251  spin0->setValue(val0);
1252  spin1->setValue(val1);
1253  }
1254  this->blockSignals(false);
1255 }
1256 //------------------------------------------------------------------------------
1257 
1258 void SParameters::setInt3Parameter(int val0, int val1, int val2, std::string key)
1259 {
1260  this->blockSignals(true);
1261  QWidget* widget = this->getParamWidget(key);
1262 
1263  if (widget)
1264  {
1265  QSpinBox* spin0 = widget->property("widget#0").value< QSpinBox*>();
1266  QSpinBox* spin1 = widget->property("widget#1").value< QSpinBox*>();
1267  QSpinBox* spin2 = widget->property("widget#2").value< QSpinBox*>();
1268 
1269  spin0->setValue(val0);
1270  spin1->setValue(val1);
1271  spin2->setValue(val2);
1272  }
1273  this->blockSignals(false);
1274 }
1275 //------------------------------------------------------------------------------
1276 
1277 void SParameters::setEnumParameter(std::string val, std::string key)
1278 {
1279  QWidget* widget = this->getParamWidget(key);
1280 
1281  QComboBox* combobox = qobject_cast<QComboBox*>(widget);
1282 
1283  if (combobox)
1284  {
1285  combobox->setCurrentText(QString::fromStdString(val));
1286  }
1287  this->blockSignals(false);
1288 }
1289 
1290 //-----------------------------------------------------------------------------
1291 
1292 void SParameters::emitColorSignal(const QColor color, const std::string& key)
1293 {
1294  const std::array<std::uint8_t, 4> newColor = {{ static_cast<std::uint8_t>(color.red()),
1295  static_cast<std::uint8_t>(color.green()),
1296  static_cast<std::uint8_t>(color.blue()),
1297  static_cast<std::uint8_t>(color.alpha()) }};
1298  if (!m_blockSignals)
1299  {
1300  this->signal<ColorChangedSignalType>(COLOR_CHANGED_SIG)->asyncEmit(newColor, key);
1301  OSLM_DEBUG("[EMIT] " << COLOR_CHANGED_SIG << "(" << int(newColor[0]) << ", " <<
1302  int(newColor[1]) << ", " << int(newColor[2]) << ", " << int(newColor[3]) << ", " << key << ")" );
1303  }
1304 }
1305 
1306 //-----------------------------------------------------------------------------
1307 
1308 void SParameters::blockSignals(bool block)
1309 {
1310  m_blockSignals = block;
1311 }
1312 
1313 //------------------------------------------------------------------------------
1314 
1315 void SParameters::setIntMinParameter(int min, std::string key)
1316 {
1317  QWidget* child = this->getParamWidget(key);
1318 
1319  QSpinBox* spinbox = qobject_cast<QSpinBox*>(child);
1320  QSlider* slider = qobject_cast<QSlider*>(child);
1321 
1322  if (spinbox)
1323  {
1324  const int count = child->property("count").toInt();
1325  QSpinBox* spin0 = child->property("widget#0").value< QSpinBox*>();
1326  spin0->setMinimum(min);
1327 
1328  if (count >= 2)
1329  {
1330  QSpinBox* spin1 = child->property("widget#1").value< QSpinBox*>();
1331  spin1->setMinimum(min);
1332  }
1333  if (count >= 3)
1334  {
1335  QSpinBox* spin2 = child->property("widget#2").value< QSpinBox*>();
1336  spin2->setMinimum(min);
1337  }
1338  }
1339  else if (slider)
1340  {
1341  slider->setMinimum(min);
1342  }
1343  else
1344  {
1345  SLM_ERROR("Widget '" + key + "' must be a QSlider or a QDoubleSpinBox");
1346  }
1347 }
1348 //------------------------------------------------------------------------------
1349 
1350 void SParameters::setIntMaxParameter(int max, std::string key)
1351 {
1352  QWidget* child = this->getParamWidget(key);
1353 
1354  QSpinBox* spinbox = qobject_cast<QSpinBox*>(child);
1355  QSlider* slider = qobject_cast<QSlider*>(child);
1356 
1357  if (spinbox)
1358  {
1359  const int count = child->property("count").toInt();
1360 
1361  QSpinBox* spin0 = child->property("widget#0").value< QSpinBox*>();
1362  spin0->setMaximum(max);
1363 
1364  if (count >= 2)
1365  {
1366  QSpinBox* spin1 = child->property("widget#1").value< QSpinBox*>();
1367  spin1->setMaximum(max);
1368  }
1369  if (count >= 3)
1370  {
1371  QSpinBox* spin2 = child->property("widget#2").value< QSpinBox*>();
1372  spin2->setMaximum(max);
1373  }
1374  }
1375  else if (slider)
1376  {
1377  slider->setMaximum(max);
1378  }
1379  else
1380  {
1381  SLM_ERROR("Widget '" + key + "' must be a QSlider or a QDoubleSpinBox");
1382  }
1383 }
1384 //------------------------------------------------------------------------------
1385 
1386 void SParameters::setDoubleMinParameter(double min, std::string key)
1387 {
1388  QWidget* child = this->getParamWidget(key);
1389 
1390  QDoubleSpinBox* spinbox = qobject_cast<QDoubleSpinBox*>(child);
1391  QSlider* slider = qobject_cast<QSlider*>(child);
1392 
1393  if (spinbox)
1394  {
1395  const int count = child->property("count").toInt();
1396 
1397  QDoubleSpinBox* spin0 = child->property("widget#0").value< QDoubleSpinBox*>();
1398  spin0->setMinimum(min);
1399 
1400  if (count >= 2)
1401  {
1402  QDoubleSpinBox* spin1 = child->property("widget#1").value< QDoubleSpinBox*>();
1403  spin1->setMinimum(min);
1404  }
1405  if (count >= 3)
1406  {
1407  QDoubleSpinBox* spin2 = child->property("widget#2").value< QDoubleSpinBox*>();
1408  spin2->setMinimum(min);
1409  }
1410  }
1411  else if (slider)
1412  {
1413  const double value = getDoubleSliderValue(slider);
1414  slider->setProperty("min", min);
1415  setDoubleSliderRange(slider, value);
1416  }
1417  else
1418  {
1419  SLM_ERROR("Widget '" + key + "' must be a QSlider or a QDoubleSpinBox");
1420  }
1421 }
1422 
1423 //------------------------------------------------------------------------------
1424 
1425 void SParameters::setDoubleMaxParameter(double max, std::string key)
1426 {
1427  QWidget* child = this->getParamWidget(key);
1428 
1429  QDoubleSpinBox* spinbox = qobject_cast<QDoubleSpinBox*>(child);
1430  QSlider* slider = qobject_cast<QSlider*>(child);
1431 
1432  if (spinbox)
1433  {
1434  const int count = child->property("count").toInt();
1435 
1436  QDoubleSpinBox* spin0 = child->property("widget#0").value< QDoubleSpinBox*>();
1437  spin0->setMaximum(max);
1438 
1439  if (count >= 2)
1440  {
1441  QDoubleSpinBox* spin1 = child->property("widget#1").value< QDoubleSpinBox*>();
1442  spin1->setMaximum(max);
1443  }
1444  if (count >= 3)
1445  {
1446  QDoubleSpinBox* spin2 = child->property("widget#2").value< QDoubleSpinBox*>();
1447  spin2->setMaximum(max);
1448  }
1449  }
1450  else if (slider)
1451  {
1452  const double value = getDoubleSliderValue(slider);
1453  slider->setProperty("max", max);
1454  setDoubleSliderRange(slider, value);
1455  }
1456  else
1457  {
1458  SLM_ERROR("Widget '" + key + "' must be a QSlider or a QDoubleSpinBox");
1459  }
1460 }
1461 
1462 //-----------------------------------------------------------------------------
1463 
1464 void SParameters::setDoubleSliderRange(QSlider* slider, double currentValue)
1465 {
1466  const std::string key = slider->property("key").toString().toStdString();
1467  const double min = slider->property("min").toDouble();
1468  const double max = slider->property("max").toDouble();
1469  const std::uint8_t decimals = static_cast<std::uint8_t>(slider->property("decimals").toUInt());
1470  int maxSliderValue = 1;
1471  for(std::uint8_t i = 0; i < decimals; ++i)
1472  {
1473  maxSliderValue *= 10;
1474  }
1475 
1476  const double valueRange = max - min;
1477  maxSliderValue *= valueRange;
1478 
1479  // The slider's maximum internal range is [0; 2 147 483 647]
1480  // We could technically extend this range by setting the minimum to std::numeric_limits<int>::min()
1481  // but it would be ridiculous to use a slider handling so many values.
1482  slider->setMinimum(0);
1483 
1484  SLM_ERROR_IF("The requested value range for '" + key + "' is too large to be handled by a double slider. "
1485  "Please reduce your range, the number of decimals or use a 'spin' widget.",
1486  maxSliderValue < std::numeric_limits<double>::epsilon());
1487  if (maxSliderValue < std::numeric_limits<double>::epsilon())
1488  {
1489  maxSliderValue = 1.;
1490  }
1491  slider->setMaximum(maxSliderValue);
1492 
1493  // Update the slider integer value according to the new mix/max
1494  if (currentValue <= min)
1495  {
1496  slider->setValue(0);
1497  // qt does not emit the signal if the value does not change, we have to force qt signal to update the displayed
1498  // value and emit 'doubleChanged' signal
1499  Q_EMIT slider->valueChanged(0);
1500  }
1501  else if (currentValue > max)
1502  {
1503  slider->setValue(maxSliderValue);
1504  }
1505  else
1506  {
1507  const int sliderVal = int(std::round(((currentValue - min) / valueRange) * double(slider->maximum())));
1508  slider->setValue(sliderVal);
1509  }
1510 }
1511 
1512 //-----------------------------------------------------------------------------
1513 
1514 QWidget* SParameters::getParamWidget(const std::string& key)
1515 {
1516  auto qtContainer = ::fwGuiQt::container::QtContainer::dynamicCast(this->getContainer());
1517  const QWidget* widget = qtContainer->getQtContainer();
1518 
1519  QWidget* child = widget->findChild<QWidget*>(QString::fromStdString(key));
1520  SLM_ERROR_IF("Widget '" + key + "' is not found", !child);
1521 
1522  return child;
1523 }
1524 
1525 //-----------------------------------------------------------------------------
1526 
1527 } //namespace editor
1528 } //namespace guiQt
static FWDATATOOLS_API void hexaStringToRGBA(const std::string &_hexaColor, std::uint8_t _rgba[4])
Convert a color coded as an hexadecimal string into an array of four bytes (RGBA) ...
Defines the service interface managing the editor service for object.
Definition: IEditor.hpp:25
GUIQT_API void starting() override
Initializes Qt input widgets for parameters according to xml configuration.
FWGUI_API void destroy()
Stops sub-views and toobar services. Destroys view, sub-views and toolbar containers.
GUIQT_API void stopping() override
This method launches the IEditor::stopping method.
GUIQT_API void configuring() override
Configure the editor.
#define SLM_ERROR(message)
Definition: spyLog.hpp:272
#define SLM_ERROR_IF(message, cond)
Definition: spyLog.hpp:276
GUIQT_API SParameters() noexcept
Constructor. Initializes signals.
Definition: SParameters.cpp:68
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
GUIQT_API void updating() override
This method is used to update services. Does nothing.
Generic editor to interact with parameters.
Definition: SParameters.hpp:95
FWGUI_API void create()
Creates view, sub-views and toolbar containers. Manages sub-views and toobar services.
virtual GUIQT_API ~SParameters() noexcept
Destructor. Does nothing.
Definition: SParameters.cpp:99
The namespace guiQt contains the basic services to build the application IHM with Qt...
Definition: Code.hpp:21
FWGUI_API void initialize()
Initialize managers.
#define OSLM_DEBUG(message)
Definition: spyLog.hpp:241
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.
Definition: IService.cpp:247