X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/c4f51073fc1a2cb74363bb9b0d9f616c7dd742bb..f66d28afcc699588612e40359e02d75eb408739c:/client/proxguiqt.cpp?ds=sidebyside diff --git a/client/proxguiqt.cpp b/client/proxguiqt.cpp index c1fc7e12..cda90cc0 100644 --- a/client/proxguiqt.cpp +++ b/client/proxguiqt.cpp @@ -7,7 +7,9 @@ //----------------------------------------------------------------------------- // GUI (QT) //----------------------------------------------------------------------------- +#include "proxguiqt.h" +#include #include #include #include @@ -22,14 +24,19 @@ #include #include #include -#include "proxguiqt.h" #include "proxgui.h" #include -//#include +extern "C" { +#include "util_darwin.h" +} +//#include -int startMax; -int PageWidth; +bool g_useOverlays = false; +int g_absVMax = 0; +int startMax; // Maximum offset in the graph (right side of graph) +int PageWidth; // How many samples are currently visible on this 'page' / graph +int unlockStart = 0; void ProxGuiQT::ShowGraphWindow(void) { @@ -46,13 +53,23 @@ void ProxGuiQT::HideGraphWindow(void) emit HideGraphWindowSignal(); } +void ProxGuiQT::Exit(void) +{ + emit ExitSignal(); +} + void ProxGuiQT::_ShowGraphWindow(void) { if(!plotapp) return; if (!plotwidget) + { +#if defined(__MACH__) && defined(__APPLE__) + makeFocusable(); +#endif plotwidget = new ProxWidget(); + } plotwidget->show(); } @@ -73,6 +90,21 @@ void ProxGuiQT::_HideGraphWindow(void) plotwidget->hide(); } +void ProxGuiQT::_Exit(void) { + delete this; +} + +void ProxGuiQT::_StartProxmarkThread(void) { + if (!proxmarkThread) + return; + + // if thread finished delete self and delete application + QObject::connect(proxmarkThread, SIGNAL(finished()), proxmarkThread, SLOT(deleteLater())); + QObject::connect(proxmarkThread, SIGNAL(finished()), this, SLOT(_Exit())); + // start proxmark thread + proxmarkThread->start(); +} + void ProxGuiQT::MainLoop() { plotapp = new QApplication(argc, argv); @@ -80,26 +112,34 @@ void ProxGuiQT::MainLoop() connect(this, SIGNAL(ShowGraphWindowSignal()), this, SLOT(_ShowGraphWindow())); connect(this, SIGNAL(RepaintGraphWindowSignal()), this, SLOT(_RepaintGraphWindow())); connect(this, SIGNAL(HideGraphWindowSignal()), this, SLOT(_HideGraphWindow())); + connect(this, SIGNAL(ExitSignal()), this, SLOT(_Exit())); + + //start proxmark thread after starting event loop + QTimer::singleShot(200, this, SLOT(_StartProxmarkThread())); + +#if defined(__MACH__) && defined(__APPLE__) + //Prevent the terminal from loosing focus during launch by making the client unfocusable + makeUnfocusable(); +#endif plotapp->exec(); } -ProxGuiQT::ProxGuiQT(int argc, char **argv) : plotapp(NULL), plotwidget(NULL), - argc(argc), argv(argv) +ProxGuiQT::ProxGuiQT(int argc, char **argv, WorkerThread *wthread) : plotapp(NULL), plotwidget(NULL), + argc(argc), argv(argv), proxmarkThread(wthread) { } ProxGuiQT::~ProxGuiQT(void) { - if (plotwidget) { - //plotwidget->close(); - delete plotwidget; - plotwidget = NULL; - } - + //if (plotwidget) { + //plotwidget->destroy(true,true); + // delete plotwidget; + // plotwidget = NULL; + //} if (plotapp) { plotapp->quit(); - delete plotapp; + // delete plotapp; plotapp = NULL; } } @@ -107,22 +147,22 @@ ProxGuiQT::~ProxGuiQT(void) //-------------------- void ProxWidget::applyOperation() { - printf("ApplyOperation()"); - save_restoreGB(1); + //printf("ApplyOperation()"); + save_restoreGB(GRAPH_SAVE); memcpy(GraphBuffer, s_Buff, sizeof(int) * GraphTraceLen); RepaintGraphWindow(); - } void ProxWidget::stickOperation() { - save_restoreGB(0); - printf("stickOperation()"); + save_restoreGB(GRAPH_RESTORE); + //printf("stickOperation()"); } void ProxWidget::vchange_autocorr(int v) { int ans; ans = AutoCorrelate(GraphBuffer, s_Buff, GraphTraceLen, v, true, false); - printf("vchange_autocorr(w:%d): %d\n", v, ans); + if (g_debugMode) printf("vchange_autocorr(w:%d): %d\n", v, ans); + g_useOverlays = true; RepaintGraphWindow(); } void ProxWidget::vchange_askedge(int v) @@ -130,39 +170,44 @@ void ProxWidget::vchange_askedge(int v) int ans; //extern int AskEdgeDetect(const int *in, int *out, int len, int threshold); ans = AskEdgeDetect(GraphBuffer, s_Buff, GraphTraceLen, v); - printf("vchange_askedge(w:%d)\n", v); + if (g_debugMode) printf("vchange_askedge(w:%d)%d\n", v, ans); + g_useOverlays = true; RepaintGraphWindow(); } void ProxWidget::vchange_dthr_up(int v) { int down = opsController->horizontalSlider_dirthr_down->value(); directionalThreshold(GraphBuffer, s_Buff, GraphTraceLen, v, down); - printf("vchange_dthr_up(%d)", v); + //printf("vchange_dthr_up(%d)", v); + g_useOverlays = true; RepaintGraphWindow(); - } void ProxWidget::vchange_dthr_down(int v) { - printf("vchange_dthr_down(%d)", v); + //printf("vchange_dthr_down(%d)", v); int up = opsController->horizontalSlider_dirthr_up->value(); directionalThreshold(GraphBuffer,s_Buff, GraphTraceLen, v, up); + g_useOverlays = true; RepaintGraphWindow(); - } ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) { this->master = master; resize(800,500); - /** Setup the controller widget **/ - - QWidget* controlWidget = new QWidget(); + // Setup the controller widget + controlWidget = new QWidget(); opsController = new Ui::Form(); opsController->setupUi(controlWidget); //Due to quirks in QT Designer, we need to fiddle a bit opsController->horizontalSlider_dirthr_down->setMinimum(-128); opsController->horizontalSlider_dirthr_down->setMaximum(0); opsController->horizontalSlider_dirthr_down->setValue(-20); + opsController->horizontalSlider_dirthr_up->setMinimum(-40); + opsController->horizontalSlider_dirthr_up->setMaximum(128); + opsController->horizontalSlider_dirthr_up->setValue(20); + opsController->horizontalSlider_askedge->setValue(25); + opsController->horizontalSlider_window->setValue(4000); QObject::connect(opsController->pushButton_apply, SIGNAL(clicked()), this, SLOT(applyOperation())); @@ -172,25 +217,54 @@ ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) QObject::connect(opsController->horizontalSlider_dirthr_down, SIGNAL(valueChanged(int)), this, SLOT(vchange_dthr_down(int))); QObject::connect(opsController->horizontalSlider_askedge, SIGNAL(valueChanged(int)), this, SLOT(vchange_askedge(int))); - controlWidget->show(); - // Set up the plot widget, which does the actual plotting - plot = new Plot(this); - /* - QSlider* slider = new QSlider(Qt::Horizontal); - slider->setFocusPolicy(Qt::StrongFocus); - slider->setTickPosition(QSlider::TicksBothSides); - slider->setTickInterval(10); - slider->setSingleStep(1); - */ QVBoxLayout *layout = new QVBoxLayout; - //layout->addWidget(slider); layout->addWidget(plot); setLayout(layout); - printf("Proxwidget Constructor just set layout\r\n"); + show(); // places the window on the screen. + + // Move controller widget below plot + controlWidget->move(x(),y()+frameSize().height()); + controlWidget->resize(size().width(), controlWidget->size().height()); + controlWidget->show(); } +// not 100% sure what i need in this block +// feel free to fix - marshmellow... +ProxWidget::~ProxWidget(void) +{ + if (controlWidget) { + controlWidget->close(); + delete controlWidget; + controlWidget = NULL; + } + + if (opsController) { + delete opsController; + opsController = NULL; + } + + if (plot) { + plot->close(); + delete plot; + plot = NULL; + } +} +void ProxWidget::closeEvent(QCloseEvent *event) +{ + event->ignore(); + this->hide(); + g_useOverlays = false; +} +void ProxWidget::hideEvent(QHideEvent *event) { + controlWidget->hide(); + plot->hide(); +} +void ProxWidget::showEvent(QShowEvent *event) { + controlWidget->show(); + plot->show(); +} //----------- Plotting @@ -202,6 +276,7 @@ int Plot::xCoordOf(int i, QRect r ) int Plot::yCoordOf(int v, QRect r, int maxVal) { int z = (r.bottom() - r.top())/2; + if ( maxVal == 0 ) maxVal++; return -(z * v) / maxVal + z; } @@ -225,6 +300,32 @@ QColor Plot::getColor(int graphNum) } } +void Plot::setMaxAndStart(int *buffer, int len, QRect plotRect) +{ + if (len == 0) return; + startMax = (len - (int)((plotRect.right() - plotRect.left() - 40) / GraphPixelsPerPoint)); + if(startMax < 0) { + startMax = 0; + } + if(GraphStart > startMax) { + GraphStart = startMax; + } + if (GraphStart > len) return; + int vMin = INT_MAX, vMax = INT_MIN, v = 0; + int sample_index = GraphStart ; + for( ; sample_index < len && xCoordOf(sample_index,plotRect) < plotRect.right() ; sample_index++) { + + v = buffer[sample_index]; + if(v < vMin) vMin = v; + if(v > vMax) vMax = v; + } + + g_absVMax = 0; + if(fabs( (double) vMin) > g_absVMax) g_absVMax = (int)fabs( (double) vMin); + if(fabs( (double) vMax) > g_absVMax) g_absVMax = (int)fabs( (double) vMax); + g_absVMax = (int)(g_absVMax*1.25 + 1); +} + void Plot::PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotationRect, QPainter *painter, int graphNum, int plotOffset) { if (len == 0 || PlotGridX <= 0) return; @@ -241,7 +342,7 @@ void Plot::PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotati // round down if (DemodStart-plotOffset > 0) BitStart = (int)(((DemodStart-plotOffset)+(PlotGridX-1))/PlotGridX)-1; first_delta_x += BitStart * PlotGridX; - if (BitStart > len) return; + if (BitStart > (int)len) return; int delta_x = 0; int v = 0; //printf("first_delta_x %i, grid_delta_x %i, DemodStart %i, BitStart %i\n",first_delta_x,grid_delta_x,DemodStart, BitStart); @@ -254,8 +355,8 @@ void Plot::PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotati penPath.moveTo(x, y); delta_x = 0; int clk = first_delta_x; - for(int i = BitStart; i < len && xCoordOf(delta_x+DemodStart, plotRect) < plotRect.right(); i++) { - for (int ii = 0; ii < (clk) && i < len && xCoordOf(DemodStart+delta_x+ii, plotRect) < plotRect.right() ; ii++ ) { + for(int i = BitStart; i < (int)len && xCoordOf(delta_x+DemodStart, plotRect) < plotRect.right(); i++) { + for (int ii = 0; ii < (clk) && i < (int)len && xCoordOf(DemodStart+delta_x+ii, plotRect) < plotRect.right() ; ii++ ) { x = xCoordOf(DemodStart+delta_x+ii, plotRect); v = buffer[i]*200-100; @@ -286,47 +387,16 @@ void Plot::PlotGraph(int *buffer, int len, QRect plotRect, QRect annotationRect, if (len == 0) return; //clock_t begin = clock(); QPainterPath penPath; - - startMax = (len - (int)((plotRect.right() - plotRect.left() - 40) / GraphPixelsPerPoint)); - if(startMax < 0) { - startMax = 0; - } - if(GraphStart > startMax) { - GraphStart = startMax; - } - if (GraphStart > len) return; - int vMin = INT_MAX, vMax = INT_MIN, vMean = 0, v = 0, absVMax = 0; - int sample_index = GraphStart ; - for( ; sample_index < len && xCoordOf(sample_index,plotRect) < plotRect.right() ; sample_index++) { - - v = buffer[sample_index]; - if(v < vMin) vMin = v; - if(v > vMax) vMax = v; - vMean += v; - } - - vMean /= (sample_index - GraphStart); - - if(fabs( (double) vMin) > absVMax) absVMax = (int)fabs( (double) vMin); - if(fabs( (double) vMax) > absVMax) absVMax = (int)fabs( (double) vMax); - absVMax = (int)(absVMax*1.25 + 1); - // number of points that will be plotted - int span = (int)((plotRect.right() - plotRect.left()) / GraphPixelsPerPoint); - // one label every 100 pixels, let us say - int labels = (plotRect.right() - plotRect.left() - 40) / 100; - if(labels <= 0) labels = 1; - int pointsPerLabel = span / labels; - if(pointsPerLabel <= 0) pointsPerLabel = 1; - + int vMin = INT_MAX, vMax = INT_MIN, vMean = 0, v = 0, i = 0; int x = xCoordOf(GraphStart, plotRect); - int y = yCoordOf(buffer[GraphStart],plotRect,absVMax); + int y = yCoordOf(buffer[GraphStart],plotRect,g_absVMax); penPath.moveTo(x, y); - for(int i = GraphStart; i < len && xCoordOf(i, plotRect) < plotRect.right(); i++) { + for(i = GraphStart; i < len && xCoordOf(i, plotRect) < plotRect.right(); i++) { x = xCoordOf(i, plotRect); v = buffer[i]; - y = yCoordOf( v, plotRect, absVMax);//(y * (r.top() - r.bottom()) / (2*absYMax)) + zeroHeight; + y = yCoordOf( v, plotRect, g_absVMax); penPath.lineTo(x, y); @@ -334,7 +404,12 @@ void Plot::PlotGraph(int *buffer, int len, QRect plotRect, QRect annotationRect, QRect f(QPoint(x - 3, y - 3),QPoint(x + 3, y + 3)); painter->fillRect(f, QColor(100, 255, 100)); } + //catch stats + if(v < vMin) vMin = v; + if(v > vMax) vMax = v; + vMean += v; } + vMean /= (i - GraphStart); painter->setPen(getColor(graphNum)); @@ -342,7 +417,7 @@ void Plot::PlotGraph(int *buffer, int len, QRect plotRect, QRect annotationRect, int xo = 5+(graphNum*40); painter->drawLine(xo, plotRect.top(),xo, plotRect.bottom()); - int vMarkers = (absVMax - (absVMax % 10)) / 5; + int vMarkers = (g_absVMax - (g_absVMax % 10)) / 5; int minYDist = 40; //Minimum pixel-distance between markers char yLbl[20]; @@ -350,10 +425,10 @@ void Plot::PlotGraph(int *buffer, int len, QRect plotRect, QRect annotationRect, int n = 0; int lasty0 = 65535; - for(int v = vMarkers; yCoordOf(v,plotRect,absVMax) > plotRect.top() && n < 20; v+= vMarkers ,n++) + for(v = vMarkers; yCoordOf(v,plotRect,g_absVMax) > plotRect.top() && n < 20; v+= vMarkers ,n++) { - int y0 = yCoordOf(v,plotRect,absVMax); - int y1 = yCoordOf(-v,plotRect,absVMax); + int y0 = yCoordOf(v,plotRect,g_absVMax); + int y1 = yCoordOf(-v,plotRect,g_absVMax); if(lasty0 - y0 < minYDist) continue; @@ -372,7 +447,7 @@ void Plot::PlotGraph(int *buffer, int len, QRect plotRect, QRect annotationRect, painter->drawPath(penPath); char str[200]; sprintf(str, "max=%d min=%d mean=%d n=%d/%d CursorAVal=[%d] CursorBVal=[%d]", - vMax, vMin, vMean, sample_index, len, buffer[CursorAPos], buffer[CursorBPos]); + vMax, vMin, vMean, i, len, buffer[CursorAPos], buffer[CursorBPos]); painter->drawText(20, annotationRect.bottom() - 23 - 20 * graphNum, str); //clock_t end = clock(); @@ -382,20 +457,29 @@ void Plot::PlotGraph(int *buffer, int len, QRect plotRect, QRect annotationRect, void Plot::plotGridLines(QPainter* painter,QRect r) { - int zeroHeight = r.top() + (r.bottom() - r.top()) / 2; + // set GridOffset + if (PlotGridX <= 0) return; + int offset = GridOffset; + if (GridLocked && PlotGridX) { + offset = GridOffset + PlotGridX - (GraphStart % PlotGridX); + } else if (!GridLocked && GraphStart > 0 && PlotGridX) { + offset = PlotGridX-((GraphStart - offset) % PlotGridX) + GraphStart - unlockStart; + } + offset %= PlotGridX; + if (offset < 0) offset += PlotGridX; int i; int grid_delta_x = (int) (PlotGridX * GraphPixelsPerPoint); - int grid_delta_y = (int) (PlotGridY * GraphPixelsPerPoint); + int grid_delta_y = PlotGridY; if ((PlotGridX > 0) && ((PlotGridX * GraphPixelsPerPoint) > 1)) { - for(i = (GridOffset * GraphPixelsPerPoint); i < r.right(); i += grid_delta_x) { + for(i = (offset * GraphPixelsPerPoint); i < r.right(); i += grid_delta_x) { painter->drawLine(r.left()+i, r.top(), r.left()+i, r.bottom()); - } - } - if ((PlotGridY > 0) && ((PlotGridY * GraphPixelsPerPoint) > 1)){ - for(i = 0; i < ((r.top() + r.bottom())>>1); i += grid_delta_y) { - painter->drawLine(r.left(),zeroHeight + i,r.right(),zeroHeight + i); - painter->drawLine(r.left(),zeroHeight - i,r.right(),zeroHeight - i); + } + } + if (PlotGridY > 0) { + for(i = 0; yCoordOf(i,r,g_absVMax) > r.top(); i += grid_delta_y) { + painter->drawLine( r.left(), yCoordOf(i,r,g_absVMax), r.right(), yCoordOf(i,r,g_absVMax) ); + painter->drawLine( r.left(), yCoordOf(i*-1,r,g_absVMax), r.right(), yCoordOf(i*-1,r,g_absVMax) ); } } } @@ -405,9 +489,8 @@ void Plot::plotGridLines(QPainter* painter,QRect r) void Plot::paintEvent(QPaintEvent *event) { + QPainter painter(this); - //QPainterPath penPath, whitePath, greyPath, lightgreyPath, cursorAPath, cursorBPath, cursorCPath, cursorDPath; - //QRect r; QBrush brush(QColor(100, 255, 100)); QPen pen(QColor(100, 255, 100)); @@ -426,14 +509,18 @@ void Plot::paintEvent(QPaintEvent *event) if(CursorDPos > GraphTraceLen) CursorDPos= 0; - QRect plotRect(WIDTH_AXES, 0, width()-WIDTH_AXES, height()-HEIGHT_INFO); - QRect infoRect(0, height()-HEIGHT_INFO, width(), HEIGHT_INFO); + QRect plotRect(WIDTH_AXES, 0, width() - WIDTH_AXES, height() - HEIGHT_INFO); + QRect infoRect(0, height() - HEIGHT_INFO, width(), HEIGHT_INFO); + PageWidth = plotRect.width() / GraphPixelsPerPoint; //Grey background painter.fillRect(rect(), QColor(60, 60, 60)); //Black foreground painter.fillRect(plotRect, QColor(0, 0, 0)); + //init graph variables + setMaxAndStart(GraphBuffer,GraphTraceLen,plotRect); + // center line int zeroHeight = plotRect.top() + (plotRect.bottom() - plotRect.top()) / 2; painter.setPen(QColor(100, 100, 100)); @@ -442,11 +529,15 @@ void Plot::paintEvent(QPaintEvent *event) plotGridLines(&painter, plotRect); //Start painting graph - if (showDemod && DemodBufferLen > 8) { + PlotGraph(GraphBuffer, GraphTraceLen,plotRect,infoRect,&painter,0); + if (showDemod && DemodBufferLen > 8) { PlotDemod(DemodBuffer, DemodBufferLen,plotRect,infoRect,&painter,2,g_DemodStartIdx); } - PlotGraph(s_Buff, GraphTraceLen,plotRect,infoRect,&painter,1); - PlotGraph(GraphBuffer, GraphTraceLen,plotRect,infoRect,&painter,0); + if (g_useOverlays) { + //init graph variables + setMaxAndStart(s_Buff,GraphTraceLen,plotRect); + PlotGraph(s_Buff, GraphTraceLen,plotRect,infoRect,&painter,1); + } // End graph drawing //Draw the cursors @@ -474,7 +565,7 @@ void Plot::paintEvent(QPaintEvent *event) //Draw annotations char str[200]; sprintf(str, "@%d dt=%d [%2.2f] zoom=%2.2f CursorAPos=%d CursorBPos=%d GridX=%d GridY=%d (%s) GridXoffset=%d", - GraphStart, CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor, + GraphStart, CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor, GraphPixelsPerPoint,CursorAPos,CursorBPos,PlotGridXdefault,PlotGridYdefault,GridLocked?"Locked":"Unlocked",GridOffset); painter.setPen(QColor(255, 255, 255)); painter.drawText(20, infoRect.bottom() - 3, str); @@ -497,12 +588,15 @@ Plot::Plot(QWidget *parent) : QWidget(parent), GraphStart(0), GraphPixelsPerPoin CursorBPos = 0; setWindowTitle(tr("Sliders")); + + master = parent; } void Plot::closeEvent(QCloseEvent *event) { event->ignore(); this->hide(); + g_useOverlays = false; } void Plot::mouseMoveEvent(QMouseEvent *event) @@ -523,17 +617,14 @@ void Plot::mouseMoveEvent(QMouseEvent *event) void Plot::keyPressEvent(QKeyEvent *event) { - int offset; - int gridchanged; - - gridchanged= 0; + int offset; // Left/right movement offset (in sample size) if(event->modifiers() & Qt::ShiftModifier) { if (PlotGridX) offset= PageWidth - (PageWidth % PlotGridX); else offset= PageWidth; - } else + } else if(event->modifiers() & Qt::ControlModifier) offset= 1; else @@ -554,53 +645,18 @@ void Plot::keyPressEvent(QKeyEvent *event) case Qt::Key_Right: if(GraphPixelsPerPoint < 20) { - if (PlotGridX && GridLocked && GraphStart < startMax){ - GridOffset -= offset; - GridOffset %= PlotGridX; - gridchanged= 1; - } GraphStart += offset; } else { - if (PlotGridX && GridLocked && GraphStart < startMax){ - GridOffset--; - GridOffset %= PlotGridX; - gridchanged= 1; - } GraphStart++; } - if(GridOffset < 0) { - GridOffset += PlotGridX; - } - if (gridchanged) - if (GraphStart > startMax) { - GridOffset += (GraphStart - startMax); - GridOffset %= PlotGridX; - } break; case Qt::Key_Left: if(GraphPixelsPerPoint < 20) { - if (PlotGridX && GridLocked && GraphStart > 0){ - GridOffset += offset; - GridOffset %= PlotGridX; - gridchanged= 1; - } GraphStart -= offset; } else { - if (PlotGridX && GridLocked && GraphStart > 0){ - GridOffset++; - GridOffset %= PlotGridX; - gridchanged= 1; - } GraphStart--; } - if (gridchanged){ - if (GraphStart < 0) - GridOffset += GraphStart; - if(GridOffset < 0) - GridOffset += PlotGridX; - GridOffset %= PlotGridX; - } break; case Qt::Key_G: @@ -610,36 +666,50 @@ void Plot::keyPressEvent(QKeyEvent *event) } else { PlotGridX= PlotGridXdefault; PlotGridY= PlotGridYdefault; - } + } break; case Qt::Key_H: puts("Plot Window Keystrokes:\n"); puts(" Key Action\n"); + puts(" UP Zoom out"); puts(" DOWN Zoom in"); puts(" G Toggle grid display"); puts(" H Show help"); puts(" L Toggle lock grid relative to samples"); + puts(" Q Hide window"); + puts(" HOME Move to the start of the graph"); + puts(" END Move to the end of the graph"); puts(" LEFT Move left"); puts(" LEFT Move left 1 sample"); puts(" LEFT Page left"); puts(" LEFT-MOUSE-CLICK Set yellow cursor"); - puts(" Q Hide window"); puts(" RIGHT Move right"); puts(" RIGHT Move right 1 sample"); puts(" RIGHT Page right"); puts(" RIGHT-MOUSE-CLICK Set purple cursor"); - puts(" UP Zoom out"); puts(""); puts("Use client window 'data help' for more plot commands\n"); break; case Qt::Key_L: - GridLocked= !GridLocked; + GridLocked = !GridLocked; + if (GridLocked) + GridOffset += (GraphStart - unlockStart); + else + unlockStart = GraphStart; break; case Qt::Key_Q: - this->hide(); + master->hide(); + break; + + case Qt::Key_Home: + GraphStart = 0; + break; + + case Qt::Key_End: + GraphStart = startMax; break; default: