2 * This file is part of the PulseView project.
4 * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 #include <QHBoxLayout>
35 // Note that "using std::isnan;" is _not_ put here since that would break
36 // compilation on some platforms. Use "std::isnan()" instead in checks below.
37 using std::numeric_limits;
44 Enum::Enum(QString name, QString desc,
45 vector<pair<Glib::VariantBase, QString> > values,
46 Getter getter, Setter setter) :
47 Property(name, desc, getter, setter),
51 slider_layout_widget_(nullptr),
53 slider_label_(nullptr)
55 // Try to determine whether the values make up a range, created by e.g.
56 // std_gvar_min_max_step_thresholds()
58 vector<double> deltas;
59 double prev_value = 0;
61 for (const pair<Glib::VariantBase, QString> &v : values_) {
63 if (v.first.is_of_type(Glib::VariantType("d"))) {
64 g_variant_get((GVariant*)(v.first.gobj()), "d", &value);
65 } else if (v.first.is_of_type(Glib::VariantType("(dd)"))) {
67 g_variant_get((GVariant*)(v.first.gobj()), "(dd)", &value, &dummy);
69 break; // Type not d or (dd), so not a range that we can handle
70 deltas.push_back(value - prev_value);
74 if (deltas.size() > 0) {
75 bool constant_delta = true;
76 double prev_delta = numeric_limits<double>::quiet_NaN();
78 bool skip_first = true;
79 for (double delta : deltas) {
80 // First value is incorrect, it's the delta to 0 since no
81 // previous value existed yet
86 if (std::isnan(prev_delta))
89 // 2*DBL_EPSILON doesn't work here, so use a workaround
90 if (abs(delta - prev_delta) > (delta/10))
91 constant_delta = false;
101 QWidget* Enum::get_widget(QWidget *parent, bool auto_commit)
106 Glib::VariantBase variant = getter_();
112 if (slider_layout_widget_)
113 return slider_layout_widget_;
115 slider_ = new QSlider();
116 // Sliders can't handle float values, so we just use it to specify
117 // the number of steps that we're away from the range's beginning
118 slider_->setOrientation(Qt::Horizontal);
119 slider_->setMinimum(0);
120 slider_->setMaximum(values_.size() - 1);
121 slider_->setSingleStep(1);
123 slider_label_ = new QLabel();
125 slider_layout_widget_ = new QWidget(parent);
126 QHBoxLayout *layout = new QHBoxLayout(slider_layout_widget_);
127 layout->addWidget(slider_);
128 layout->addWidget(slider_label_);
133 connect(slider_, SIGNAL(valueChanged(int)),
134 this, SLOT(on_value_changed(int)));
136 return slider_layout_widget_;
143 selector_ = new QComboBox(parent);
144 for (unsigned int i = 0; i < values_.size(); i++) {
145 const pair<Glib::VariantBase, QString> &v = values_[i];
146 selector_->addItem(v.second, qVariantFromValue(v.first));
152 connect(selector_, SIGNAL(currentIndexChanged(int)),
153 this, SLOT(on_current_index_changed(int)));
159 void Enum::update_widget()
161 Glib::VariantBase variant = getter_();
162 assert(variant.gobj());
167 if (!slider_layout_widget_)
170 for (unsigned int i = 0; i < values_.size(); i++) {
171 const pair<Glib::VariantBase, QString> &v = values_[i];
173 // g_variant_equal() doesn't handle floating point properly
174 if (v.first.is_of_type(Glib::VariantType("d"))) {
176 g_variant_get(variant.gobj(), "d", &a);
177 g_variant_get((GVariant*)(v.first.gobj()), "d", &b);
179 if (abs(a - b) <= 2 * DBL_EPSILON) {
180 slider_->setValue(i);
181 slider_label_->setText(v.second);
184 // Check for "(dd)" type and handle it if it's found
185 if (v.first.is_of_type(Glib::VariantType("(dd)"))) {
186 gdouble a1, a2, b1, b2;
187 g_variant_get(variant.gobj(), "(dd)", &a1, &a2);
188 g_variant_get((GVariant*)(v.first.gobj()), "(dd)", &b1, &b2);
190 if ((abs(a1 - b1) <= 2 * DBL_EPSILON) && \
191 (abs(a2 - b2) <= 2 * DBL_EPSILON)) {
192 slider_->setValue(i);
193 slider_label_->setText(v.second);
197 qWarning() << "Enum property" << name() << "encountered unsupported type";
208 for (unsigned int i = 0; i < values_.size(); i++) {
209 const pair<Glib::VariantBase, QString> &v = values_[i];
211 // g_variant_equal() doesn't handle floating point properly
212 if (v.first.is_of_type(Glib::VariantType("d"))) {
214 g_variant_get(variant.gobj(), "d", &a);
215 g_variant_get((GVariant*)(v.first.gobj()), "d", &b);
216 if (abs(a - b) <= 2 * DBL_EPSILON)
217 selector_->setCurrentIndex(i);
219 // Check for "(dd)" type and handle it if it's found
220 if (v.first.is_of_type(Glib::VariantType("(dd)"))) {
221 gdouble a1, a2, b1, b2;
222 g_variant_get(variant.gobj(), "(dd)", &a1, &a2);
223 g_variant_get((GVariant*)(v.first.gobj()), "(dd)", &b1, &b2);
224 if ((abs(a1 - b1) <= 2 * DBL_EPSILON) && \
225 (abs(a2 - b2) <= 2 * DBL_EPSILON))
226 selector_->setCurrentIndex(i);
229 // Handle all other types
230 if (v.first.equal(variant))
231 selector_->setCurrentIndex(i);
243 if (!slider_layout_widget_)
246 setter_(values_.at(slider_->value()).first);
254 const int index = selector_->currentIndex();
258 setter_(selector_->itemData(index).value<Glib::VariantBase>());
260 // The combo box needs no update, it already shows the current value
261 // by definition: the user picked it
265 void Enum::on_current_index_changed(int)
270 void Enum::on_value_changed(int)