viswnd.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Kamil Dudka <xdudka00@stud.fit.vutbr.cz>
00003  *
00004  * This file is part of rob08
00005  *
00006  * rob08 is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, either version 3 of the License, or
00009  * any later version.
00010  *
00011  * rob08 is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with rob08.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include "config.h"
00021 #include "viswnd.h"
00022 
00023 #include "arena.h"
00024 #include "robIO.h"
00025 
00026 #ifndef BUILDING_DOX
00027 #   include <assert.h>
00028 #   include <math.h>
00029 #   include <QApplication>
00030 #   include <QCheckBox>
00031 #   include <QFormLayout>
00032 #   include <QGridLayout>
00033 #   include <QLabel>
00034 #   include <QLCDNumber>
00035 #   include <QMessageBox>
00036 #   include <QScrollBar>
00037 #   include <QSlider>
00038 #   include <QTimer>
00039 #   include <QWheelEvent>
00040 #endif
00041 
00042 using std::string;
00043 using namespace StreamDecorator;
00044 
00045 static const qreal defaultZoomRatio = 4.0;
00046 
00047 // /////////////////////////////////////////////////////////////////////////////
00048 // VisWnd implementation
00049 struct VisWnd::Private {
00050     Arena               *arena;
00051     QScrollArea         *scrollArea;
00052     NavigationBar       *navigationBar;
00053     MetersBar           *metersBar;
00054     QStatusBar          *statusBar;
00055 };
00056 VisWnd::VisWnd(CoreSync *cs):
00057     d(new Private)
00058 {
00059     // craete arena
00060     d->arena = new Arena(cs);
00061     d->arena->zoom(defaultZoomRatio);
00062 
00063     // create scroll area
00064     d->scrollArea = new ScrollArea;
00065     d->scrollArea->setWidget(d->arena);
00066     d->scrollArea->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
00067     d->scrollArea->setBackgroundRole(QPalette::Midlight);
00068     this->setCentralWidget(d->scrollArea);
00069 
00070     // create navigation toolbar
00071     d->navigationBar = new NavigationBar;
00072     connect(
00073             d->navigationBar,   SIGNAL(setShrinkPathEnabled(bool)),
00074             d->arena,           SLOT(setShrinkPathEnabled(bool)));
00075     connect(
00076             d->navigationBar,   SIGNAL(setDrawSurfaceEnabled(bool)),
00077             d->arena,           SLOT(setDrawSurfaceEnabled(bool)));
00078     connect(
00079             d->navigationBar,   SIGNAL(zoomChanged(qreal)),
00080             d->arena,           SLOT(zoom(qreal)));
00081     connect(
00082             d->arena,           SIGNAL(preferredPosChanged(QPoint)),
00083             this,               SLOT(scrollToView(QPoint)));
00084     connect(
00085             d->scrollArea,      SIGNAL(zoomIn()),
00086             d->navigationBar,   SLOT(zoomIn()));
00087     connect(
00088             d->scrollArea,      SIGNAL(zoomOut()),
00089             d->navigationBar,   SLOT(zoomOut()));
00090     this->addDockWidget(Qt::TopDockWidgetArea, d->navigationBar);
00091 
00092     // create meters bar
00093     d->metersBar = new MetersBar(d->arena);
00094     d->metersBar->coreInfoChanged();
00095     connect(
00096             d->arena,           SIGNAL(coreInfoChanged()),
00097             d->metersBar,       SLOT(coreInfoChanged()));
00098     this->addDockWidget(Qt::LeftDockWidgetArea, d->metersBar);
00099 
00100     // craete status bar
00101     d->statusBar = new QStatusBar;
00102     this->setStatusBar(d->statusBar);
00103 }
00104 VisWnd* VisWnd::showMainWindow(CoreSync *cs) {
00105     // show/initialize
00106     VisWnd *wnd = new VisWnd(cs);
00107     wnd->show();
00108     wnd->d->navigationBar->setMaximumHeight(wnd->d->navigationBar->minimumHeight());
00109     wnd->d->metersBar->setMaximumWidth(wnd->d->metersBar->minimumWidth());
00110     wnd->d->navigationBar->zoom(defaultZoomRatio);
00111 
00112     // update status bar
00113     QSize envSize = wnd->d->arena->envSize();
00114     wnd->d->statusBar->showMessage(QString("Environment loaded, arena size is %1 x %2...")
00115             .arg(envSize.width())
00116             .arg(envSize.height()),
00117             8000);
00118 
00119     // return initialized instance
00120     return wnd;
00121 }
00122 VisWnd::~VisWnd() {
00123     delete d;
00124 }
00125 void VisWnd::syncThreadFinished() {
00126     if (QMessageBox::Yes == QMessageBox::warning(this, "rob08 visualizer",
00127             "Connection lost. Do you want to close visualizer?", 
00128             QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))
00129         QCoreApplication::quit();
00130     else
00131         d->statusBar->showMessage("Out of sync!!!");
00132 }
00133 void VisWnd::scrollToView(QPoint pos) {
00134     QScrollArea *sArea = d->scrollArea;
00135     QScrollBar *hSb = sArea->horizontalScrollBar();
00136     QScrollBar *vSb = sArea->verticalScrollBar();
00137     if ((hSb && hSb->isSliderDown())
00138             || (vSb && vSb->isSliderDown()))
00139         return;
00140 
00141     // save scrollbars original position
00142     int hPos1 = hSb ? hSb->value() : 0;
00143     int vPos1 = vSb ? vSb->value() : 0;
00144 
00145     const int margin = 50 + d->arena->botSize();
00146     // std::cerr << "scrollToView: x = " << pos.x() << ", y = " << pos.y() << ", margin = " << margin << std::endl;
00147     d->scrollArea->ensureVisible(pos.x(), pos.y(), margin, margin);
00148 
00149     // check scrollbars new position
00150     hSb = sArea->horizontalScrollBar();
00151     vSb = sArea->verticalScrollBar();
00152     int hPos2 = hSb ? hSb->value() : 0;
00153     int vPos2 = vSb ? vSb->value() : 0;
00154 
00155     // update statusbar
00156     QStatusBar *sb = d->statusBar;
00157     if (sb->currentMessage().isEmpty() && (hPos1 != hPos2 || vPos1 != vPos2))
00158         d->statusBar->showMessage("Scrolling to Trilobot position, hold scrollbar down to suppress this behavior...", 4000);
00159 }
00160 
00161 // /////////////////////////////////////////////////////////////////////////////
00162 // ScrollArea implementation
00163 ScrollArea::ScrollArea(QWidget *parent):
00164     QScrollArea(parent)
00165 {
00166 }
00167 ScrollArea::~ScrollArea() {
00168 }
00169 void ScrollArea::wheelEvent(QWheelEvent *e) {
00170     if (!(e->modifiers() & Qt::ControlModifier)) {
00171         QScrollArea::wheelEvent(e);
00172         return;
00173     }
00174     if (0 < e->delta())
00175         emit zoomIn();
00176     else
00177         emit zoomOut();
00178 
00179     // TODO: move scrollbars?
00180     e->accept();
00181 }
00182 
00183 // /////////////////////////////////////////////////////////////////////////////
00184 // Bar implementation
00185 Bar::Bar(QSize floatingSize):
00186     floatingSize_(floatingSize)
00187 {
00188     this->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
00189     connect(this, SIGNAL(topLevelChanged(bool)),
00190             this, SLOT(topLevelChanged(bool)));
00191 }
00192 void Bar::topLevelChanged (bool topLevel) {
00193     if (!topLevel) {
00194         this->setMinimumSize(0,0);
00195         if (this->allowedAreas() & (Qt::TopDockWidgetArea|Qt::BottomDockWidgetArea))
00196             this->setMaximumWidth(QWIDGETSIZE_MAX);
00197         if (this->allowedAreas() & (Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea))
00198             this->setMaximumHeight(QWIDGETSIZE_MAX);
00199     }
00200     this->resize(this->floatingSize_);
00201     this->updateGeometry();
00202     if (topLevel) {
00203         this->setMinimumSize(this->size());
00204         this->setMaximumSize(this->size());
00205     }
00206 }
00207 
00208 // /////////////////////////////////////////////////////////////////////////////
00209 // NavigationBar implementation
00210 struct NavigationBar::Private {
00211     QFrame              *frame;
00212     QHBoxLayout         *layout;
00213     QLabel              *titleBar;
00214     QLabel              *zoomLabel;
00215     QSlider             *zoomSlider;
00216     QCheckBox           *shrinkPath;
00217     QCheckBox           *drawSurface;
00218 };
00219 NavigationBar::NavigationBar():
00220     Bar(QSize(600, 0)),
00221     d(new Private)
00222 {
00223     // initialize frame
00224     d->frame = new QFrame;
00225     d->layout = new QHBoxLayout;
00226     d->frame->setLayout(d->layout);
00227 
00228     // create "shrink path" checkbox
00229     d->shrinkPath = new QCheckBox("shrink path", d->frame);
00230     d->layout->addWidget(d->shrinkPath);
00231     connect(
00232             d->shrinkPath,  SIGNAL(stateChanged(int)),
00233             this,           SLOT(shrinkPathChanged(int)));
00234     d->layout->addSpacing(32);
00235 
00236     // create "draw surface" checkbox
00237     d->drawSurface = new QCheckBox("draw surface", d->frame);
00238     d->layout->addWidget(d->drawSurface);
00239     connect(
00240             d->drawSurface, SIGNAL(stateChanged(int)),
00241             this,           SLOT(drawSurfaceChanged(int)));
00242     d->layout->addSpacing(32);
00243 
00244     // create label
00245     d->zoomLabel = new QLabel(d->frame);
00246     d->layout->addWidget(d->zoomLabel);
00247 
00248     // create slider
00249     d->zoomSlider = new QSlider(Qt::Horizontal, d->frame);
00250     d->zoomSlider->setMinimum(10);
00251     d->zoomSlider->setMaximum(320);
00252     d->layout->addWidget(d->zoomSlider);
00253     connect(
00254             d->zoomSlider,  SIGNAL(valueChanged(int)),
00255             this,           SLOT(zoomChanged(int)));
00256 
00257     // initialize self
00258     this->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea | Qt::NoDockWidgetArea);
00259     this->setWidget(d->frame);
00260     d->shrinkPath->setCheckState(Qt::Checked);
00261 }
00262 NavigationBar::~NavigationBar() {
00263     delete d;
00264 }
00265 void NavigationBar::zoom(qreal ratio) {
00266     QSlider *slider = d->zoomSlider;
00267 
00268     // convert rario to slider position
00269     int pos = static_cast<int>(ratio*10);
00270     assert(slider->minimum() < pos);
00271     assert(pos < slider->maximum());
00272 
00273     slider->setValue(pos);
00274 }
00275 void NavigationBar::zoomIn() {
00276     //d->zoomSlider->triggerAction(QAbstractSlider::SliderSingleStepAdd);
00277     d->zoomSlider->triggerAction(QAbstractSlider::SliderPageStepAdd);
00278 }
00279 void NavigationBar::zoomOut() {
00280     //d->zoomSlider->triggerAction(QAbstractSlider::SliderSingleStepSub);
00281     d->zoomSlider->triggerAction(QAbstractSlider::SliderPageStepSub);
00282 }
00283 void NavigationBar::shrinkPathChanged(int state) {
00284     emit setShrinkPathEnabled(state == Qt::Checked);
00285 }
00286 void NavigationBar::drawSurfaceChanged(int state) {
00287     emit setDrawSurfaceEnabled(state == Qt::Checked);
00288 }
00289 void NavigationBar::zoomChanged(int pos) {
00290     qreal ratio = static_cast<double>(pos)/10;
00291 
00292     // update label
00293     QString label("zoom ratio: ");
00294     label += QString::number(ratio, 'f', 1);
00295     label += "x";
00296     d->zoomLabel->setText(label);
00297 
00298     d->zoomSlider->setSingleStep(pos/10);
00299     d->zoomSlider->setPageStep(pos/10);
00300     emit zoomChanged(ratio);
00301 }
00302 
00303 // /////////////////////////////////////////////////////////////////////////////
00304 // MetersBar implementation
00305 struct MetersBar::Private {
00306     ICoreInfoSource *ciSource;
00307 
00308     QFrame          *frame;
00309     QFormLayout     *layout;
00310     QCheckBox       *fastRefresh;
00311 
00312     QLCDNumber      *xLcd;
00313     QLCDNumber      *yLcd;
00314     QLCDNumber      *alphaLcd;
00315     QLCDNumber      *distanceLcd;
00316     QLCDNumber      *speedLcd;
00317     QLCDNumber      *radiusLcd;
00318 
00319     QTimer          timer;
00320 
00321     void createLcd(QLCDNumber *&, QString label);
00322     void display(QLCDNumber *, qreal value);
00323 };
00324 MetersBar::MetersBar(ICoreInfoSource *ciSource):
00325     Bar(QSize()),
00326     d(new Private)
00327 {
00328     d->ciSource = ciSource;
00329 
00330     // create root frame
00331     QBoxLayout *rootLayout = new QVBoxLayout;
00332     QFrame *rootFrame = new QFrame;
00333     rootFrame->setLayout(rootLayout);
00334     this->setWidget(rootFrame);
00335     this->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::NoDockWidgetArea);
00336 
00337     // create controls
00338     d->fastRefresh = new QCheckBox("fast refresh", rootFrame);
00339     d->fastRefresh->setCheckState(Qt::Checked);
00340     rootLayout->addWidget(d->fastRefresh);
00341 
00342     // create frame for meters
00343     d->frame = new QFrame(rootFrame);
00344     d->layout = new QFormLayout;
00345     rootLayout->addWidget(d->frame);
00346 
00347     d->createLcd(d->xLcd, "x");
00348     d->createLcd(d->yLcd, "y");
00349     d->createLcd(d->alphaLcd, "angle");
00350     d->createLcd(d->distanceLcd, "distance");
00351     d->createLcd(d->speedLcd, "speed");
00352     d->createLcd(d->radiusLcd, "radius");
00353 
00354     d->frame->setLayout(d->layout);
00355 
00356     QTimer &timer = d->timer;
00357     connect(&timer, SIGNAL(timeout()),
00358             this,   SLOT(refresh()));
00359     timer.start(250);
00360 }
00361 MetersBar::~MetersBar() {
00362     delete d;
00363 }
00364 void MetersBar::coreInfoChanged() {
00365     if (Qt::Checked == d->fastRefresh->checkState())
00366         refresh();
00367 }
00368 void MetersBar::refresh() {
00369     const CoreInfo &info = d->ciSource->coreInfo();
00370 
00371     d->display(d->xLcd, info.x);
00372     d->display(d->yLcd, info.y);
00373     d->display(d->alphaLcd, info.angle);
00374     d->display(d->distanceLcd, info.distance);
00375     d->display(d->speedLcd, info.speed);
00376     d->display(d->radiusLcd,
00377             fabs(info.speed) < 0.1
00378             ? 0.0 : info.radius);
00379 }
00380 void MetersBar::Private::createLcd(QLCDNumber *&lcd, QString text) {
00381     lcd = new QLCDNumber(6, frame);
00382     lcd->setAutoFillBackground(true);
00383     lcd->setPalette(QPalette(Qt::black, QPalette().window().color()));
00384     layout->addRow(new QLabel(text, frame), lcd);
00385 }
00386 void MetersBar::Private::display(QLCDNumber *lcd, qreal value) {
00387     lcd->display(QString::number(value, 'f', 1));
00388 }

Generated on Fri Jul 10 22:42:01 2009 for rob08 by  doxygen 1.5.4