40 #include <QMessageBox> 41 #include <QStringList> 42 #include <QVBoxLayout> 44 #include <google/protobuf/reflection.h> 54 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
56 _layout =
new QVBoxLayout(
this);
57 _layout->setContentsMargins(5, 5, 5, 5);
58 _layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
67 if (!info.oneof_descriptor)
return;
75 QString oneof_widget_key;
76 auto it = info.nested_names.begin();
77 oneof_widget_key = QString::fromStdString(*it);
79 for (; it != std::prev(info.nested_names.end()); ++it) oneof_widget_key +=
"." + QString::fromStdString(*it);
98 oneof_widget = it_oneof.value();
103 QString widget_label = QString::fromStdString(info.oneof_descriptor->name());
105 oneof_widget->nestedFieldName() = info.nested_names;
116 QString field_label = QString::fromStdString(info.field_raw->name());
125 messages::GuiType type = info.gui_type.first ? info.gui_type.second : messages::GuiType::TEXTEDIT;
126 QString label = info.label.first ? QString::fromStdString(info.label.second) : QString::fromStdString(info.field_name);
127 QString description = info.description.first ? QString::fromStdString(info.description.second) :
"";
128 int min = info.min_value.first ?
static_cast<int>(info.min_value.second) :
CORBO_MIN_INT;
129 int max = info.max_value.first ?
static_cast<int>(info.max_value.second) :
CORBO_MAX_INT;
132 if (info.print_description)
addSubWidget(
new QLabel(description));
135 if (info.default_value.first && !
_groups.empty() && std::get<2>(
_groups.back()))
142 PRINT_ERROR_NAMED(
"Cannot convert default parameter: " << info.default_value.second <<
" to int.");
145 info.message_raw->GetReflection()->SetInt32(info.message_raw, info.field_raw, value);
150 case messages::GuiType::SLIDER:
153 param_widget->setToolTip(description);
155 if (!info.min_value.first) min = 0;
156 if (!info.max_value.first) max = 100;
162 auto fun_write_param = [
info,
this](
double value) {
163 int value_int =
static_cast<int>(value);
164 info.message_raw->GetReflection()->SetInt32(info.message_raw, info.field_raw, value_int);
165 emit
parameterInt32Updated(QString::fromStdString(MessageParser::nestedNamesToString(info.nested_names)), value_int);
170 case messages::GuiType::TEXTEDIT:
174 param_widget->setToolTip(description);
175 QRegExp regexp_no_decimal(
"^((?!\\.).)*$");
181 auto fun_write_param = [
info, param_widget,
min,
max,
this]() {
185 bool out_of_range =
false;
191 if (ok && !out_of_range)
193 info.message_raw->GetReflection()->SetInt32(info.message_raw, info.field_raw, value);
195 parentFieldNames() +
"." + QString::fromStdString(MessageParser::nestedNamesToString(info.nested_names)), value);
200 param_widget->widgetLineEdit()->setText(
206 QMessageBox::warning(
this, tr(
"Out of Range"),
209 connect(param_widget->widgetLineEdit(), &QLineEdit::editingFinished, fun_write_param);
219 messages::GuiType type = info.gui_type.first ? info.gui_type.second : messages::GuiType::TEXTEDIT;
220 QString label = info.label.first ? QString::fromStdString(info.label.second) : QString::fromStdString(info.field_name);
221 QString description = info.description.first ? QString::fromStdString(info.description.second) :
"";
225 std::vector<int> values_mod = values;
228 if (info.print_description)
addSubWidget(
new QLabel(description));
231 if (info.default_value.first && !
_groups.empty() && std::get<2>(
_groups.back()))
238 info.message_raw->GetReflection()->GetMutableRepeatedFieldRef<
int>(info.message_raw, info.field_raw).CopyFrom(values_mod);
242 PRINT_ERROR_NAMED(
"Cannot convert default parameter: " << info.default_value.second <<
" to int array.");
249 case messages::GuiType::TEXTEDIT:
253 param_widget->setToolTip(description);
254 QRegExp regexp_no_decimal(
"^((?!\\.).)*$");
260 auto fun_write_param = [
info, param_widget,
min,
max,
this]() {
263 std::vector<int> values;
267 bool dimension_range_exceeded =
false;
269 if (info.dynamic_size)
271 field_size = (
int)values.size();
272 if (info.min_size.first && field_size < info.min_size.second)
274 dimension_range_exceeded =
true;
277 else if (info.max_size.first && field_size < info.max_size.second)
279 dimension_range_exceeded =
true;
285 int field_size = info.message_raw->GetReflection()->FieldSize(*info.message_raw, info.field_raw);
286 if (ok && (
int)values.size() != field_size) ok =
false;
290 bool out_of_range =
false;
294 if (ok && !out_of_range)
296 if (info.dynamic_size)
298 info.message_raw->GetReflection()
299 ->GetMutableRepeatedFieldRef<
int>(info.message_raw, info.field_raw)
304 for (
int idx = 0; idx < (
int)values.size(); ++idx)
306 info.message_raw->GetReflection()->SetRepeatedInt32(info.message_raw, info.field_raw, idx, values[idx]);
313 auto orig_values = info.message_raw->GetReflection()->GetRepeatedFieldRef<
int>(*info.message_raw, info.field_raw);
315 param_widget->widgetLineEdit()->setText(test);
319 if ((
int)values.size() != field_size)
321 QMessageBox::warning(
this, tr(
"Invalid Number of Elements"),
322 "Number of elements must be " + QString::number(field_size) +
", but " + QString::number(values.size()) +
323 (values.size() == 1 ?
" is" :
" are") +
" provided.");
325 else if (dimension_range_exceeded)
327 QMessageBox::warning(
this, tr(
"Invalid Number of Elements"),
331 else if (out_of_range)
333 QMessageBox::warning(
this, tr(
"Out of Range"),
337 connect(param_widget->widgetLineEdit(), &QLineEdit::editingFinished, fun_write_param);
347 messages::GuiType type = info.gui_type.first ? info.gui_type.second : messages::GuiType::TEXTEDIT;
348 QString label = info.label.first ? QString::fromStdString(info.label.second) : QString::fromStdString(info.field_name);
349 QString description = info.description.first ? QString::fromStdString(info.description.second) :
"";
354 if (info.print_description)
addSubWidget(
new QLabel(description));
357 if (info.default_value.first && !
_groups.empty() && std::get<2>(
_groups.back()))
364 PRINT_ERROR_NAMED(
"Cannot convert default parameter: " << info.default_value.second <<
" to double.");
367 info.message_raw->GetReflection()->SetDouble(info.message_raw, info.field_raw, value);
372 case messages::GuiType::SLIDER:
375 param_widget->setToolTip(description);
377 if (!info.min_value.first) min = 0;
378 if (!info.max_value.first) max = 100;
384 auto fun_write_param = [
this,
info](
double value) {
385 info.message_raw->GetReflection()->SetDouble(info.message_raw, info.field_raw, value);
391 case messages::GuiType::TEXTEDIT:
395 param_widget->setToolTip(description);
400 auto fun_write_param = [
info, param_widget,
min,
max,
this]() {
404 bool out_of_range =
false;
410 if (ok && !out_of_range)
411 info.message_raw->GetReflection()->SetDouble(info.message_raw, info.field_raw, value);
415 param_widget->widgetLineEdit()->setText(
421 QMessageBox::warning(
422 this, tr(
"Out of Range"),
427 connect(param_widget->widgetLineEdit(), &QLineEdit::editingFinished, fun_write_param);
437 messages::GuiType type = info.gui_type.first ? info.gui_type.second : messages::GuiType::TEXTEDIT;
438 QString label = info.label.first ? QString::fromStdString(info.label.second) : QString::fromStdString(info.field_name);
439 QString description = info.description.first ? QString::fromStdString(info.description.second) :
"";
443 std::vector<double> values_mod = values;
446 if (info.print_description)
addSubWidget(
new QLabel(description));
449 if (info.default_value.first && !
_groups.empty() && std::get<2>(
_groups.back()))
456 info.message_raw->GetReflection()->GetMutableRepeatedFieldRef<
double>(info.message_raw, info.field_raw).CopyFrom(values_mod);
460 PRINT_ERROR_NAMED(
"Cannot convert default parameter: " << info.default_value.second <<
" to double array.");
467 case messages::GuiType::TEXTEDIT:
471 param_widget->setToolTip(description);
476 auto fun_write_param = [
info, param_widget,
min,
max,
this]() {
479 std::vector<double> values;
484 bool dimension_range_exceeded =
false;
485 if (info.dynamic_size)
487 field_size = (
int)values.size();
488 if (info.min_size.first && field_size < info.min_size.second)
490 dimension_range_exceeded =
true;
493 else if (info.max_size.first && field_size < info.max_size.second)
495 dimension_range_exceeded =
true;
501 field_size = info.message_raw->GetReflection()->FieldSize(*info.message_raw, info.field_raw);
502 if (ok && (
int)values.size() != field_size) ok =
false;
506 bool out_of_range =
false;
510 if (ok && !out_of_range)
512 if (info.dynamic_size)
514 info.message_raw->GetReflection()
515 ->GetMutableRepeatedFieldRef<
double>(info.message_raw, info.field_raw)
520 for (
int idx = 0; idx < (
int)values.size(); ++idx)
522 info.message_raw->GetReflection()->SetRepeatedDouble(info.message_raw, info.field_raw, idx, values[idx]);
529 auto orig_values = info.message_raw->GetReflection()->GetRepeatedFieldRef<
double>(*info.message_raw, info.field_raw);
531 param_widget->widgetLineEdit()->setText(text);
535 if ((
int)values.size() != field_size)
537 QMessageBox::warning(
this, tr(
"Invalid Number of Elements"),
538 "Number of elements must be " + QString::number(field_size) +
", but " + QString::number(values.size()) +
539 (values.size() == 1 ?
" is" :
" are") +
" provided.");
541 else if (dimension_range_exceeded)
543 QMessageBox::warning(
this, tr(
"Invalid Number of Elements"),
547 else if (out_of_range)
549 QMessageBox::warning(
550 this, tr(
"Out of Range"),
555 connect(param_widget->widgetLineEdit(), &QLineEdit::editingFinished, fun_write_param);
565 messages::GuiType type = info.gui_type.first ? info.gui_type.second : messages::GuiType::CHECKBOX;
566 QString label = info.label.first ? QString::fromStdString(info.label.second) : QString::fromStdString(info.field_name);
567 QString description = info.description.first ? QString::fromStdString(info.description.second) :
"";
570 if (info.print_description)
addSubWidget(
new QLabel(description));
573 if (info.default_value.first && !
_groups.empty() && std::get<2>(
_groups.back()))
580 PRINT_ERROR_NAMED(
"Cannot convert default parameter: " << info.default_value.second <<
" to bool.");
583 info.message_raw->GetReflection()->SetBool(info.message_raw, info.field_raw, value);
588 case messages::GuiType::CHECKBOX:
591 QCheckBox* param_widget =
new QCheckBox(label);
592 param_widget->setToolTip(description);
593 param_widget->setChecked(value);
598 auto fun_write_param = [
info,
this](
bool toggled) {
599 info.message_raw->GetReflection()->SetBool(info.message_raw, info.field_raw, toggled);
602 connect(param_widget, &QCheckBox::toggled, fun_write_param);
613 messages::GuiType type = info.gui_type.first ? info.gui_type.second : messages::GuiType::CHECKBOX;
614 QString label = info.label.first ? QString::fromStdString(info.label.second) : QString::fromStdString(info.field_name);
615 QString description = info.description.first ? QString::fromStdString(info.description.second) :
"";
617 std::vector<bool> values_mod = values;
620 if (info.print_description)
addSubWidget(
new QLabel(description));
623 if (info.default_value.first && !
_groups.empty() && std::get<2>(
_groups.back()))
630 info.message_raw->GetReflection()->GetMutableRepeatedFieldRef<
bool>(info.message_raw, info.field_raw).CopyFrom(values_mod);
634 PRINT_ERROR_NAMED(
"Cannot convert default parameter: " << info.default_value.second <<
" to bool array.");
640 QStringList label_list = label.split(
',');
642 QString group_name = label_list.empty() ? label : label_list.first();
644 if (type == messages::GuiType::TEXTEDIT)
648 param_widget->setToolTip(description);
653 auto fun_write_param = [
info, param_widget,
this]() {
656 std::vector<bool> values;
661 bool dimension_range_exceeded =
false;
662 if (info.dynamic_size)
664 field_size = (
int)values.size();
665 if (info.min_size.first && field_size < info.min_size.second)
667 dimension_range_exceeded =
true;
670 else if (info.max_size.first && field_size < info.max_size.second)
672 dimension_range_exceeded =
true;
678 field_size = info.message_raw->GetReflection()->FieldSize(*info.message_raw, info.field_raw);
679 if (ok && (
int)values.size() != field_size) ok =
false;
685 if (info.dynamic_size)
687 info.message_raw->GetReflection()
688 ->GetMutableRepeatedFieldRef<
bool>(info.message_raw, info.field_raw)
693 for (
int idx = 0; idx < (
int)values.size(); ++idx)
695 info.message_raw->GetReflection()->SetRepeatedBool(info.message_raw, info.field_raw, idx, values[idx]);
702 auto orig_values = info.message_raw->GetReflection()->GetRepeatedFieldRef<
bool>(*info.message_raw, info.field_raw);
704 param_widget->widgetLineEdit()->setText(text);
708 if ((
int)values.size() != field_size)
710 QMessageBox::warning(
this, tr(
"Invalid Number of Elements"),
711 "Number of elements must be " + QString::number(field_size) +
", but " + QString::number(values.size()) +
712 (values.size() == 1 ?
" is" :
" are") +
" provided.");
714 else if (dimension_range_exceeded)
716 QMessageBox::warning(
this, tr(
"Invalid Number of Elements"),
722 connect(param_widget->widgetLineEdit(), &QLineEdit::editingFinished, fun_write_param);
727 bool exclusive = type != messages::GuiType::CHECKBOX;
730 param_widget->setToolTip(description);
732 for (
int idx = 0; idx < (
int)values_mod.size(); ++idx)
734 QString field_label = (idx + 1 < label_list.size()) ? label_list[idx + 1] :
"";
735 QAbstractButton* btn = param_widget->
addButton(values_mod[idx], field_label);
739 auto fun_write_param = [
info, idx,
this](
bool toggled) {
740 info.message_raw->GetReflection()->SetRepeatedBool(info.message_raw, info.field_raw, idx, toggled);
743 connect(btn, &QAbstractButton::toggled, fun_write_param);
753 QString label = info.label.first ? QString::fromStdString(info.label.second) : QString::fromStdString(info.field_name);
754 QString description = info.description.first ? QString::fromStdString(info.description.second) :
"";
757 if (info.print_description)
addSubWidget(
new QLabel(description));
760 param_widget->setToolTip(description);
764 const google::protobuf::EnumDescriptor* enum_descr = info.field_raw->enum_type();
767 PRINT_WARNING(
"ParameterWidget::addParameterEnum(): provided parameter '" << info.field_name <<
"' is no enumerator!");
770 for (
int idx = 0; idx < enum_descr->value_count(); ++idx)
772 param_widget->
widgetComboBox()->addItem(QString::fromStdString(enum_descr->value(idx)->name()));
775 param_widget->
widgetComboBox()->setCurrentText(QString::fromStdString(value));
779 auto fun_write_param = [
info,
this](
int idx) {
780 info.message_raw->GetReflection()->SetEnumValue(info.message_raw, info.field_raw, idx);
783 connect(param_widget->
widgetComboBox(),
static_cast<void (QComboBox::*)(
int)
>(&QComboBox::currentIndexChanged), fun_write_param);
790 QString label = info.label.first ? QString::fromStdString(info.label.second) : QString::fromStdString(info.field_name);
791 QString description = info.description.first ? QString::fromStdString(info.description.second) :
"";
794 if (info.print_description)
addSubWidget(
new QLabel(description));
797 if (info.default_value.first && !
_groups.empty() && std::get<2>(
_groups.back()))
800 value = info.default_value.second;
802 info.message_raw->GetReflection()->SetString(info.message_raw, info.field_raw, value);
806 param_widget->setToolTip(description);
811 auto fun_write_param = [param_widget,
info,
this]() {
812 std::string value = param_widget->
widgetLineEdit()->text().toUtf8().constData();
813 info.message_raw->GetReflection()->SetString(info.message_raw, info.field_raw, value);
816 connect(param_widget->
widgetLineEdit(), &QLineEdit::editingFinished, fun_write_param);
823 QString text_q = QString::fromStdString(text);
825 if (info.default_value.first && text.empty()) text_q = QString::fromStdString(info.default_value.second);
833 QString name = info.label.first ? QString::fromStdString(info.label.second) : QString::fromStdString(info.field_name);
837 QVBoxLayout* layout =
new QVBoxLayout;
838 layout->setContentsMargins(5, 15, 5, 0);
839 layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
846 std::tuple<CollapsableGroupBox*, QLayout*, bool> top =
_groups.pop();
849 std::get<0>(top)->groupBox()->setLayout(std::get<1>(top));
850 std::get<0>(top)->setCollapsed(
false);
854 _layout->addWidget(std::get<0>(top));
856 std::get<1>(
_groups.top())->addWidget(std::get<0>(top));
865 widget->setStyleSheet(
"font-size: 11px");
873 else if (std::get<1>(
_groups.top()))
875 std::get<1>(
_groups.top())->addWidget(widget);
890 parse(message, field);
901 MessageParser parser;
903 using std::placeholders::_1;
904 using std::placeholders::_2;
916 parser.setCallbackMessageEvent([
this, field](corbo::MessageParser::MessageEvent ev,
const corbo::MessageParser::FieldInformation&
info) {
917 if (ev == corbo::MessageParser::MessageEvent::MessageStart)
919 else if (ev == corbo::MessageParser::MessageEvent::MessageEnd)
921 else if (ev == corbo::MessageParser::MessageEvent::OneOf)
927 std::list<std::string> nested_field_name;
931 if (!nested_field_name.empty()) nested_field_name.pop_back();
935 parser.parseField(message, field,
false,
true,
false,
939 parser.parse(message,
false,
true, &nested_field_name);
947 for (
auto widget : this->findChildren<ParameterWidget*>(QString(), Qt::FindChildrenRecursively))
949 if (static_cast<ParameterWidget*>(widget)->
hasParameters())
return true;
956 for (
auto widget : this->findChildren<QWidget*>(QString(), Qt::FindDirectChildrenOnly))
delete widget;
#define PRINT_ERROR_NAMED(msg)
bool qstring_to_bool(const QString &string, bool *ok=nullptr)
constexpr const double CORBO_MIN_DBL
Minimum (negative) double value.
QString double_to_qstring(double value)
#define PRINT_WARNING(msg)
Print msg-stream.
QString int_container_to_qstring(Iterator first, Iterator last)
QString double_container_to_qstring(Iterator first, Iterator last)
double qstring_to_double(const QString &string, bool *ok=nullptr)
constexpr const double CORBO_MAX_DBL
Maximum double value.
QString bool_container_to_qstring(Iterator first, Iterator last)
constexpr const bool is_in_bounds(const T &v, const T &lo, const T &hi)
Check if a value is inside the interval [lo, hi].
constexpr const int CORBO_MIN_INT
Minimum (negative) integer value.
void setCollapsed(bool collapsed)
constexpr const int CORBO_MAX_INT
Maximum integer value.
void qstring_to_container(const QString &string, std::vector< double > &values, bool *ok=nullptr)
int qstring_to_int(const QString &string, bool *ok=nullptr)
QString int_to_qstring(int value)
const bool is_in_bounds_all(Iterator first, Iterator last, const T &lo, const T &hi)
Check if all components of a container are inside the interval [lo, hi].
bool ok()
global method to check whether to proceed or cancel the current action
Tuple< Args... > make_tuple(Args... args)
Creates a tuple object, deducing the target type from the types of arguments.