Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/diagrams/timingdiagram.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                              timingdiagram.cpp
00003                             -------------------
00004     begin                : Sat Oct 22 2005
00005     copyright            : (C) 2005 by Michael Margraf
00006     email                : michael.margraf@alumni.tu-berlin.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00023 #include "timingdiagram.h"
00024 #include "main.h"
00025 #include "misc.h"
00026 
00027 #include <cmath>
00028 #include <QPolygon>
00029 #include <QPainter>
00030 
00031 
00032 TimingDiagram::TimingDiagram(int _cx, int _cy) : TabDiagram(_cx, _cy)
00033 {
00034   x1 = 0;    // no extension to select area
00035   y1 = 0;
00036   x2 = x3 = 300;  // initial size of diagram
00037   y2 = 200;
00038   Name = "Time";
00039   xAxis.limit_min = 0.0;  // scroll bar position (needs to be saved in file)
00040 
00041   calcDiagram();
00042 }
00043 
00044 TimingDiagram::~TimingDiagram()
00045 {
00046 }
00047 
00048 // ------------------------------------------------------------
00049 void TimingDiagram::paint(ViewPainter *p)
00050 {
00051   // paint all lines
00052   foreach(Line *pl, Lines) {
00053     p->Painter->setPen(pl->style);
00054     p->drawLine(cx+pl->x1, cy-pl->y1, cx+pl->x2, cy-pl->y2);
00055   }
00056 
00057   p->Painter->setPen(Qt::black);
00058   // write whole text
00059   foreach(Text *pt, Texts)
00060     p->drawText(pt->s, cx+pt->x, cy-pt->y);
00061 
00062 
00063   if(y1 > 0) {  // paint scroll bar ?
00064     int   x, y, dx, dy;
00065     QPolygon Points;
00066     // draw scroll bar
00067     p->fillRect(cx+yAxis.numGraphs, cy+2, zAxis.numGraphs, 14, QColor(192, 192, 192));
00068 
00069     int bx = cx+yAxis.numGraphs+zAxis.numGraphs;
00070     // draw frame for scroll bar
00071     p->Painter->setPen(QPen(Qt::black,0));
00072     p->drawLine(cx+xAxis.numGraphs, cy, cx+xAxis.numGraphs, cy+17);
00073     p->drawLine(cx+xAxis.numGraphs+17, cy, cx+xAxis.numGraphs+17, cy+17);
00074     p->drawLine(cx+xAxis.numGraphs, cy+17, cx+x2, cy+17);
00075     p->drawLine(cx+x2, cy, cx+x2, cy+17);
00076     p->drawLine(cx+x2-17, cy, cx+x2-17, cy+17);
00077 
00078     // draw the arrows above and below the scroll bar
00079     p->Painter->setBrush(QColor(192, 192, 192));
00080     p->Painter->setPen(QColor(152, 152, 152));
00081     p->drawLine(cx+yAxis.numGraphs, cy+15, bx, cy+15);
00082     p->drawLine(bx, cy+2, bx, cy+15);
00083 
00084     p->map(cx+xAxis.numGraphs+3,  cy+3, x, y);
00085     p->map(cx+xAxis.numGraphs+14, cy+14, dx, dy);
00086     Points.setPoints(3, x, (y+dy)>>1, dx, y, dx, dy);
00087     p->Painter->drawConvexPolygon(Points);
00088     p->Painter->setPen(QColor(224, 224, 224));
00089     p->Painter->drawLine(x, (y+dy)>>1, dx, y);
00090     p->drawLine(cx+yAxis.numGraphs, cy+2, bx, cy+2);
00091     p->drawLine(cx+yAxis.numGraphs, cy+2, cx+yAxis.numGraphs, cy+15);
00092 
00093     p->Painter->setPen(QColor(152, 152, 152));
00094     dx -= x;
00095     p->map(cx+x2-3,  cy+3, x, y);
00096     Points.setPoints(3, x, (y+dy)>>1, x-dx, y, x-dx, dy);
00097     p->Painter->drawConvexPolygon(Points);
00098     p->Painter->setPen(QColor(208, 208, 208));
00099     p->Painter->drawLine(x-dx, y, x, (y+dy)>>1);
00100     p->Painter->setPen(QColor(224, 224, 224));
00101     p->Painter->drawLine(x-dx, y, x-dx, dy);
00102 
00103     p->Painter->setBrush(QBrush(Qt::NoBrush));
00104   }
00105 
00106 
00107   if(isSelected) {
00108     p->Painter->setPen(QPen(Qt::darkGray,3));
00109     p->drawRect(cx-5, cy-y2-5, x2+10, y2+10);
00110     p->Painter->setPen(QPen(Qt::darkRed,2));
00111     p->drawResizeRect(cx, cy-y2);  // markers for changing the size
00112     p->drawResizeRect(cx, cy);
00113     p->drawResizeRect(cx+x2, cy-y2);
00114     p->drawResizeRect(cx+x2, cy);
00115   }
00116 }
00117 
00118 // ------------------------------------------------------------
00119 int TimingDiagram::calcDiagram()
00120 {
00121   Lines.clear();
00122   Texts.clear();
00123 
00124   y1 = 0;  // no scroll bar
00125   x3 = x2;
00126   // get size of text using the screen-compatible metric
00127   QFontMetrics metrics(QucsSettings.font, 0);
00128   int tHeight = metrics.lineSpacing();
00129   QString Str;
00130   int colWidth=0, x=4, y, xStart = 0, z;
00131 
00132   int NumAll=0;   // how many values per row
00133   int NumLeft=0;  // how many values could not be written
00134   int invisibleCount = 0;  // how many values are invisible
00135   
00136   if(y2 < (tHeight + 8))
00137     y2 = tHeight + 8;
00138   y = y2 - tHeight - 6;
00139 
00140   // outer frame
00141   Lines.append(new Line(0, y2, x2, y2, QPen(Qt::black,0)));
00142   Lines.append(new Line(0, y2, 0, 0, QPen(Qt::black,0)));
00143   Lines.append(new Line(x2, y2, x2, 0, QPen(Qt::black,0)));
00144   Lines.append(new Line(0, 0, x2, 0, QPen(Qt::black,0)));
00145   Lines.append(new Line(0, y+2, x2, y+2, QPen(Qt::black,0)));
00146 
00147   if(xAxis.limit_min < 0.0)
00148     xAxis.limit_min = 0.0;
00149 
00150   Graph *firstGraph;
00151 
00152   QListIterator<Graph *> ig(Graphs);
00153   Graph *g = 0;
00154   if (ig.hasNext()) // point to first graph
00155     g = ig.next();
00156   
00157   if(g == 0) {  // no variables specified in diagram ?
00158     Str = QObject::tr("no variables");
00159     colWidth = checkColumnWidth(Str, metrics, colWidth, x, y2);
00160     if(colWidth >= 0)
00161       Texts.append(new Text(x, y2-2, Str)); // independent variable
00162     return 0;
00163   }
00164 
00165 
00166   double *px;
00167   // any graph with data ?
00168   while(g->isEmpty()) {
00169     if (!ig.hasNext()) break; // no more graphs, exit loop
00170     g = ig.next(); // point to next graph
00171   }
00172   
00173   if(g->isEmpty()) { // no graph with data found ?
00174     Str = QObject::tr("no data");
00175     colWidth = checkColumnWidth(Str, metrics, colWidth, x, y2);
00176     if(colWidth < 0)  return 0;
00177     Texts.append(new Text(x, y2-2, Str));
00178     return 0;
00179   }
00180   firstGraph = g;
00181 
00182 
00183   // First check the maximum bit number of all vectors.
00184   colWidth = 0;
00185   foreach(Graph *g, Graphs)
00186     if(g->cPointsY) {
00187       if(g->Var.right(2) == ".X") {
00188         z = strlen((char*)g->cPointsY);
00189         if(z > colWidth)
00190           colWidth = z;
00191       }
00192       else {
00193         z = 8;
00194         if(z > colWidth)
00195           colWidth = z;
00196       }
00197     }
00198   int TimeStepWidth = colWidth * metrics.width("X") + 8;
00199   if(TimeStepWidth < 40)
00200     TimeStepWidth = 40;
00201 
00202 
00203   colWidth = 0;
00204 if(!firstGraph->isEmpty()) {
00205   // ................................................
00206   if(firstGraph->numAxes() > 1) {
00207     Str = QObject::tr("wrong dependency");
00208     colWidth = checkColumnWidth(Str, metrics, colWidth, x, y2);
00209     if(colWidth >= 0)
00210       Texts.append(new Text(x, y2-2, Str)); // independent variable
00211     return 0;
00212   }
00213 
00214 
00215   // first, write name of independent variable
00216   DataX const *pD = firstGraph->axis(0);
00217   NumAll = pD->count;
00218   Str = pD->Var;
00219   colWidth = checkColumnWidth(Str, metrics, colWidth, x, y2);
00220   if(colWidth < 0)  return 1;
00221   Texts.append(new Text(x, y2-2, Str));
00222   
00223 
00224   y -= 5;
00225   // write all dependent variable names to get width of first column
00226   foreach(Graph *g, Graphs) {
00227     if(y < tHeight)  break;
00228     Str = g->Var;
00229     colWidth = checkColumnWidth(Str, metrics, colWidth, x, y);
00230     if(colWidth < 0)  return 1;
00231     Texts.append(new Text(x, y, Str));  // dependent variable
00232     y -= tHeight + 2;
00233   }
00234   x += colWidth + 13;
00235   xAxis.numGraphs = x -6;
00236   Lines.append(new Line(x-6, y2, x-6, 0, QPen(Qt::black,0)));
00237   xStart = x;
00238 
00239 
00240   invisibleCount = NumAll - (x2-xAxis.numGraphs)/TimeStepWidth;
00241   if(invisibleCount <= 0)  xAxis.limit_min = 0.0;  // longer than needed
00242   else {
00243     NumLeft = invisibleCount - int(xAxis.limit_min + 0.5);
00244     if(invisibleCount < int(xAxis.limit_min + 0.5))
00245       xAxis.limit_min = double(invisibleCount); // adjust limit of scroll bar
00246   }
00247 
00248 
00249   // write independent variable values (usually time)
00250   y = y2-tHeight-4;
00251   px = pD->Points;
00252   z = int(xAxis.limit_min + 0.5);
00253   px += z;
00254   z = pD->count - z;
00255   for( ; z>0; z--) {
00256     Str = misc::num2str(*(px++));
00257     colWidth = metrics.width(Str);  // width of text
00258     if(x+colWidth+2 >= x2)  break;
00259 
00260     Texts.append(new Text( x, y2-2, Str));
00261     Lines.append(new Line(x+5, y, x+5, y-3, QPen(Qt::black,0)));
00262     x += TimeStepWidth;
00263   }
00264 
00265 }  // of "if no data in graphs"
00266 
00267 
00268   tHeight += 2;
00269   // ................................................
00270   // work on all dependent variables
00271   QPen Pen;
00272   int  yLast, yNow;
00273   y = y2-tHeight-9;
00274   foreach(Graph *g, Graphs) {
00275     if(y < tHeight) {
00276       // mark lack of space with a small arrow
00277       Lines.append(new Line(4, 6, 4, -7, QPen(Qt::red,2)));
00278       Lines.append(new Line(1, 0, 4, -7, QPen(Qt::red,2)));
00279       Lines.append(new Line(7, 0, 4, -7, QPen(Qt::red,2)));
00280       break;
00281     }
00282 
00283     x = xStart + 5;
00284     colWidth = 0;
00285 
00286     if(g->cPointsY == 0) {
00287       Str = QObject::tr("no data");
00288       colWidth = checkColumnWidth(Str, metrics, colWidth, x, y);
00289       if(colWidth < 0)  goto funcEnd;
00290       Texts.append(new Text(x, y, Str));
00291       y -= tHeight;
00292       continue;
00293     }
00294 
00295     if(!sameDependencies(g, firstGraph)) {
00296       Str = QObject::tr("wrong dependency");
00297       colWidth = checkColumnWidth(Str, metrics, colWidth, x, y);
00298       if(colWidth < 0)  goto funcEnd;
00299       Texts.append(new Text(x, y, Str));
00300       y -= tHeight;
00301       continue;
00302     }
00303 
00304     Pen = QPen(g->Color, g->Thick);  // default is solid line
00305     switch(g->Style) {
00306       case 1: Pen.setStyle(Qt::DashLine); break;
00307       case 2: Pen.setStyle(Qt::DotLine);  break;
00308     default: break;
00309     }
00310 
00311     z = int(xAxis.limit_min + 0.5);
00312     if(g->Var.right(2) != ".X") {  // not digital variable ?
00313       px = g->cPointsY;
00314       px += 2 * z;
00315       z = g->axis(0)->count - z;
00316       yNow = 1 + ((tHeight - 6) >> 1);
00317       Lines.append(new Line(x, y-yNow, x+2, y-1, Pen));
00318       Lines.append(new Line(x+2, y-tHeight+5, x, y-yNow, Pen));
00319       for( ; z>0; z--) {
00320         if(x+TimeStepWidth >= x2) break;
00321         Lines.append(new Line(x+2, y-1, x+TimeStepWidth-2, y-1, Pen));
00322         Lines.append(new Line(x+2, y-tHeight+5, x+TimeStepWidth-2, y-tHeight+5, Pen));
00323 
00324   if (*(px+1) == 0.0)
00325     // output real number
00326     Texts.append(new Text(x+3, y,QString::number(*px)));
00327   else
00328     // output magnitude of (complex) number
00329     Texts.append(new Text(x+3, y,
00330               QString::number(sqrt((*px)*(*px) + (*(px+1))*(*(px+1))))));
00331 
00332         px += 2;
00333         x += TimeStepWidth;
00334         Lines.append(new Line(x-2, y-tHeight+5, x+2, y-1, Pen));
00335         Lines.append(new Line(x+2, y-tHeight+5, x-2, y-1, Pen));
00336       }
00337       y -= tHeight;
00338       continue;
00339     }
00340 
00341 
00342     // digital variable !!!
00343     char *pcx = (char*)g->cPointsY;
00344     pcx += z * (strlen(pcx)+1);
00345 
00346     if(strlen(pcx) < 2) {   // vector or single bit ?
00347 
00348       // It is single "bit".
00349       yLast = 0;
00350       if(z > 0)  yLast += 2; // vertical line before first value ?
00351       switch(*(pcx-yLast)) {  // high or low ?
00352         case '0':  // low
00353           yLast = tHeight - 5;
00354           break;
00355         case '1':  // high
00356           yLast = 1;
00357           break;
00358         default:
00359           yLast = 1 + ((tHeight - 6) >> 1);
00360       }
00361 
00362       z = g->axis(0)->count - z;
00363       for( ; z>0; z--) {
00364 
00365         switch(*pcx) {
00366           case '0':  // low
00367             yNow = tHeight - 5;
00368             break;
00369           case '1':  // high
00370             yNow = 1;
00371             break;
00372           default:
00373             yNow = 1 + ((tHeight - 6) >> 1);
00374         } 
00375 
00376         if(yLast != yNow)
00377           Lines.append(new Line(x, y-yLast, x, y-yNow, Pen));
00378         if(x+TimeStepWidth >= x2) break;
00379         if((*pcx & 254) == '0')
00380           Lines.append(new Line(x, y-yNow, x+TimeStepWidth, y-yNow, Pen));
00381         else {
00382           Texts.append(new Text(x+(TimeStepWidth>>1)-3, y, QString(pcx)));
00383           Lines.append(new Line(x+3, y-1, x+TimeStepWidth-3, y-1, Pen));
00384           Lines.append(new Line(x+3, y-tHeight+5, x+TimeStepWidth-3, y-tHeight+5, Pen));
00385           Lines.append(new Line(x, y-yNow, x+3, y-1, Pen));
00386           Lines.append(new Line(x, y-yNow, x+3, y-tHeight+5, Pen));
00387           Lines.append(new Line(x+TimeStepWidth-3, y-1, x+TimeStepWidth, y-yNow, Pen));
00388           Lines.append(new Line(x+TimeStepWidth-3, y-tHeight+5, x+TimeStepWidth, y-yNow, Pen));
00389         }
00390 
00391         yLast = yNow;
00392         x += TimeStepWidth;
00393         pcx += 2;
00394       }
00395 
00396     }
00397     else {  // It is a bit vector !!!
00398 
00399       z = g->axis(0)->count - z;
00400       yNow = 1 + ((tHeight - 6) >> 1);
00401       Lines.append(new Line(x, y-yNow, x+2, y-1, Pen));
00402       Lines.append(new Line(x+2, y-tHeight+5, x, y-yNow, Pen));
00403       for( ; z>0; z--) {
00404         if(x+TimeStepWidth >= x2) break;
00405         Lines.append(new Line(x+2, y-1, x+TimeStepWidth-2, y-1, Pen));
00406         Lines.append(new Line(x+2, y-tHeight+5, x+TimeStepWidth-2, y-tHeight+5, Pen));
00407 
00408         Texts.append(new Text(x+3, y, QString(pcx)));
00409 
00410         x += TimeStepWidth;
00411         pcx += strlen(pcx) + 1;
00412         Lines.append(new Line(x-2, y-tHeight+5, x+2, y-1, Pen));
00413         Lines.append(new Line(x+2, y-tHeight+5, x-2, y-1, Pen));
00414       }
00415     }
00416 
00417     y -= tHeight;
00418   }  // of "for(Graphs...)"
00419 
00420 
00421 funcEnd:
00422   if(invisibleCount > 0) {  // could all values be displayed ?
00423     x  = x2 - xAxis.numGraphs - 37;
00424     if(x < MIN_SCROLLBAR_SIZE+2) {  // not enough space for scrollbar ?
00425       Lines.append(new Line(x2, 0, x2, -17, QPen(Qt::red,0)));
00426       Lines.append(new Line(xAxis.numGraphs, -17, x2, -17, QPen(Qt::red,0)));
00427       Lines.append(new Line(xAxis.numGraphs, 0, xAxis.numGraphs, -17, QPen(Qt::red,0)));
00428       return 1;
00429     }
00430 
00431     y1 = 18;   // extend the select area to the bottom
00432     z  = int(xAxis.limit_min + 0.5);
00433     if(NumLeft < 0) NumLeft = 0;
00434     y  = NumAll - NumLeft - z;
00435 
00436     // number of data (times) 
00437     zAxis.limit_max = double(firstGraph->axis(0)->count);
00438 
00439     // position of scroll bar in pixel
00440     yAxis.numGraphs = x * z / NumAll + xAxis.numGraphs + 19;
00441 
00442     // length of scroll bar
00443     zAxis.numGraphs = x * y / NumAll;
00444     if(zAxis.numGraphs < MIN_SCROLLBAR_SIZE) {
00445       yAxis.numGraphs -= (MIN_SCROLLBAR_SIZE - zAxis.numGraphs + 1)
00446                          * z / NumAll;
00447       zAxis.numGraphs = MIN_SCROLLBAR_SIZE;
00448 
00449       x = x2 - 19 - yAxis.numGraphs - zAxis.numGraphs;
00450       if(x < 0)  yAxis.numGraphs += x;
00451     }
00452 
00453     xAxis.limit_max = double(y);
00454   }
00455 
00456   return 1;
00457 }
00458 
00459 // ------------------------------------------------------------
00460 int TimingDiagram::scroll(int clickPos)
00461 {
00462   if(y1 <= 0) return 0;   // no scroll bar ?
00463   int tmp = int(xAxis.limit_min + 0.5);
00464 
00465   int x = cx;
00466   if(clickPos > (cx+x2-20)) {  // scroll one value to the right ?
00467     xAxis.limit_min++;
00468   }
00469   else {
00470     x += xAxis.numGraphs + 20;
00471     if(clickPos < x) {  // scroll bar one value to the left ?
00472       if(xAxis.limit_min <= 0.0)  return 0;
00473       xAxis.limit_min--;
00474     }
00475     else {
00476       x = cx + yAxis.numGraphs;
00477       if(clickPos < x)   // scroll bar one page to the left ?
00478         xAxis.limit_min -= xAxis.limit_max;
00479       else {
00480         x += zAxis.numGraphs;
00481         if(clickPos > x)   // one page to the right ?
00482           xAxis.limit_min += xAxis.limit_max;
00483         else
00484           return 2;  // click on position bar
00485       }
00486     }
00487   }
00488 
00489   calcDiagram();
00490   if(tmp == int(xAxis.limit_min+0.5))
00491     return 0;   // did anything change ?
00492 
00493   return 1;
00494 }
00495 
00496 // ------------------------------------------------------------
00497 bool TimingDiagram::scrollTo(int initial, int dx, int)
00498 {
00499   int tmp = int(xAxis.limit_min + 0.5);
00500   xAxis.limit_min  = double(initial);
00501   xAxis.limit_min += double(dx) / double(x2-xAxis.numGraphs-39) * zAxis.limit_max;
00502   xAxis.limit_min  = floor(xAxis.limit_min + 0.5);
00503 
00504   calcDiagram();
00505   if(tmp == int(xAxis.limit_min + 0.5))
00506     return false;   // did anything change ?
00507 
00508   return true;
00509 }
00510 
00511 // ------------------------------------------------------------
00512 Diagram* TimingDiagram::newOne()
00513 {
00514   return new TimingDiagram();
00515 }
00516 
00517 // ------------------------------------------------------------
00518 Element* TimingDiagram::info(QString& Name, char* &BitmapFile, bool getNewOne)
00519 {
00520   Name = QObject::tr("Timing Diagram");
00521   BitmapFile = (char *) "timing";
00522 
00523   if(getNewOne)  return new TimingDiagram();
00524   return 0;
00525 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines