Introduce DecodeSignal class
[pulseview.git] / pv / widgets / sweeptimingwidget.cpp
1 /*
2  * This file is part of the PulseView project.
3  *
4  * Copyright (C) 2013 Joel Holdsworth <joel@airwebreathe.org.uk>
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include "sweeptimingwidget.hpp"
21
22 #include <cassert>
23 #include <cstdlib>
24 #include <vector>
25
26 #include <extdef.h>
27
28 using std::abs;
29 using std::vector;
30
31 namespace pv {
32 namespace widgets {
33
34 SweepTimingWidget::SweepTimingWidget(const char *suffix,
35         QWidget *parent) :
36         QWidget(parent),
37         suffix_(suffix),
38         layout_(this),
39         value_(this),
40         list_(this),
41         value_type_(None)
42 {
43         setContentsMargins(0, 0, 0, 0);
44
45         value_.setDecimals(0);
46         value_.setSuffix(QString::fromUtf8(suffix));
47
48         connect(&list_, SIGNAL(currentIndexChanged(int)),
49                 this, SIGNAL(value_changed()));
50         connect(&value_, SIGNAL(editingFinished()),
51                 this, SIGNAL(value_changed()));
52
53         setLayout(&layout_);
54         layout_.setMargin(0);
55         layout_.addWidget(&list_);
56         layout_.addWidget(&value_);
57
58         show_none();
59 }
60
61 void SweepTimingWidget::show_none()
62 {
63         value_type_ = None;
64         value_.hide();
65         list_.hide();
66 }
67
68 void SweepTimingWidget::show_min_max_step(uint64_t min, uint64_t max,
69         uint64_t step)
70 {
71         assert(max > min);
72         assert(step > 0);
73
74         value_type_ = MinMaxStep;
75
76         value_.setRange(min, max);
77         value_.setSingleStep(step);
78
79         value_.show();
80         list_.hide();
81 }
82
83 void SweepTimingWidget::show_list(const uint64_t *vals, size_t count)
84 {
85         value_type_ = List;
86
87         list_.clear();
88         for (size_t i = 0; i < count; i++) {
89                 char *const s = sr_si_string_u64(vals[i], suffix_);
90                 list_.addItem(QString::fromUtf8(s), qVariantFromValue(vals[i]));
91                 g_free(s);
92         }
93
94         value_.hide();
95         list_.show();
96 }
97
98 void SweepTimingWidget::show_125_list(uint64_t min, uint64_t max)
99 {
100         assert(max > min);
101
102         // Create a 1-2-5-10 list of entries.
103         const unsigned int FineScales[] = {1, 2, 5};
104         uint64_t value, decade;
105         unsigned int fine;
106         vector<uint64_t> values;
107
108         // Compute the starting decade
109         for (decade = 1; decade * 10 <= min; decade *= 10);
110
111         // Compute the first entry
112         for (fine = 0; fine < countof(FineScales); fine++)
113                 if (FineScales[fine] * decade >= min)
114                         break;
115
116         assert(fine < countof(FineScales));
117
118         // Add the minimum entry if it's not on the 1-2-5 progression
119         if (min != FineScales[fine] * decade)
120                 values.push_back(min);
121
122         while ((value = FineScales[fine] * decade) < max) {
123                 values.push_back(value);
124                 if (++fine >= countof(FineScales))
125                         fine = 0, decade *= 10;
126         }
127
128         // Add the max value
129         values.push_back(max);
130
131         // Make a C array, and give it to the sweep timing widget
132         uint64_t *const values_array = new uint64_t[values.size()];
133         copy(values.begin(), values.end(), values_array);
134         show_list(values_array, values.size());
135         delete[] values_array;
136 }
137
138 uint64_t SweepTimingWidget::value() const
139 {
140         switch (value_type_) {
141         case None:
142                 return 0;
143         case MinMaxStep:
144                 return (uint64_t)value_.value();
145         case List:
146         {
147                 const int index = list_.currentIndex();
148                 return (index >= 0) ? list_.itemData(
149                         index).value<uint64_t>() : 0;
150         }
151         default:
152                 // Unexpected value type
153                 assert(false);
154                 return 0;
155         }
156 }
157
158 void SweepTimingWidget::set_value(uint64_t value)
159 {
160         value_.setValue(value);
161
162         int best_match = list_.count() - 1;
163         int64_t best_variance = INT64_MAX;
164
165         for (int i = 0; i < list_.count(); i++) {
166                 const int64_t this_variance = abs(
167                         (int64_t)value - list_.itemData(i).value<int64_t>());
168                 if (this_variance < best_variance) {
169                         best_variance = this_variance;
170                         best_match = i;
171                 }
172         }
173
174         list_.setCurrentIndex(best_match);
175 }
176
177 }  // namespace widgets
178 }  // namespace pv