]>
Commit | Line | Data |
---|---|---|
4640a84e SA |
1 | /* |
2 | * This file is part of the PulseView project. | |
3 | * | |
4 | * Copyright (C) 2020 Soeren Apel <soeren@apelpie.net> | |
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 <extdef.h> | |
21 | ||
22 | #include <QComboBox> | |
23 | #include <QDebug> | |
86eeec3b | 24 | #include <QDialogButtonBox> |
4640a84e SA |
25 | #include <QFormLayout> |
26 | #include <QGridLayout> | |
2823de2c | 27 | #include <QLabel> |
4640a84e | 28 | #include <QLineEdit> |
2823de2c | 29 | #include <QPushButton> |
4640a84e | 30 | #include <QString> |
2823de2c SA |
31 | #include <QTabWidget> |
32 | #include <QVBoxLayout> | |
4640a84e SA |
33 | |
34 | #include "mathsignal.hpp" | |
35 | ||
36 | #include "pv/data/signalbase.hpp" | |
37 | ||
38 | using pv::data::SignalBase; | |
39 | ||
40 | namespace pv { | |
41 | namespace views { | |
42 | namespace trace { | |
43 | ||
44 | #define MATHSIGNAL_INPUT_TIMEOUT (2000) | |
45 | ||
2823de2c SA |
46 | const vector< pair<string, string> > MathEditDialog::Examples = { |
47 | {"Product of signals named A1 and A2:", | |
48 | "A1 * A2"}, | |
49 | {"Create a sine wave with f=1MHz:", | |
50 | "sin(1e6 * 2 * pi * t)"}, | |
51 | {"Average the past 4 samples of A2:", | |
52 | "var v := 0;\n" \ | |
53 | "var n := 4;\n\n" \ | |
54 | "for (var i := 0; i < n; i += 1) {\n" \ | |
55 | "\tv += sample('A2', s - i) / n;\n" \ | |
56 | "}"}, | |
57 | {"Create a <a href=https://en.wikipedia.org/wiki/Chirp#Linear>frequency sweep</a> from 1Hz to 1MHz over 10 seconds:", | |
58 | "var f_min := 1;\n" \ | |
59 | "var f_max := 1e6;\n" \ | |
60 | "var duration := 10;\n" \ | |
61 | "var gradient := (f_max - f_min) / duration;\n" \ | |
62 | "// phase is the antiderivative of (gradient * t + f_min) dt\n" \ | |
63 | "var phase := gradient * (t ^ 2 / 2) + f_min * t;\n" \ | |
64 | "sin(2 * pi * phase)"}, | |
65 | {"Single-pole low-pass IIR filter, see " \ | |
66 | "<a href=https://tomroelandts.com/articles/low-pass-single-pole-iir-filter>this</a> " \ | |
67 | "and <a href=https://dsp.stackexchange.com/questions/34969/cutoff-frequency-of-a-first-order-recursive-filter>this</a> article:", | |
68 | "// -3db point is set to 10% of the sampling frequency\n" \ | |
69 | "var f_c := 0.1;\n" \ | |
70 | "var omega_c := 2 * pi * f_c;\n" \ | |
71 | "var b := 2 - cos(omega_c) - sqrt(((2 - cos(omega_c)) ^ 2) - 1);\n" \ | |
72 | "var a := 1 - b;\n\n" \ | |
73 | "// formula is y[n] = ax[n] + (1 - a) * y[n - 1]\n" \ | |
74 | "// x[n] becomes the input signal, here A4\n" \ | |
75 | "// y[n - 1] becomes sample('Math1', s - 1)\n" \ | |
76 | "a * A4 + (1 - a) * sample('Math1', s - 1)"} | |
77 | }; | |
78 | ||
86eeec3b SA |
79 | |
80 | MathEditDialog::MathEditDialog(pv::Session &session, | |
81 | shared_ptr<pv::data::MathSignal> math_signal, QWidget *parent) : | |
82 | QDialog(parent), | |
83 | session_(session), | |
84 | math_signal_(math_signal), | |
2823de2c SA |
85 | old_expression_(math_signal->get_expression()), |
86 | expr_edit_(new QPlainTextEdit()) | |
86eeec3b SA |
87 | { |
88 | setWindowTitle(tr("Math Expression Editor")); | |
89 | ||
2823de2c SA |
90 | // Create the pages |
91 | QWidget *basics_page = new QWidget(); | |
92 | QVBoxLayout *basics_layout = new QVBoxLayout(basics_page); | |
93 | basics_layout->addWidget(new QLabel("<b>" + tr("Inputs:") + "</b>")); | |
94 | basics_layout->addWidget(new QLabel("signal_name\tCurrent value of signal signal_name (e.g. A0 or CH1)")); | |
95 | basics_layout->addWidget(new QLabel("T\t\tSampling interval (= 1 / sample rate)")); | |
96 | basics_layout->addWidget(new QLabel("t\t\tCurrent time in seconds")); | |
97 | basics_layout->addWidget(new QLabel("s\t\tCurrent sample number")); | |
98 | basics_layout->addWidget(new QLabel("sample('s', n)\tValue of sample #n of the signal named s")); | |
99 | basics_layout->addWidget(new QLabel("<b>" + tr("Variables:") + "</b>")); | |
100 | basics_layout->addWidget(new QLabel("var x;\t\tCreate variable\nvar x := 5;\tCreate variable with initial value")); | |
101 | basics_layout->addWidget(new QLabel("<b>" + tr("Basic operators:") + "</b>")); | |
102 | basics_layout->addWidget(new QLabel("x + y\t\tAddition of x and y")); | |
103 | basics_layout->addWidget(new QLabel("x - y\t\tSubtraction of x and y")); | |
104 | basics_layout->addWidget(new QLabel("x * y\t\tMultiplication of x and y")); | |
105 | basics_layout->addWidget(new QLabel("x / y\t\tDivision of x and y")); | |
106 | basics_layout->addWidget(new QLabel("x % y\t\tRemainder of division x / y")); | |
107 | basics_layout->addWidget(new QLabel("x ^ y\t\tx to the power of y")); | |
108 | basics_layout->addWidget(new QLabel("<b>" + tr("Assignments:") + "</b>")); | |
109 | basics_layout->addWidget(new QLabel("x := y\t\tAssign the value of y to x")); | |
110 | basics_layout->addWidget(new QLabel("x += y\t\tIncrement x by y")); | |
111 | basics_layout->addWidget(new QLabel("x -= y\t\tDecrement x by y")); | |
112 | basics_layout->addWidget(new QLabel("x *= y\t\tMultiply x by y")); | |
113 | basics_layout->addWidget(new QLabel("x /= y\t\tDivide x by y")); | |
114 | basics_layout->addWidget(new QLabel("x %= y\t\tSet x to the value of x % y")); | |
115 | ||
116 | QWidget *func1_page = new QWidget(); | |
117 | QVBoxLayout *func1_layout = new QVBoxLayout(func1_page); | |
118 | func1_layout->addWidget(new QLabel("<b>" + tr("General purpose functions:") + "</b>")); | |
119 | func1_layout->addWidget(new QLabel(tr("abs(x)\t\tAbsolute value of x"))); | |
120 | func1_layout->addWidget(new QLabel(tr("avg(x, y, ...)\tAverage of all input values"))); | |
121 | func1_layout->addWidget(new QLabel(tr("ceil(x)\t\tSmallest integer that is greater than or equal to x"))); | |
122 | func1_layout->addWidget(new QLabel(tr("clamp(lb, x, ub)\tClamp x in range between lb and ub, where lb < ub"))); | |
123 | func1_layout->addWidget(new QLabel(tr("equal(x, y)\tEquality test between x and y using normalised epsilon"))); | |
124 | func1_layout->addWidget(new QLabel(tr("erf(x)\t\tError function of x"))); | |
125 | func1_layout->addWidget(new QLabel(tr("erfc(x)\t\tComplimentary error function of x"))); | |
126 | func1_layout->addWidget(new QLabel(tr("exp(x)\t\te to the power of x"))); | |
127 | func1_layout->addWidget(new QLabel(tr("expm1(x)\te to the power of x minus 1, where x is very small."))); | |
128 | func1_layout->addWidget(new QLabel(tr("floor(x)\t\tLargest integer that is less than or equal to x"))); | |
129 | func1_layout->addWidget(new QLabel(tr("frac(x)\t\tFractional portion of x"))); | |
130 | func1_layout->addWidget(new QLabel(tr("hypot(x)\t\tHypotenuse of x and y (i.e. sqrt(x*x + y*y))"))); | |
131 | func1_layout->addWidget(new QLabel(tr("iclamp(lb, x, ub)\tInverse-clamp x outside of the range lb and ub, where lb < ub.\n\t\tIf x is within the range it will snap to the closest bound"))); | |
132 | func1_layout->addWidget(new QLabel(tr("inrange(lb, x, ub)\tIn-range returns true when x is within the range lb and ub, where lb < ub."))); | |
133 | func1_layout->addWidget(new QLabel(tr("log(x)\t\tNatural logarithm of x"))); | |
134 | func1_layout->addWidget(new QLabel(tr("log10(x)\t\tBase 10 logarithm of x"))); | |
135 | ||
136 | QWidget *func2_page = new QWidget(); | |
137 | QVBoxLayout *func2_layout = new QVBoxLayout(func2_page); | |
138 | func2_layout->addWidget(new QLabel(tr("log1p(x)\t\tNatural logarithm of 1 + x, where x is very small"))); | |
139 | func2_layout->addWidget(new QLabel(tr("log2(x)\t\tBase 2 logarithm of x"))); | |
140 | func2_layout->addWidget(new QLabel(tr("logn(x)\t\tBase N logarithm of x, where n is a positive integer"))); | |
141 | func2_layout->addWidget(new QLabel(tr("max(x, y, ...)\tLargest value of all the inputs"))); | |
142 | func2_layout->addWidget(new QLabel(tr("min(x, y, ...)\tSmallest value of all the inputs"))); | |
143 | func2_layout->addWidget(new QLabel(tr("mul(x, y, ...)\tProduct of all the inputs"))); | |
144 | func2_layout->addWidget(new QLabel(tr("ncdf(x)\t\tNormal cumulative distribution function"))); | |
145 | func2_layout->addWidget(new QLabel(tr("nequal(x, y)\tNot-equal test between x and y using normalised epsilon"))); | |
146 | func2_layout->addWidget(new QLabel(tr("pow(x, y)\tx to the power of y"))); | |
147 | func2_layout->addWidget(new QLabel(tr("root(x, n)\tNth-Root of x, where n is a positive integer"))); | |
148 | func2_layout->addWidget(new QLabel(tr("round(x)\t\tRound x to the nearest integer"))); | |
149 | func2_layout->addWidget(new QLabel(tr("roundn(x, n)\tRound x to n decimal places, where n > 0 and is an integer"))); | |
150 | func2_layout->addWidget(new QLabel(tr("sgn(x)\t\tSign of x; -1 if x < 0, +1 if x > 0, else zero"))); | |
151 | func2_layout->addWidget(new QLabel(tr("sqrt(x)\t\tSquare root of x, where x >= 0"))); | |
152 | func2_layout->addWidget(new QLabel(tr("sum(x, y, ..,)\tSum of all the inputs"))); | |
153 | func2_layout->addWidget(new QLabel(tr("swap(x, y)\tSwap the values of the variables x and y and return the current value of y"))); | |
154 | func2_layout->addWidget(new QLabel(tr("trunc(x)\t\tInteger portion of x"))); | |
155 | ||
156 | QWidget *trig_page = new QWidget(); | |
157 | QVBoxLayout *trig_layout = new QVBoxLayout(trig_page); | |
158 | trig_layout->addWidget(new QLabel("<b>" + tr("Trigonometry functions:") + "</b>")); | |
159 | trig_layout->addWidget(new QLabel(tr("acos(x)\t\tArc cosine of x expressed in radians. Interval [-1,+1]"))); | |
160 | trig_layout->addWidget(new QLabel(tr("acosh(x)\t\tInverse hyperbolic cosine of x expressed in radians"))); | |
161 | trig_layout->addWidget(new QLabel(tr("asin(x)\t\tArc sine of x expressed in radians. Interval [-1,+1]"))); | |
162 | trig_layout->addWidget(new QLabel(tr("asinh(x)\t\tInverse hyperbolic sine of x expressed in radians"))); | |
163 | trig_layout->addWidget(new QLabel(tr("atan(x)\t\tArc tangent of x expressed in radians. Interval [-1,+1]"))); | |
164 | trig_layout->addWidget(new QLabel(tr("atan2(x, y)\tArc tangent of (x / y) expressed in radians. [-pi,+pi] "))); | |
165 | trig_layout->addWidget(new QLabel(tr("atanh(x)\t\tInverse hyperbolic tangent of x expressed in radians"))); | |
166 | trig_layout->addWidget(new QLabel(tr("cos(x)\t\tCosine of x"))); | |
167 | trig_layout->addWidget(new QLabel(tr("cosh(x)\t\tHyperbolic cosine of x"))); | |
168 | trig_layout->addWidget(new QLabel(tr("cot(x)\t\tCotangent of x"))); | |
169 | trig_layout->addWidget(new QLabel(tr("csc(x)\t\tCosectant of x"))); | |
170 | trig_layout->addWidget(new QLabel(tr("sec(x)\t\tSecant of x"))); | |
171 | trig_layout->addWidget(new QLabel(tr("sin(x)\t\tSine of x"))); | |
172 | trig_layout->addWidget(new QLabel(tr("sinc(x)\t\tSine cardinal of x"))); | |
173 | trig_layout->addWidget(new QLabel(tr("sinh(x)\t\tHyperbolic sine of x"))); | |
174 | trig_layout->addWidget(new QLabel(tr("tan(x)\t\tTangent of x"))); | |
175 | trig_layout->addWidget(new QLabel(tr("tanh(x)\t\tHyperbolic tangent of x"))); | |
176 | trig_layout->addWidget(new QLabel(tr("deg2rad(x)\tConvert x from degrees to radians"))); | |
177 | trig_layout->addWidget(new QLabel(tr("deg2grad(x)\tConvert x from degrees to gradians"))); | |
178 | trig_layout->addWidget(new QLabel(tr("rad2deg(x)\tConvert x from radians to degrees"))); | |
179 | trig_layout->addWidget(new QLabel(tr("grad2deg(x)\tConvert x from gradians to degrees"))); | |
180 | ||
181 | QWidget *logic_page = new QWidget(); | |
182 | QVBoxLayout *logic_layout = new QVBoxLayout(logic_page); | |
183 | logic_layout->addWidget(new QLabel("<b>" + tr("Logic operators:") + "</b>")); | |
184 | logic_layout->addWidget(new QLabel("true\t\tTrue state or any value other than zero (typically 1)")); | |
185 | logic_layout->addWidget(new QLabel("false\t\tFalse state, value of exactly zero")); | |
186 | logic_layout->addWidget(new QLabel("x and y\t\tLogical AND, true only if x and y are both true")); | |
187 | logic_layout->addWidget(new QLabel("mand(x, y, z, ...)\tMulti-input logical AND, true only if all inputs are true")); | |
188 | logic_layout->addWidget(new QLabel("x or y\t\tLogical OR, true if either x or y is true")); | |
189 | logic_layout->addWidget(new QLabel("mor(x, y, z, ...)\tMulti-input logical OR, true if at least one of the inputs is true")); | |
190 | logic_layout->addWidget(new QLabel("x nand y\t\tLogical NAND, true only if either x or y is false")); | |
191 | logic_layout->addWidget(new QLabel("x nor y\t\tLogical NOR, true only if the result of x or y is false")); | |
192 | logic_layout->addWidget(new QLabel("not(x)\t\tLogical NOT, negate the logical sense of the input")); | |
193 | logic_layout->addWidget(new QLabel("x xor y\t\tLogical NOR, true only if the logical states of x and y differ")); | |
194 | logic_layout->addWidget(new QLabel("x xnor y\t\tLogical NOR, true only if x and y have the same state")); | |
195 | logic_layout->addWidget(new QLabel("x & y\t\tSame as AND but with left to right expression short circuiting optimisation")); | |
196 | logic_layout->addWidget(new QLabel("x | y\t\tSame as OR but with left to right expression short circuiting optimisation")); | |
197 | ||
198 | QWidget *control1_page = new QWidget(); | |
199 | QVBoxLayout *control1_layout = new QVBoxLayout(control1_page); | |
200 | control1_layout->addWidget(new QLabel("<b>" + tr("Comparisons:") + "</b>")); | |
201 | control1_layout->addWidget(new QLabel(tr("x = y or x == y\tTrue only if x is strictly equal to y"))); | |
202 | control1_layout->addWidget(new QLabel(tr("x <> y or x != y\tTrue only if x does not equal y"))); | |
203 | control1_layout->addWidget(new QLabel(tr("x < y\t\tTrue only if x is less than y"))); | |
204 | control1_layout->addWidget(new QLabel(tr("x <= y\t\tTrue only if x is less than or equal to y"))); | |
205 | control1_layout->addWidget(new QLabel(tr("x > y\t\tTrue only if x is greater than y"))); | |
206 | control1_layout->addWidget(new QLabel(tr("x >= y\t\tTrue only if x is greater than or equal to y"))); | |
207 | control1_layout->addWidget(new QLabel("<b>" + tr("Flow control:") + "</b>")); | |
208 | control1_layout->addWidget(new QLabel(tr("{ ... }\t\tBeginning and end of instruction block"))); | |
209 | control1_layout->addWidget(new QLabel(tr("if (x, y, z)\tIf x is true then return y else return z\nif (x) y;\t\t\tvariant without implied else\nif (x) { y };\t\tvariant with an instruction block\nif (x) y; else z;\t\tvariant with explicit else\nif (x) { y } else { z };\tvariant with instruction blocks"))); | |
210 | control1_layout->addWidget(new QLabel(tr("x ? y : z\tTernary operator, equivalent to 'if (x, y, z)'"))); | |
211 | control1_layout->addWidget(new QLabel(tr("switch {\t\tThe first true case condition that is encountered will\n case x > 1: a;\tdetermine the result of the switch. If none of the case\n case x < 1: b;\tconditions hold true, the default action is used\n default: c;\tto determine the return value\n}"))); | |
212 | ||
213 | QWidget *control2_page = new QWidget(); | |
214 | QVBoxLayout *control2_layout = new QVBoxLayout(control2_page); | |
215 | control2_layout->addWidget(new QLabel(tr("while (conditon) {\tEvaluates expression repeatedly as long as condition is true,\n expression;\treturning the last value of expression\n}"))); | |
216 | control2_layout->addWidget(new QLabel(tr("repeat\t\tEvalues expression repeatedly as long as condition is false,\n expression;\treturning the last value of expression\nuntil (condition)\n"))); | |
217 | control2_layout->addWidget(new QLabel(tr("for (var x := 0; condition; x += 1) {\tRepeatedly evaluates expression while the condition is true,\n expression\t\t\twhile evaluating the 'increment' expression on each loop\n}"))); | |
218 | control2_layout->addWidget(new QLabel(tr("break\t\tTerminates the execution of the nearest enclosed loop, returning NaN"))); | |
219 | control2_layout->addWidget(new QLabel(tr("break[x]\t\tTerminates the execution of the nearest enclosed loop, returning x"))); | |
220 | control2_layout->addWidget(new QLabel(tr("continue\t\tInterrupts loop execution and resumes with the next loop iteration"))); | |
221 | control2_layout->addWidget(new QLabel(tr("return[x]\t\tReturns immediately from within the current expression, returning x"))); | |
222 | control2_layout->addWidget(new QLabel(tr("~(expr; expr; ...)\tEvaluates each sub-expression and returns the value of the last one\n~{expr; expr; ...}"))); | |
223 | ||
224 | QWidget *example_page = new QWidget(); | |
225 | QVBoxLayout *example_layout = new QVBoxLayout(example_page); | |
226 | for (const pair<string, string> &entry : Examples) { | |
227 | const string &desc = entry.first; | |
228 | const string &example = entry.second; | |
229 | ||
230 | QLabel *desc_label = new QLabel("<b>" + tr(desc.c_str()) + "</b>"); | |
231 | desc_label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard); | |
232 | desc_label->setOpenExternalLinks(true); | |
233 | example_layout->addWidget(desc_label); | |
234 | QPushButton *btn = new QPushButton(tr("Copy to expression")); | |
235 | connect(btn, &QPushButton::clicked, this, [&]() { set_expr(QString::fromStdString(example)); }); | |
236 | QGridLayout *gridlayout = new QGridLayout(); | |
237 | gridlayout->addWidget(new QLabel(QString::fromStdString(example)), 0, 0, Qt::AlignLeft); | |
238 | gridlayout->addWidget(btn, 0, 1, Qt::AlignRight); | |
239 | example_layout->addLayout(gridlayout); | |
240 | } | |
241 | ||
86eeec3b SA |
242 | // Create the rest of the dialog |
243 | QDialogButtonBox *button_box = new QDialogButtonBox( | |
244 | QDialogButtonBox::Ok | QDialogButtonBox::Cancel); | |
245 | ||
2823de2c SA |
246 | QTabWidget *tabs = new QTabWidget(); |
247 | tabs->addTab(basics_page, tr("Basics")); | |
248 | tabs->addTab(func1_page, tr("Functions 1")); | |
249 | tabs->addTab(func2_page, tr("Functions 2")); | |
250 | tabs->addTab(trig_page, tr("Trigonometry")); | |
251 | tabs->addTab(logic_page, tr("Logic")); | |
252 | tabs->addTab(control1_page, tr("Flow Control 1")); | |
253 | tabs->addTab(control2_page, tr("Flow Control 2")); | |
254 | tabs->addTab(example_page, tr("Examples")); | |
255 | ||
256 | QVBoxLayout *root_layout = new QVBoxLayout(this); | |
257 | root_layout->addWidget(tabs); | |
258 | root_layout->addWidget(expr_edit_); | |
86eeec3b SA |
259 | root_layout->addWidget(button_box); |
260 | ||
2823de2c SA |
261 | // Set tab width to 4 characters |
262 | expr_edit_->setTabStopWidth(util::text_width(QFontMetrics(font()), "XXXX")); | |
263 | ||
86eeec3b SA |
264 | connect(button_box, SIGNAL(accepted()), this, SLOT(accept())); |
265 | connect(button_box, SIGNAL(rejected()), this, SLOT(reject())); | |
266 | } | |
267 | ||
2823de2c SA |
268 | void MathEditDialog::set_expr(const QString &expr) |
269 | { | |
270 | expr_edit_->document()->setPlainText(expr); | |
271 | } | |
272 | ||
86eeec3b SA |
273 | void MathEditDialog::accept() |
274 | { | |
2823de2c | 275 | math_signal_->set_expression(expr_edit_->document()->toPlainText()); |
86eeec3b SA |
276 | QDialog::accept(); |
277 | } | |
278 | ||
279 | void MathEditDialog::reject() | |
280 | { | |
281 | math_signal_->set_expression(old_expression_); | |
282 | QDialog::reject(); | |
283 | } | |
284 | ||
285 | ||
4640a84e SA |
286 | MathSignal::MathSignal( |
287 | pv::Session &session, | |
288 | shared_ptr<data::SignalBase> base) : | |
289 | AnalogSignal(session, base), | |
290 | math_signal_(dynamic_pointer_cast<pv::data::MathSignal>(base)) | |
291 | { | |
292 | delayed_expr_updater_.setSingleShot(true); | |
293 | delayed_expr_updater_.setInterval(MATHSIGNAL_INPUT_TIMEOUT); | |
294 | connect(&delayed_expr_updater_, &QTimer::timeout, | |
295 | this, [this]() { math_signal_->set_expression(expression_edit_->text()); }); | |
296 | } | |
297 | ||
298 | void MathSignal::populate_popup_form(QWidget *parent, QFormLayout *form) | |
299 | { | |
300 | AnalogSignal::populate_popup_form(parent, form); | |
301 | ||
302 | expression_edit_ = new QLineEdit(); | |
303 | expression_edit_->setText(math_signal_->get_expression()); | |
86eeec3b SA |
304 | |
305 | const QIcon edit_icon(QIcon::fromTheme("edit", QIcon(":/icons/math.svg"))); | |
306 | QAction *edit_action = | |
307 | expression_edit_->addAction(edit_icon, QLineEdit::TrailingPosition); | |
308 | ||
4640a84e SA |
309 | connect(expression_edit_, SIGNAL(textEdited(QString)), |
310 | this, SLOT(on_expression_changed(QString))); | |
86eeec3b SA |
311 | connect(edit_action, SIGNAL(triggered(bool)), |
312 | this, SLOT(on_edit_clicked())); | |
4640a84e SA |
313 | form->addRow(tr("Expression"), expression_edit_); |
314 | ||
315 | sample_count_cb_ = new QComboBox(); | |
316 | sample_count_cb_->setEditable(true); | |
317 | sample_count_cb_->addItem(tr("same as session")); | |
318 | sample_count_cb_->addItem(tr("100")); | |
319 | sample_count_cb_->addItem(tr("10000")); | |
320 | sample_count_cb_->addItem(tr("1000000")); | |
321 | connect(sample_count_cb_, SIGNAL(editTextChanged(QString)), | |
322 | this, SLOT(on_sample_count_changed(QString))); | |
323 | form->addRow(tr("Number of Samples"), sample_count_cb_); | |
324 | ||
325 | sample_rate_cb_ = new QComboBox(); | |
326 | sample_rate_cb_->setEditable(true); | |
327 | sample_rate_cb_->addItem(tr("same as session")); | |
328 | sample_rate_cb_->addItem(tr("100")); | |
329 | sample_rate_cb_->addItem(tr("10000")); | |
330 | sample_rate_cb_->addItem(tr("1000000")); | |
331 | form->addRow(tr("Sample rate"), sample_rate_cb_); | |
332 | } | |
333 | ||
334 | void MathSignal::on_expression_changed(const QString &text) | |
335 | { | |
336 | (void)text; | |
337 | ||
338 | // Restart update timer | |
339 | delayed_expr_updater_.start(); | |
340 | } | |
341 | ||
342 | void MathSignal::on_sample_count_changed(const QString &text) | |
343 | { | |
344 | (void)text; | |
345 | } | |
346 | ||
86eeec3b SA |
347 | void MathSignal::on_edit_clicked() |
348 | { | |
349 | MathEditDialog dlg(session_, math_signal_); | |
2823de2c | 350 | dlg.set_expr(expression_edit_->text()); |
86eeec3b SA |
351 | |
352 | dlg.exec(); | |
353 | } | |
354 | ||
4640a84e SA |
355 | } // namespace trace |
356 | } // namespace views | |
357 | } // namespace pv |