00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
00060 d->arena = new Arena(cs);
00061 d->arena->zoom(defaultZoomRatio);
00062
00063
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
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
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
00101 d->statusBar = new QStatusBar;
00102 this->setStatusBar(d->statusBar);
00103 }
00104 VisWnd* VisWnd::showMainWindow(CoreSync *cs) {
00105
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
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
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
00142 int hPos1 = hSb ? hSb->value() : 0;
00143 int vPos1 = vSb ? vSb->value() : 0;
00144
00145 const int margin = 50 + d->arena->botSize();
00146
00147 d->scrollArea->ensureVisible(pos.x(), pos.y(), margin, margin);
00148
00149
00150 hSb = sArea->horizontalScrollBar();
00151 vSb = sArea->verticalScrollBar();
00152 int hPos2 = hSb ? hSb->value() : 0;
00153 int vPos2 = vSb ? vSb->value() : 0;
00154
00155
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
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
00180 e->accept();
00181 }
00182
00183
00184
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
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
00224 d->frame = new QFrame;
00225 d->layout = new QHBoxLayout;
00226 d->frame->setLayout(d->layout);
00227
00228
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
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
00245 d->zoomLabel = new QLabel(d->frame);
00246 d->layout->addWidget(d->zoomLabel);
00247
00248
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
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
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
00277 d->zoomSlider->triggerAction(QAbstractSlider::SliderPageStepAdd);
00278 }
00279 void NavigationBar::zoomOut() {
00280
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
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
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
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
00338 d->fastRefresh = new QCheckBox("fast refresh", rootFrame);
00339 d->fastRefresh->setCheckState(Qt::Checked);
00340 rootLayout->addWidget(d->fastRefresh);
00341
00342
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 }