00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <QDragEnterEvent>
00020 #include <QDropEvent>
00021 #include <QFile>
00022 #include <QFileDialog>
00023 #include <QFontMetrics>
00024 #include <QPainter>
00025 #include <QTextStream>
00026 #include <QMimeData>
00027
00028 #include <qwt/qwt_plot_canvas.h>
00029 #include <qwt/qwt_plot_curve.h>
00030 #include <qwt/qwt_plot_picker.h>
00031 #include <qwt/qwt_plot_renderer.h>
00032 #include <qwt/qwt_scale_widget.h>
00033 #include <qwt/qwt_plot.h>
00034
00035 #include <ros/package.h>
00036
00037 #include <rqt_multiplot/CurveData.h>
00038 #include <rqt_multiplot/PlotConfigDialog.h>
00039 #include <rqt_multiplot/PlotConfigWidget.h>
00040 #include <rqt_multiplot/PlotCursor.h>
00041 #include <rqt_multiplot/PlotCurve.h>
00042 #include <rqt_multiplot/PlotLegend.h>
00043 #include <rqt_multiplot/PlotMagnifier.h>
00044 #include <rqt_multiplot/PlotPanner.h>
00045 #include <rqt_multiplot/PlotZoomer.h>
00046
00047 #include <ui_PlotWidget.h>
00048
00049 #include "rqt_multiplot/PlotWidget.h"
00050
00051 namespace rqt_multiplot {
00052
00053
00054
00055
00056
00057 PlotWidget::PlotWidget(QWidget* parent) :
00058 QWidget(parent),
00059 ui_(new Ui::PlotWidget()),
00060 timer_(new QTimer(this)),
00061 menuImportExport_(new QMenu(this)),
00062 config_(0),
00063 broker_(0),
00064 legend_(0),
00065 cursor_(0),
00066 panner_(0),
00067 magnifier_(0),
00068 zoomer_(0),
00069 paused_(true),
00070 rescale_(false),
00071 replot_(false),
00072 state_(Normal) {
00073 qRegisterMetaType<BoundingRectangle>("BoundingRectangle");
00074
00075 ui_->setupUi(this);
00076
00077 setAcceptDrops(true);
00078
00079 runIcon_ = QIcon(QString::fromStdString(ros::package::getPath(
00080 "rqt_multiplot").append("/resource/16x16/run.png")));
00081 pauseIcon_ = QIcon(QString::fromStdString(ros::package::getPath(
00082 "rqt_multiplot").append("/resource/16x16/pause.png")));
00083 normalIcon_ = QIcon(QString::fromStdString(ros::package::getPath(
00084 "rqt_multiplot").append("/resource/16x16/zoom_in.png")));
00085 maximizedIcon_ = QIcon(QString::fromStdString(ros::package::getPath(
00086 "rqt_multiplot").append("/resource/16x16/zoom_out.png")));
00087
00088 ui_->pushButtonRunPause->setIcon(runIcon_);
00089 ui_->pushButtonClear->setIcon(
00090 QIcon(QString::fromStdString(ros::package::getPath("rqt_multiplot").
00091 append("/resource/16x16/clear.png"))));
00092 ui_->pushButtonImportExport->setIcon(
00093 QIcon(QString::fromStdString(ros::package::getPath("rqt_multiplot").
00094 append("/resource/16x16/eject.png"))));
00095 ui_->pushButtonSetup->setIcon(
00096 QIcon(QString::fromStdString(ros::package::getPath("rqt_multiplot").
00097 append("/resource/16x16/setup.png"))));
00098 ui_->pushButtonState->setIcon(normalIcon_);
00099
00100 ui_->plot->setAutoReplot(false);
00101 static_cast<QFrame*>(ui_->plot->canvas())->setFrameStyle(QFrame::NoFrame);
00102
00103 ui_->plot->enableAxis(QwtPlot::xTop);
00104 ui_->plot->enableAxis(QwtPlot::yRight);
00105
00106 ui_->plot->setAxisAutoScale(QwtPlot::yLeft, false);
00107 ui_->plot->setAxisAutoScale(QwtPlot::yRight, false);
00108 ui_->plot->setAxisAutoScale(QwtPlot::xTop, false);
00109 ui_->plot->setAxisAutoScale(QwtPlot::xBottom, false);
00110
00111 ui_->plot->axisScaleDraw(QwtPlot::xTop)->enableComponent(
00112 QwtAbstractScaleDraw::Labels, false);
00113 ui_->plot->axisScaleDraw(QwtPlot::yRight)->enableComponent(
00114 QwtAbstractScaleDraw::Labels, false);
00115
00116 ui_->horizontalSpacerRight->changeSize(
00117 ui_->plot->axisWidget(QwtPlot::yRight)->width()-5, 20);
00118
00119 timer_->setInterval(1e3/30.0);
00120 timer_->start();
00121
00122 menuImportExport_->addAction("Export to image file...", this,
00123 SLOT(menuExportImageFileTriggered()));
00124 menuImportExport_->addAction("Export to text file...", this,
00125 SLOT(menuExportTextFileTriggered()));
00126
00127 QwtPlotCanvas* canvas = static_cast<QwtPlotCanvas*>(ui_->plot->canvas());
00128 cursor_ = new PlotCursor(canvas);
00129 magnifier_ = new PlotMagnifier(canvas);
00130 panner_ = new PlotPanner(canvas);
00131 zoomer_ = new PlotZoomer(canvas);
00132 zoomer_->setTrackerMode(QwtPicker::AlwaysOff);
00133
00134 #if QWT_VERSION >= 0x060100
00135 currentBounds_.getMinimum().setX(ui_->plot->axisScaleDiv(
00136 QwtPlot::xBottom).lowerBound());
00137 currentBounds_.getMinimum().setY(ui_->plot->axisScaleDiv(
00138 QwtPlot::yLeft).lowerBound());
00139 currentBounds_.getMaximum().setX(ui_->plot->axisScaleDiv(
00140 QwtPlot::xBottom).upperBound());
00141 currentBounds_.getMaximum().setY(ui_->plot->axisScaleDiv(
00142 QwtPlot::yLeft).upperBound());
00143 #else
00144 currentBounds_.getMinimum().setX(ui_->plot->axisScaleDiv(
00145 QwtPlot::xBottom)->lowerBound());
00146 currentBounds_.getMinimum().setY(ui_->plot->axisScaleDiv(
00147 QwtPlot::yLeft)->lowerBound());
00148 currentBounds_.getMaximum().setX(ui_->plot->axisScaleDiv(
00149 QwtPlot::xBottom)->upperBound());
00150 currentBounds_.getMaximum().setY(ui_->plot->axisScaleDiv(
00151 QwtPlot::yLeft)->upperBound());
00152 #endif
00153
00154 connect(ui_->lineEditTitle, SIGNAL(textChanged(const QString&)), this,
00155 SLOT(lineEditTitleTextChanged(const QString&)));
00156 connect(ui_->lineEditTitle, SIGNAL(editingFinished()), this,
00157 SLOT(lineEditTitleEditingFinished()));
00158
00159 connect(ui_->pushButtonRunPause, SIGNAL(clicked()), this,
00160 SLOT(pushButtonRunPauseClicked()));
00161 connect(ui_->pushButtonClear, SIGNAL(clicked()), this,
00162 SLOT(pushButtonClearClicked()));
00163 connect(ui_->pushButtonSetup, SIGNAL(clicked()), this,
00164 SLOT(pushButtonSetupClicked()));
00165 connect(ui_->pushButtonImportExport, SIGNAL(clicked()), this,
00166 SLOT(pushButtonImportExportClicked()));
00167 connect(ui_->pushButtonState, SIGNAL(clicked()), this,
00168 SLOT(pushButtonStateClicked()));
00169
00170 connect(ui_->plot->axisWidget(QwtPlot::xBottom),
00171 SIGNAL(scaleDivChanged()), this, SLOT(plotXBottomScaleDivChanged()));
00172 connect(ui_->plot->axisWidget(QwtPlot::yLeft),
00173 SIGNAL(scaleDivChanged()), this, SLOT(plotYLeftScaleDivChanged()));
00174
00175 connect(timer_, SIGNAL(timeout()), this, SLOT(timerTimeout()));
00176
00177 ui_->plot->axisWidget(QwtPlot::yLeft)->installEventFilter(this);
00178 ui_->plot->axisWidget(QwtPlot::yRight)->installEventFilter(this);
00179 }
00180
00181 PlotWidget::~PlotWidget() {
00182 delete ui_;
00183 }
00184
00185
00186
00187
00188
00189 void PlotWidget::setConfig(PlotConfig* config) {
00190 if (config != config_) {
00191 if (config_) {
00192 disconnect(config_, SIGNAL(titleChanged(const QString&)), this,
00193 SLOT(configTitleChanged(const QString&)));
00194 disconnect(config_, SIGNAL(curveAdded(size_t)), this,
00195 SLOT(configCurveAdded(size_t)));
00196 disconnect(config_, SIGNAL(curveRemoved(size_t)), this,
00197 SLOT(configCurveRemoved(size_t)));
00198 disconnect(config_, SIGNAL(curvesCleared()), this,
00199 SLOT(configCurvesCleared()));
00200 disconnect(config_, SIGNAL(curveConfigChanged(size_t)), this,
00201 SLOT(configCurveConfigChanged(size_t)));
00202 disconnect(config_->getAxesConfig()->getAxisConfig(PlotAxesConfig::X),
00203 SIGNAL(changed()), this, SLOT(configXAxisConfigChanged()));
00204 disconnect(config_->getAxesConfig()->getAxisConfig(PlotAxesConfig::Y),
00205 SIGNAL(changed()), this, SLOT(configYAxisConfigChanged()));
00206 disconnect(config_->getLegendConfig(), SIGNAL(changed()), this,
00207 SLOT(configLegendConfigChanged()));
00208 disconnect(config_, SIGNAL(plotRateChanged(double)), this,
00209 SLOT(configPlotRateChanged(double)));
00210
00211 configCurvesCleared();
00212 }
00213
00214 config_ = config;
00215
00216 if (config) {
00217 connect(config, SIGNAL(titleChanged(const QString&)), this,
00218 SLOT(configTitleChanged(const QString&)));
00219 connect(config, SIGNAL(curveAdded(size_t)), this,
00220 SLOT(configCurveAdded(size_t)));
00221 connect(config, SIGNAL(curveRemoved(size_t)), this,
00222 SLOT(configCurveRemoved(size_t)));
00223 connect(config, SIGNAL(curvesCleared()), this,
00224 SLOT(configCurvesCleared()));
00225 connect(config, SIGNAL(curveConfigChanged(size_t)), this,
00226 SLOT(configCurveConfigChanged(size_t)));
00227 connect(config->getAxesConfig()->getAxisConfig(PlotAxesConfig::X),
00228 SIGNAL(changed()), this, SLOT(configXAxisConfigChanged()));
00229 connect(config->getAxesConfig()->getAxisConfig(PlotAxesConfig::Y),
00230 SIGNAL(changed()), this, SLOT(configYAxisConfigChanged()));
00231 connect(config->getLegendConfig(), SIGNAL(changed()), this,
00232 SLOT(configLegendConfigChanged()));
00233 connect(config, SIGNAL(plotRateChanged(double)), this,
00234 SLOT(configPlotRateChanged(double)));
00235
00236 configTitleChanged(config->getTitle());
00237 configPlotRateChanged(config->getPlotRate());
00238 configXAxisConfigChanged();
00239 configYAxisConfigChanged();
00240 configLegendConfigChanged();
00241
00242 for (size_t index = 0; index < config->getNumCurves(); ++index)
00243 configCurveAdded(index);
00244 }
00245 }
00246 }
00247
00248 PlotConfig* PlotWidget::getConfig() const {
00249 return config_;
00250 }
00251
00252 void PlotWidget::setBroker(MessageBroker* broker) {
00253 if (broker != broker_) {
00254 broker_ = broker;
00255
00256 for (size_t index = 0; index < curves_.count(); ++index)
00257 curves_[index]->setBroker(broker);
00258 }
00259 }
00260
00261 MessageBroker* PlotWidget::getBroker() const {
00262 return broker_;
00263 }
00264
00265 PlotCursor* PlotWidget::getCursor() const {
00266 return cursor_;
00267 }
00268
00269 BoundingRectangle PlotWidget::getPreferredScale() const {
00270 BoundingRectangle bounds;
00271
00272 for (size_t index = 0; index < curves_.count(); ++index)
00273 bounds += curves_[index]->getPreferredScale();
00274
00275 return bounds;
00276 }
00277
00278 void PlotWidget::setCurrentScale(const BoundingRectangle& bounds) {
00279 if (bounds != currentBounds_) {
00280 if (bounds.getMaximum().x() == bounds.getMinimum().x())
00281 ui_->plot->setAxisScale(QwtPlot::xBottom, bounds.getMinimum().x() - 0.1,
00282 bounds.getMaximum().x() + 0.1);
00283 else if (bounds.getMaximum().x() > bounds.getMinimum().x())
00284 ui_->plot->setAxisScale(QwtPlot::xBottom, bounds.getMinimum().x(),
00285 bounds.getMaximum().x());
00286 if (bounds.getMaximum().y() == bounds.getMinimum().y())
00287 ui_->plot->setAxisScale(QwtPlot::yLeft, bounds.getMinimum().y() - 0.1,
00288 bounds.getMaximum().y() + 0.1);
00289 else if (bounds.getMaximum().y() > bounds.getMinimum().y())
00290 ui_->plot->setAxisScale(QwtPlot::yLeft, bounds.getMinimum().y(),
00291 bounds.getMaximum().y());
00292
00293 rescale_ = false;
00294
00295 forceReplot();
00296 }
00297 }
00298
00299 const BoundingRectangle& PlotWidget::getCurrentScale() const {
00300 return currentBounds_;
00301 }
00302
00303 bool PlotWidget::isPaused() const {
00304 return paused_;
00305 }
00306
00307 bool PlotWidget::isReplotRequested() const {
00308 return replot_;
00309 }
00310
00311 void PlotWidget::setState(State state) {
00312 if ((state != state_) && canChangeState()) {
00313 state_ = state;
00314
00315 if (state == Maximized)
00316 ui_->pushButtonState->setIcon(maximizedIcon_);
00317 else
00318 ui_->pushButtonState->setIcon(normalIcon_);
00319
00320 emit stateChanged(state);
00321 }
00322 }
00323
00324 PlotWidget::State PlotWidget::getState() const {
00325 return state_;
00326 }
00327
00328 void PlotWidget::setCanChangeState(bool can) {
00329 ui_->pushButtonState->setEnabled(can);
00330 }
00331
00332 bool PlotWidget::canChangeState() const {
00333 return ui_->pushButtonState->isEnabled();
00334 }
00335
00336
00337
00338
00339
00340 void PlotWidget::run() {
00341 if (paused_) {
00342 paused_ = false;
00343
00344 for (size_t index = 0; index < curves_.count(); ++index)
00345 curves_[index]->run();
00346
00347 ui_->pushButtonRunPause->setIcon(pauseIcon_);
00348
00349 emit pausedChanged(false);
00350 }
00351 }
00352
00353 void PlotWidget::pause() {
00354 if (!paused_) {
00355 for (size_t index = 0; index < curves_.count(); ++index)
00356 curves_[index]->pause();
00357
00358 paused_ = true;
00359
00360 ui_->pushButtonRunPause->setIcon(runIcon_);
00361
00362 emit pausedChanged(true);
00363 }
00364 }
00365
00366 void PlotWidget::clear() {
00367 for (size_t index = 0; index < curves_.count(); ++index)
00368 curves_[index]->clear();
00369
00370 forceReplot();
00371
00372 emit cleared();
00373 }
00374
00375 void PlotWidget::requestReplot() {
00376 replot_ = true;
00377 }
00378
00379 void PlotWidget::forceReplot() {
00380 BoundingRectangle preferredBounds = getPreferredScale();
00381
00382 if (rescale_) {
00383 emit preferredScaleChanged(preferredBounds);
00384
00385 rescale_ = false;
00386 }
00387
00388 zoomer_->setZoomBase(preferredBounds.getRectangle());
00389
00390 ui_->plot->replot();
00391
00392 replot_ = false;
00393 }
00394
00395 void PlotWidget::renderToPixmap(QPixmap& pixmap, const QRectF& bounds) {
00396 QRectF plotBounds = bounds;
00397
00398 if (plotBounds.isEmpty())
00399 plotBounds = QRectF(0, 0, pixmap.width(), pixmap.height());
00400
00401 QwtPlotRenderer renderer;
00402
00403 renderer.setDiscardFlag(QwtPlotRenderer::DiscardBackground, true);
00404 renderer.setDiscardFlag(QwtPlotRenderer::DiscardCanvasBackground, true);
00405
00406 QPainter painter(&pixmap);
00407 size_t textHeight = 0;
00408
00409 if (config_) {
00410 textHeight = painter.fontMetrics().boundingRect(config_->
00411 getTitle()).height();
00412
00413 painter.drawText(QRectF(plotBounds.x(), plotBounds.y(),
00414 plotBounds.width(), textHeight), Qt::AlignHCenter |
00415 Qt::AlignVCenter, config_->getTitle());
00416 }
00417
00418 renderer.render(ui_->plot, &painter, QRectF(plotBounds.x(),
00419 plotBounds.y()+textHeight+10, plotBounds.width(), plotBounds.
00420 height()-textHeight-10));
00421 }
00422
00423 void PlotWidget::writeFormattedCurveData(QList<QStringList>& formattedData) {
00424 formattedData.clear();
00425
00426 for (size_t index = 0; index < curves_.count(); ++index) {
00427 QStringList formattedX, formattedY;
00428
00429 curves_[index]->getData()->writeFormatted(formattedX, formattedY);
00430
00431 formattedData.append(formattedX);
00432 formattedData.append(formattedY);
00433 }
00434 }
00435
00436 void PlotWidget::writeFormattedCurveAxisTitles(QStringList&
00437 formattedAxisTitles) {
00438 formattedAxisTitles.clear();
00439
00440 for (size_t index = 0; index < curves_.count(); ++index) {
00441 CurveAxisConfig* xAxisConfig = curves_[index]->getConfig()->
00442 getAxisConfig(CurveConfig::X);
00443 CurveAxisConfig* yAxisConfig = curves_[index]->getConfig()->
00444 getAxisConfig(CurveConfig::Y);
00445
00446 QString xAxisTitle = xAxisConfig->getTopic();
00447 QString yAxisTitle = yAxisConfig->getTopic();
00448
00449 if (xAxisConfig->getFieldType() == CurveAxisConfig::MessageData)
00450 xAxisTitle += "/"+xAxisConfig->getField();
00451 else
00452 xAxisTitle += "/recceipt_time";
00453
00454 if (yAxisConfig->getFieldType() == CurveAxisConfig::MessageData)
00455 yAxisTitle += "/"+yAxisConfig->getField();
00456 else
00457 yAxisTitle += "/recceipt_time";
00458
00459 formattedAxisTitles.append(xAxisTitle);
00460 formattedAxisTitles.append(yAxisTitle);
00461 }
00462 }
00463
00464 void PlotWidget::saveToImageFile(const QString& fileName) {
00465 QPixmap pixmap(1280, 1024);
00466
00467 pixmap.fill(Qt::transparent);
00468 renderToPixmap(pixmap);
00469
00470 pixmap.save(fileName, "PNG");
00471 }
00472
00473 void PlotWidget::saveToTextFile(const QString& fileName) {
00474 QFile file(fileName);
00475
00476 if (file.open(QIODevice::WriteOnly)) {
00477 QStringList formattedAxisTitles;
00478 QList<QStringList> formattedData;
00479
00480 writeFormattedCurveAxisTitles(formattedAxisTitles);
00481 writeFormattedCurveData(formattedData);
00482
00483 QTextStream stream(&file);
00484
00485 stream << "# " << formattedAxisTitles.join(", ") << "\n";
00486
00487 size_t row = 0;
00488
00489 while (true) {
00490 QStringList dataLineParts;
00491 bool finished = true;
00492
00493 for (size_t column = 0; column < formattedData.count(); ++column) {
00494 if (row < formattedData[column].count()) {
00495 dataLineParts.append(formattedData[column][row]);
00496 finished &= false;
00497 }
00498 else
00499 dataLineParts.append(QString());
00500 }
00501
00502 if (!finished) {
00503 stream << dataLineParts.join(", ") << "\n";
00504 row++;
00505 }
00506 else
00507 break;
00508 }
00509 }
00510 }
00511
00512 void PlotWidget::dragEnterEvent(QDragEnterEvent* event) {
00513 if (event->mimeData()->hasFormat(CurveConfig::MimeType) &&
00514 (event->source() != legend_) && config_)
00515 event->acceptProposedAction();
00516 else
00517 event->ignore();
00518 }
00519
00520 void PlotWidget::dropEvent(QDropEvent* event) {
00521 if (event->mimeData()->hasFormat(CurveConfig::MimeType) &&
00522 (event->source() != legend_) && config_) {
00523 QByteArray data = event->mimeData()->data(CurveConfig::MimeType);
00524 QDataStream stream(&data, QIODevice::ReadOnly);
00525
00526 CurveConfig* curveConfig = config_->addCurve();
00527 stream >> *curveConfig;
00528
00529 while (config_->findCurves(curveConfig->getTitle()).count() > 1)
00530 curveConfig->setTitle("Copy of "+curveConfig->getTitle());
00531
00532 event->acceptProposedAction();
00533 }
00534 else
00535 event->ignore();
00536 }
00537
00538 bool PlotWidget::eventFilter(QObject* object, QEvent* event) {
00539 if ((object == ui_->plot->axisWidget(QwtPlot::yLeft)) &&
00540 (event->type() == QEvent::Resize)) {
00541 ui_->horizontalSpacerLeft->changeSize(
00542 ui_->plot->axisWidget(QwtPlot::yLeft)->width(), 20);
00543 layout()->update();
00544 }
00545 else if ((object == ui_->plot->axisWidget(QwtPlot::yRight)) &&
00546 (event->type() == QEvent::Resize)) {
00547 ui_->horizontalSpacerRight->changeSize(
00548 ui_->plot->axisWidget(QwtPlot::yRight)->width()-5, 20);
00549 layout()->update();
00550 }
00551
00552 return false;
00553 }
00554
00555 void PlotWidget::updateAxisTitle(PlotAxesConfig::Axis axis) {
00556 QwtPlot::Axis plotAxis = (axis == PlotAxesConfig::Y) ?
00557 QwtPlot::yLeft : QwtPlot::xBottom;
00558 CurveConfig::Axis curveAxis = (axis == PlotAxesConfig::Y) ?
00559 CurveConfig::Y : CurveConfig::X;
00560
00561 PlotAxisConfig* plotAxisConfig = config_->getAxesConfig()->
00562 getAxisConfig(axis);
00563
00564 if (plotAxisConfig->isTitleVisible()) {
00565 if (plotAxisConfig->getTitleType() == PlotAxisConfig::AutoTitle) {
00566 QStringList titleParts;
00567
00568 for (size_t index = 0; index < config_->getNumCurves(); ++index) {
00569 CurveAxisConfig* curveAxisConfig = config_->getCurveConfig(index)->
00570 getAxisConfig(curveAxis);
00571
00572 QString titlePart = curveAxisConfig->getTopic();
00573 if (curveAxisConfig->getFieldType() == CurveAxisConfig::MessageData)
00574 titlePart += "/"+curveAxisConfig->getField();
00575 else
00576 titlePart += "/receipt_time";
00577
00578 if (!titleParts.contains(titlePart))
00579 titleParts.append(titlePart);
00580 }
00581
00582 ui_->plot->setAxisTitle(plotAxis, QwtText(titleParts.join(", ")));
00583 }
00584 else
00585 ui_->plot->setAxisTitle(plotAxis, QwtText(plotAxisConfig->
00586 getCustomTitle()));
00587 }
00588 else
00589 ui_->plot->setAxisTitle(plotAxis, QwtText());
00590 }
00591
00592
00593
00594
00595
00596 void PlotWidget::timerTimeout() {
00597 if (replot_)
00598 forceReplot();
00599 }
00600
00601 void PlotWidget::configTitleChanged(const QString& title) {
00602 ui_->lineEditTitle->setText(config_->getTitle());
00603 }
00604
00605 void PlotWidget::configCurveAdded(size_t index) {
00606 PlotCurve* curve = new PlotCurve(this);
00607
00608 curve->attach(ui_->plot);
00609 curve->setConfig(config_->getCurveConfig(index));
00610 curve->setBroker(broker_);
00611
00612 connect(curve, SIGNAL(replotRequested()), this,
00613 SLOT(curveReplotRequested()));
00614
00615 curves_.insert(index, curve);
00616
00617 configXAxisConfigChanged();
00618 configYAxisConfigChanged();
00619
00620 forceReplot();
00621 }
00622
00623 void PlotWidget::configCurveRemoved(size_t index) {
00624 curves_[index]->detach();
00625
00626 delete curves_[index];
00627
00628 curves_.remove(index);
00629
00630 configXAxisConfigChanged();
00631 configYAxisConfigChanged();
00632
00633 forceReplot();
00634 }
00635
00636 void PlotWidget::configCurvesCleared() {
00637 for (size_t index = 0; index < curves_.count(); ++index) {
00638 curves_[index]->detach();
00639
00640 delete curves_[index];
00641 }
00642
00643 curves_.clear();
00644
00645 configXAxisConfigChanged();
00646 configYAxisConfigChanged();
00647
00648 forceReplot();
00649 }
00650
00651 void PlotWidget::configCurveConfigChanged(size_t index) {
00652 configXAxisConfigChanged();
00653 configYAxisConfigChanged();
00654 }
00655
00656 void PlotWidget::configXAxisConfigChanged() {
00657 updateAxisTitle(PlotAxesConfig::X);
00658 }
00659
00660 void PlotWidget::configYAxisConfigChanged() {
00661 updateAxisTitle(PlotAxesConfig::Y);
00662 }
00663
00664 void PlotWidget::configLegendConfigChanged() {
00665 if (!legend_ && config_->getLegendConfig()->isVisible()) {
00666 legend_ = new PlotLegend(this);
00667 ui_->plot->insertLegend(legend_, QwtPlot::TopLegend);
00668 }
00669 else if (legend_ && !config_->getLegendConfig()->isVisible()) {
00670 ui_->plot->insertLegend(0);
00671 legend_ = 0;
00672 }
00673 }
00674
00675 void PlotWidget::configPlotRateChanged(double rate) {
00676 timer_->setInterval(1e3/rate);
00677 }
00678
00679 void PlotWidget::curveReplotRequested() {
00680 rescale_ = true;
00681
00682 requestReplot();
00683 }
00684
00685 void PlotWidget::lineEditTitleTextChanged(const QString& text) {
00686 QFontMetrics fontMetrics(ui_->lineEditTitle->font());
00687
00688 ui_->lineEditTitle->setMinimumWidth(
00689 std::max(100, fontMetrics.width(text)+10));
00690 }
00691
00692 void PlotWidget::lineEditTitleEditingFinished() {
00693 if (config_)
00694 config_->setTitle(ui_->lineEditTitle->text());
00695 }
00696
00697 void PlotWidget::pushButtonRunPauseClicked() {
00698 if (paused_)
00699 run();
00700 else
00701 pause();
00702 }
00703
00704 void PlotWidget::pushButtonClearClicked() {
00705 clear();
00706 }
00707
00708 void PlotWidget::pushButtonSetupClicked() {
00709 if (config_) {
00710 PlotConfigDialog dialog(this);
00711
00712 dialog.setWindowTitle(config_->getTitle().isEmpty() ?
00713 "Configure Plot" :
00714 "Configure \""+config_->getTitle()+"\"");
00715 dialog.getWidget()->setConfig(*config_);
00716
00717 if (dialog.exec() == QDialog::Accepted)
00718 *config_ = dialog.getWidget()->getConfig();
00719 }
00720 }
00721
00722 void PlotWidget::pushButtonImportExportClicked() {
00723 menuImportExport_->popup(QCursor::pos());
00724 }
00725
00726 void PlotWidget::pushButtonStateClicked() {
00727 if (state_ == Maximized)
00728 setState(Normal);
00729 else
00730 setState(Maximized);
00731 }
00732
00733 void PlotWidget::menuExportImageFileTriggered() {
00734 QFileDialog dialog(this, "Save Image File", QDir::homePath(),
00735 "Portable Network Graphics (*.png)");
00736
00737 dialog.setAcceptMode(QFileDialog::AcceptSave);
00738 dialog.setFileMode(QFileDialog::AnyFile);
00739 dialog.selectFile("rqt_multiplot.png");
00740
00741 if (dialog.exec() == QDialog::Accepted)
00742 saveToImageFile(dialog.selectedFiles().first());
00743 }
00744
00745 void PlotWidget::menuExportTextFileTriggered() {
00746 QFileDialog dialog(this, "Save Text File", QDir::homePath(),
00747 "Text file (*.txt)");
00748
00749 dialog.setAcceptMode(QFileDialog::AcceptSave);
00750 dialog.setFileMode(QFileDialog::AnyFile);
00751 dialog.selectFile("rqt_multiplot.txt");
00752
00753 if (dialog.exec() == QDialog::Accepted)
00754 saveToTextFile(dialog.selectedFiles().first());
00755 }
00756
00757 void PlotWidget::plotXBottomScaleDivChanged() {
00758 #if QWT_VERSION >= 0x060100
00759 const QwtScaleDiv& scale = ui_->plot->axisScaleDiv(QwtPlot::xBottom);
00760 #else
00761 const QwtScaleDiv& scale = *ui_->plot->axisScaleDiv(QwtPlot::xBottom);
00762 #endif
00763
00764 ui_->plot->setAxisScaleDiv(QwtPlot::xTop, scale);
00765
00766 currentBounds_.getMinimum().setX(scale.lowerBound());
00767 currentBounds_.getMaximum().setX(scale.upperBound());
00768
00769 emit currentScaleChanged(currentBounds_);
00770 }
00771
00772 void PlotWidget::plotYLeftScaleDivChanged() {
00773 #if QWT_VERSION >= 0x060100
00774 const QwtScaleDiv& scale = ui_->plot->axisScaleDiv(QwtPlot::yLeft);
00775 #else
00776 const QwtScaleDiv& scale = *ui_->plot->axisScaleDiv(QwtPlot::yLeft);
00777 #endif
00778
00779 ui_->plot->setAxisScaleDiv(QwtPlot::yRight, scale);
00780
00781 currentBounds_.getMinimum().setY(scale.lowerBound());
00782 currentBounds_.getMaximum().setY(scale.upperBound());
00783
00784 emit currentScaleChanged(currentBounds_);
00785 }
00786
00787 }