diff options
Diffstat (limited to 'src/gui.cxx')
-rw-r--r-- | src/gui.cxx | 755 |
1 files changed, 755 insertions, 0 deletions
diff --git a/src/gui.cxx b/src/gui.cxx new file mode 100644 index 0000000..75f1f9c --- /dev/null +++ b/src/gui.cxx @@ -0,0 +1,755 @@ +#include <iostream> +#include <iomanip> +#include "gui_class.h" +#include <gsl/gsl_fit.h> +#include <iostream> +using namespace std; + +#define STRETCH /* nothing */ + +extern int verbosity; // should be in a .h file somewhere + +///////////////// +// some kludgey global variables, +// mostly for inter-thread communication +int pcmRate(0); +double cpkp(0); // cycles per krunch period +double fpkp(0); // frames per krunch period: +double actOutFreq(0); // actual refout frequency +double refOutAmp_dB(-15.); // default should not be not too loud +double VoCal_dB(0.); +double ViCal_dB(0.); +double timeShift(0.); // in seconds +double phaseShift(0.); // in degrees +double lockerPhase(0.); // in degrees +int repaintFrame(0); +// +// Note: more globals can be found in lockin.cxx + +class colorer { +public: + Qt::GlobalColor code; + const char* name; + + colorer(const Qt::GlobalColor _code, const char* const _name) + : code(_code), name(_name) + {} +}; + +#define X(foo) colorer(Qt::foo, #foo) + +static colorer color_list[] = {X(red), X(blue), X(black)}; + +#undef X + +static int color_list_size = sizeof(color_list) / sizeof(color_list[0]); + +#if 0 /* code not needed at present */ +double now(){ + timespec xx; + +#ifdef _POSIX_MONOTONIC_CLOCK + clock_gettime(CLOCK_MONOTONIC, &xx); +#else + clock_gettime(CLOCK_MONOTONIC, &xx); +#endif + + return xx.tv_sec + xx.tv_nsec*1e-9; +} +#endif + +myWindow::myWindow() { +// The top myWindow and its layout : horizontal: + // topWindow == this + topLayout = new QHBoxLayout; + setLayout(topLayout); + + ctrlCol = new ctrl_column(this); + topLayout->addWidget(ctrlCol->group); + + for (int ii = 0; ii < myWindow::numRsltPanels; ii++){ + rsltPanel[ii] = new rslt_panel(this); + topLayout->addWidget(rsltPanel[ii]->group); + } + +// setting the indication to its current value won't +// change the indicator, but will cause it to update +// the associated plot + for (unsigned int ii = 0; ii < ndc8r.size(); ii++){ + indicator* foo = ndc8r[ii]; + foo->setIndication(0,0, foo->rpBox->value(), foo->ipBox->value()); + } + + frameTimer = new timer; +} + +void myWindow::flush() { + if (!repaintFrame) return; + repaintFrame = 0; + for (int ii = 0; ii < numRsltPanels; ii++){ + rsltPanel[ii]->plot->flush(); + } +} + +ctrl_column::ctrl_column(myWindow* topwin){ + group = new QGroupBox; + group->setFlat(0); + layout = new QVBoxLayout; + group->setLayout(layout); + + refOutGroup = new refOut_grouper(topwin); + layout->addWidget(refOutGroup->group); + + layout->insertStretch(-1); + + entrailsGroup = new entrails_grouper(topwin); + layout->addWidget(entrailsGroup->group); +} + + +// the refOut group and its layout: vertical: +refOut_grouper::refOut_grouper(myWindow* _topwin) +: topwin(_topwin), + VLabel(0) +{ +// the freq box + group = new QGroupBox("Ref Out"); + layout = new QVBoxLayout; + group->setLayout(layout); +//group->setStyleSheet("background-color: lavenderblush;"); +//group->setStyleSheet("background-color: rgba(100, 0, 0, 150);"); +//group->setStyleSheet("background-color: lightcyan;"); + group->setStyleSheet(".QGroupBox{background-color: #E8ffFF}"); + freqLabel = new QLabel; + freqLabel->setText("Frequency"); + + freqBox = new QDoubleSpinBox; + freqBox->setRange(0.0, 10000.0); + freqBox->setSingleStep(1); + freqBox->setValue(440); + freqBox->setKeyboardTracking(0); + freqBox->setSuffix(" Hz"); + connect(freqBox, SIGNAL(valueChanged(double)), + this, SLOT(freqChanged(double))); + + actFreqLabel = new QLabel; + actFreqLabel->setText("Actual"); + + actFreqBox = new QDoubleSpinBox; + actFreqBox->setRange(0.0, 10000.0); + actFreqBox->setValue(440); + actFreqBox->setReadOnly(1); + actFreqBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + actFreqBox->setSuffix(" Hz"); + + dBLabel = new QLabel; + dBLabel->setText("Amplitude"); + + dBBox = new QDoubleSpinBox; + dBBox->setRange(-1000.0, 1000.0); + dBBox->setDecimals(3); + dBBox->setSingleStep(1); +//later: dBBox->setValue(refOutAmp_dB); + dBBox->setKeyboardTracking(0); + dBBox->setSuffix(" dBV"); + connect(dBBox, SIGNAL(valueChanged(double)), + this, SLOT(ampChanged(double))); + +// express amplitude in V, not just in dB: +//?? VLabel = new QLabel; +//?? VLabel->setText("???"); + + VBox = new QDoubleSpinBox; + VBox->setRange(-1e300, +1e300); + VBox->setReadOnly(1); + VBox->setDecimals(6); + VBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + VBox->setSuffix(" V"); + + dBBox->setValue(refOutAmp_dB); // will throw ampChanged signal + + layout->addWidget(freqLabel STRETCH); + layout->addWidget(freqBox STRETCH); + layout->addWidget(actFreqLabel STRETCH); + layout->addWidget(actFreqBox STRETCH); + layout->addWidget(dBLabel STRETCH); + layout->addWidget(dBBox STRETCH); + if (VLabel) layout->addWidget(VLabel STRETCH); + layout->addWidget(VBox STRETCH); +} + +// the entrails group and its layout: vertical: +entrails_grouper::entrails_grouper(myWindow* _topwin) +: topwin(_topwin), + tweakFreq(tweakSize), + tweakPhase(tweakSize), + tweakPtr(0), + howmany(0) +{ + group = new QGroupBox("Entrails"); + layout = new QVBoxLayout; + group->setLayout(layout); + group->setStyleSheet("QGroupBox{background-color: #ffffe0}"); + + VoCalLabel = new QLabel; + VoCalLabel->setText("Vo Calibration"); + + VoCalBox = new QDoubleSpinBox; + VoCalBox->setRange(-1e300, +1e300); + VoCalBox->setSingleStep(1); + VoCalBox->setKeyboardTracking(0); + VoCalBox->setSuffix(" dBV FS"); + connect(VoCalBox, SIGNAL(valueChanged(double)), + this, SLOT(VoChanged(double))); + VoCalBox->setValue(VoCal_dB); + + ViCalLabel = new QLabel; + ViCalLabel->setText("Vi Calibration"); + + ViCalBox = new QDoubleSpinBox; + ViCalBox->setRange(-1e300, +1e300); + ViCalBox->setSingleStep(1); + ViCalBox->setKeyboardTracking(0); + ViCalBox->setSuffix(" dBV FS"); + connect(ViCalBox, SIGNAL(valueChanged(double)), + this, SLOT(ViChanged(double))); + ViCalBox->setValue(ViCal_dB); + + rateLabel = new QLabel; + rateLabel->setText("Krunch Rate"); + + rateBox = new QDoubleSpinBox; + rateBox->setRange(0.0, 1e300); + rateBox->setSingleStep(1); + rateBox->setValue(6.); + rateBox->setKeyboardTracking(0); + rateBox->setSuffix(" Hz"); + connect(rateBox, SIGNAL(valueChanged(double)), + this, SLOT(rateChanged(double))); + + actRateLabel = new QLabel; + actRateLabel->setText("Actual"); + + actRateBox = new QDoubleSpinBox; + actRateBox->setRange(0.0, 1e300); + actRateBox->setValue(6.); + actRateBox->setReadOnly(1); + actRateBox->setSuffix(" Hz"); + actRateBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + + pcmLabel = new QLabel; + pcmLabel->setText("PCM Rate"); + + pcmBox = new QDoubleSpinBox; + pcmBox->setRange(-1e300, +1e300); + pcmBox->setValue(440); + pcmBox->setReadOnly(1); + pcmBox->setSuffix(" Hz"); + pcmBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + + timeShiftLabel = new QLabel; + timeShiftLabel->setText("Time Shift"); + + timeShiftBox = new QDoubleSpinBox; + timeShiftBox->setRange(-1000.0, 1000.0); + timeShiftBox->setDecimals(6); + timeShiftBox->setSingleStep(1e-6); + timeShiftBox->setValue(timeShift); + timeShiftBox->setKeyboardTracking(0); + timeShiftBox->setSuffix(" s"); + connect(timeShiftBox, SIGNAL(valueChanged(double)), + this, SLOT(timeShiftChanged(double))); + + phaseShiftLabel = new QLabel; + phaseShiftLabel->setText("Phase Shift"); + + phaseShiftBox = new QDoubleSpinBox; + phaseShiftBox->setRange(-1e300, +1e300); + phaseShiftBox->setDecimals(2); + phaseShiftBox->setSingleStep(1); + phaseShiftBox->setValue(phaseShift); + phaseShiftBox->setKeyboardTracking(0); + phaseShiftBox->setSuffix(QString::fromUtf8(" °")); + connect(phaseShiftBox, SIGNAL(valueChanged(double)), + this, SLOT(phaseShiftChanged(double))); + + tweakButton = new QPushButton("&Tweak"); + connect(tweakButton, SIGNAL(clicked()), + this, SLOT(tweakButtonClicked())); + + layout->addWidget(VoCalLabel STRETCH); + layout->addWidget(VoCalBox STRETCH); + + layout->addWidget(ViCalLabel STRETCH); + layout->addWidget(ViCalBox STRETCH); + + layout->addWidget(rateLabel STRETCH); + layout->addWidget(rateBox STRETCH); + layout->addWidget(actRateLabel STRETCH); + layout->addWidget(actRateBox STRETCH); + layout->addWidget(pcmLabel STRETCH); + layout->addWidget(pcmBox STRETCH); + layout->addWidget(timeShiftLabel STRETCH); + layout->addWidget(timeShiftBox STRETCH); + layout->addWidget(phaseShiftLabel STRETCH); + layout->addWidget(phaseShiftBox STRETCH); + layout->addWidget(tweakButton STRETCH); +} + +rslt_panel::rslt_panel(myWindow* _topWin) +: topWin(_topWin) +{ + group = new QGroupBox; + group->setFlat(0); + layout = new QHBoxLayout; + group->setLayout(layout); + plot = new myPlot("plotname"); + block = new blockOfIndicators(topWin, plot); +// layout->addWidget(plot, 0, Qt::AlignHCenter); + layout->addWidget(plot); + layout->addWidget(block->group); + layout->insertStretch(-1); +} + +double quantize125(double arg){ + if (arg < sqrt(2.)) return 1.; + if (arg < sqrt(10.)) return 2.; + if (arg < sqrt(50.)) return 5.; + return 10.; +} + +double logstep(double arg){ + double ctc = pow(10., floor(log10(arg))); + double mant = arg / ctc; + return quantize125(mant) * ctc; +} + +scaleBoxer::scaleBoxer(indicator* _parent) +: parent(_parent) +{} + +void scaleBoxer::stepBy(int steps){ + double newval(1); + if (steps == 1) newval = logstep(2.0 * logstep(value())); + if (steps == -1) newval = logstep(0.5 * logstep(value())); + + if (steps == 10) newval = logstep(10.0 * value()); + if (steps == -10) newval = logstep( 0.1 * value()); + parent->setDecim(newval); + setValue(newval); +} + +void indicator::setDecim(const double newval){ + int decim = -int(floor(log10(newval))); + scaleBox->setDecimals(std::max(0, decim)); + rpBox->setDecimals(std::max(0, 2+decim)); + ipBox->setDecimals(std::max(0, 2+decim)); + magBox->setDecimals(std::max(0, 2+decim)); +} + + +// An indicator and its internal layout: grid: +indicator::indicator(myPlot* _plot, int _locker) +: plot(_plot), + plotcur(0), + locker(_locker) +{ + if (plot) { + plotcur = plot->assign_curve(); + } + + group = new QGroupBox; + group->setFlat(0); + QString style = ".QGroupBox{"; + if (plot) { + style += "border-top: 4px solid "; + style += color_list[plotcur % color_list_size].name; + style += ";"; + } + style += "background-color: #D0ffD0;"; + style += "}"; + group->setStyleSheet(style); + + layout = new QGridLayout; + group->setLayout(layout); + + scaleLabel = new QLabel; + scaleLabel->setText("Scale"); + + scaleBox = new scaleBoxer(this); + scaleBox->setKeyboardTracking(0); + scaleBox->setRange(-1e300, +1e300); + double sc(pow(10., ViCal_dB/20.)); + sc /= 2.5; // half scale, where full scale is 5 divisions + sc = logstep(sc); + scaleBox->setDecimals(10); + scaleBox->setValue(sc); + scaleBox->setSuffix(" V/div"); + + rpLabel = new QLabel; + rpLabel->setText("Rp"); + + rpBox = new QDoubleSpinBox; + rpBox->setReadOnly(1); + rpBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + rpBox->setRange(-1e300, +1e300); + rpBox->setValue(0); + rpBox->setSuffix(" V"); + + ipLabel = new QLabel; + ipLabel->setText("Ip"); + + ipBox = new QDoubleSpinBox; + ipBox->setReadOnly(1); + ipBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + ipBox->setRange(-1e300, +1e300); + ipBox->setValue(0); + ipBox->setSuffix(" V"); + + magLabel = new QLabel; + magLabel->setText("Mag"); + + magBox = new QDoubleSpinBox; + magBox->setReadOnly(1); + magBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + magBox->setRange(-1e300, +1e300); + magBox->setValue(0.1234); + magBox->setSuffix(" V"); + + phaseLabel = new QLabel; + phaseLabel->setText("Phase"); + + phaseBox = new QDoubleSpinBox; + phaseBox->setReadOnly(1); + phaseBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + phaseBox->setRange(-1e300, +1e300); + phaseBox->setSuffix(QString::fromUtf8(" °")); + + setDecim(sc); + + int row(0); + layout->addWidget(scaleLabel, row, 0); + row++; + layout->addWidget(scaleBox, row, 0); + row++; + layout->addWidget(rpLabel, row, 0); + layout->addWidget(ipLabel, row, 1); + row++; + layout->addWidget(rpLabel, row, 0); + layout->addWidget(ipLabel, row, 1); + row++; + layout->addWidget(rpBox, row, 0); + layout->addWidget(ipBox, row, 1); + row++; + layout->addWidget(magLabel, row, 0); + layout->addWidget(phaseLabel, row, 1); + row++; + layout->addWidget(magBox, row, 0); + layout->addWidget(phaseBox, row, 1); +} + +blockOfIndicators::blockOfIndicators(myWindow* topwin, myPlot* plot) +{ + group = new QGroupBox; + group->setFlat(0); + group->setStyleSheet("border:0;"); + layout = new QVBoxLayout; + indicator* temp; + group->setLayout(layout); + + temp = new indicator(plot, 1/* phaselock */); + topwin->ndc8r.push_back(temp); + layout->addWidget(temp->group); + + temp = new indicator(plot); + topwin->ndc8r.push_back(temp); + layout->addWidget(temp->group); + + temp = new indicator(plot); + topwin->ndc8r.push_back(temp); + layout->addWidget(temp->group); + + layout->insertStretch(-1); +} + +void indicator::setIndication(const double rp0, const double ip0, + const double rp1, const double ip1){ + double rp(rp1-rp0); + double ip(ip1-ip0); + double mag(sqrt(rp*rp + ip*ip)); + double phase(0); + if (mag) phase = atan2(ip, rp); + rpBox->setValue(rp); + ipBox->setValue(ip); + magBox->setValue(mag); + double phDeg = phase * 180 / M_PI; + phaseBox->setValue(phDeg); + if (locker) lockerPhase = phDeg; + if (plot) { + double denom = scaleBox->value(); // volts per division + denom *= plot->divsPerUnit; // volts full scale + plot->setReading(plotcur, rp0/denom, ip0/denom, rp1/denom, ip1/denom); + } +} + +void myPlot::flush() { + if (need_replot) replot(); +} + +void myPlot::setReading(const int ndx, + const double rp0, const double ip0, + const double rp1, const double ip1){ + int npts(2); + double xxx[npts]; + double yyy[npts]; + xxx[0] = rp0; + yyy[0] = ip0; + xxx[1] = rp1; + yyy[1] = ip1; +////////////////// curve[ndx]->setData(xxx, yyy, npts); + curve[ndx]->setSamples(xxx, yyy, npts); + need_replot = 1; +} + +// There is no such thing as a scale change on the plot. +// Rescale the data instead. +#ifdef OLD_SCALE_IDEA +void myPlot::scaleChange(double newScale){ + setAxisScale(QwtPlot::xBottom, -newScale, newScale); + setAxisScale(QwtPlot::yLeft, -newScale, newScale); + replot(); +} +#endif + +// Unless you set keyboardTracking to false, +// this is useless when typing in digits : +// signals too early and too often. +void refOut_grouper::freqChanged(double /* newfreq not used */) +{ + topwin->actualFreqs(); +} + +void entrails_grouper::VoChanged(double newVo) +{ + VoCal_dB = newVo; +//wrong topwin->ctrlCol->refOutGroup->VBox-> +//wrong setValue(pow(10., (refOutAmp_dB + VoCal_dB)/20.)); +} + +void entrails_grouper::ViChanged(double newVi) +{ + ViCal_dB = newVi; +} + +void refOut_grouper::ampChanged(double newAmp) +{ + refOutAmp_dB = newAmp; +//wrong: VBox->setValue(pow(10., (refOutAmp_dB + VoCal_dB)/20.)); + VBox->setValue(pow(10., (refOutAmp_dB)/20.)); +} + +void entrails_grouper::rateChanged(double /* newRate not used */) +{ + topwin->actualFreqs(); +} + +// beware the fmod of a negative number is negative +double pval(const double angle){ + double rslt = fmod(angle, 360.); + if (rslt > 180.) rslt -= 360.; + if (rslt < -180.) rslt += 360.; + return rslt; +} + +void entrails_grouper::timeShiftChanged(double newTimeShift) +{ +//-- std::cout << "timeShiftChange: " << newTimeShift << std::endl; + +// Calculate new phase such that changing the timeShift +// doesn't change the phase; it is only supposed to +// change d(phase)/d(frequency). + double newPhase = phaseShift - (newTimeShift - timeShift) * actOutFreq * 360.; + newPhase = pval(newPhase); + timeShift = newTimeShift; + phaseShiftBox->setValue(newPhase); +} + +void entrails_grouper::phaseShiftChanged(double newPhaseShift) +{ +//-- std::cout << "phaseShiftChange: " << newPhaseShift << std::endl; + + while (newPhaseShift > 360.) newPhaseShift -= 360.; + while (newPhaseShift < -360.) newPhaseShift += 360.; + + phaseShift = newPhaseShift; +} + +class bad_thing: public std::exception{ + const char* msg; + virtual const char* what() const throw() { + return msg; + } +public: + bad_thing(const char* _msg) + : msg(_msg) {} +}; + +double max(const std::valarray<double>& foo){ + unsigned int howmany(foo.size()); + if (howmany == 0) throw bad_thing("max of empty list"); + double rslt = foo[0]; + for (unsigned int ii = 1; ii < howmany; ii++) { + rslt = std::max(rslt, foo[ii]); + } + return rslt; +} + +double min(const std::valarray<double>& foo){ + unsigned int howmany(foo.size()); + if (howmany == 0) throw bad_thing("min of empty list"); + double rslt = foo[0]; + for (unsigned int ii = 1; ii < howmany; ii++) { + rslt = std::min(rslt, foo[ii]); + } + return rslt; +} + +void entrails_grouper::tweakButtonClicked(){ + using namespace std; + double rawPhase = (lockerPhase + phaseShift) + + actOutFreq*timeShift * 360.; + + if (tweakPtr >= 10) tweakPtr = 0; + tweakFreq[tweakPtr] = actOutFreq; + tweakPhase[tweakPtr] = rawPhase; + tweakPtr++; + if (howmany < tweakPtr) howmany = tweakPtr; + // otherwise howmany stays at its maximum, i.e. tweakSize. + + valarray<double> myFreq(&tweakFreq[0], howmany); + valarray<double> myPhase(&tweakPhase[0], howmany); + + double big = max(myFreq); + double little = min(myFreq); + if (big == little) { + double newPhase = myPhase.sum() / howmany - timeShift*myFreq[0]*360.; +// This will change the value in the box, and raise +// the valueChanged signal: + phaseShiftBox->setValue(pval(newPhase)); + } else do { + valarray<double> cookedPhase(myPhase); + valarray<double> cookedFreq(myFreq); + for (unsigned int ii = 0; ii < howmany; ii++) { + cookedFreq[ii] -= actOutFreq; + cookedPhase[ii] -= phaseShift + timeShift*myFreq[ii]*360.; + cookedPhase[ii] = pval(cookedPhase[ii]); + } + if (max(cookedPhase) > 90. || min(cookedPhase) < -90.) { + cout << "Phase range too big; can't tweak." << endl; + break; + } + double intercept, slope; + double cv00, cv01, cv11; + double sumsq; + gsl_fit_linear(&cookedFreq[0], 1, + &cookedPhase[0], 1, howmany, + &intercept, &slope, + &cv00, &cv01, &cv11, + &sumsq); + + double newTime = timeShift + slope / 360.; + double newPhase = phaseShift + intercept + - (newTime - timeShift) * actOutFreq * 360.; +// must do time shift first: + timeShiftBox->setValue(newTime); + phaseShiftBox->setValue(pval(newPhase)); + + } while (0); +} + +void myWindow::actualFreqs() { + using namespace std; + double d_out_freq = ctrlCol->refOutGroup->freqBox->value(); + { // calculatte cycles per krunch period + double d_krunch_rate = ctrlCol->entrailsGroup->rateBox->value(); + if (d_krunch_rate == 0.) cpkp = 1; + else cpkp = round(d_out_freq/d_krunch_rate); + if (cpkp < 1.) cpkp = 1.; + } +// frames per krunch period: + fpkp = round(cpkp * pcmRate / d_out_freq); + double actUp = pcmRate / fpkp; + ctrlCol->entrailsGroup->actRateBox->setValue(actUp); + ctrlCol->entrailsGroup->pcmBox->setValue(pcmRate); + + actOutFreq = cpkp * actUp; + ctrlCol->refOutGroup->actFreqBox->setValue(actOutFreq); + if (verbosity > 0) { + cout.precision(4); + cout << fixed; + cout << " d_out_freq: " << d_out_freq + << " cpkp: " << cpkp + << " fpkp: " << fpkp + << " actUp: " << setw(10) << actUp + << " actOutFreq: " << actOutFreq + << endl; + } +} + +myPlot::myPlot(const QString name) : QwtPlot(QwtText(name)), + grid(), divsPerUnit(5), need_replot(0) + { +// FIXME : should calculate these sizes: + setMinimumWidth(500); setMaximumWidth(500); + setMinimumHeight(500); setMaximumHeight(500); + +// Set up axis, permanently -1 to 1 in both directions. +// We are ASSUMING the library function will give us +// five minor divisions per unit (ten total). + setAxisScale(QwtPlot::xBottom,-1.0, 1.0, 1.); + setAxisScale(QwtPlot::yLeft, -1.0, 1.0, 1.); + enableAxis(QwtPlot::xBottom, 0); + enableAxis(QwtPlot::yLeft, 0); + setStyleSheet("border:0;"); + + grid.enableXMin(true); + grid.enableYMin(true); + grid.setMajorPen(QPen(Qt::white, 2)); + grid.setMinorPen(QPen(Qt::white, 1)); +// was: (QPen(Qt::white, 1, Qt::DotLine)); + grid.attach(this); +} + +int myPlot::assign_curve(){ + int ndx = curve.size(); + + curve.push_back(new QwtPlotCurve); + + int npts(2); + double xxx[npts]; + double yyy[npts]; + xxx[0] = 0; + yyy[0] = 0; + xxx[1] = sin(.1 * ndx); + yyy[1] = cos(.2 * ndx); + +///////////// curve[ndx]->setData(xxx, yyy, npts); + curve[ndx]->setSamples(xxx, yyy, npts); + curve[ndx]->setPen(QPen(color_list[ndx % color_list_size].code, 4)); + curve[ndx]->attach(this); + + return ndx; +} + +//////////////////////////////////// + +timer::timer(QWidget *parent) +: QWidget(parent) +{ + startTimer(33); // 30.303 repaints per second +} + +void timer::timerEvent(QTimerEvent* /* event not used */){ + using namespace std; + repaintFrame = 1; +} |