Qucs-GUI  0.0.18
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
timingdiagram.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  timingdiagram.cpp
3  -------------------
4  begin : Sat Oct 22 2005
5  copyright : (C) 2005 by Michael Margraf
6  email : michael.margraf@alumni.tu-berlin.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 #include <QtGui>
18 #include "timingdiagram.h"
19 #include "main.h"
20 
21 #include <math.h>
22 //Added by qt3to4:
23 #include <Q3PointArray>
24 
25 #include "qucs.h"
26 #include "schematic.h"
27 
28 TimingDiagram::TimingDiagram(int _cx, int _cy) : TabDiagram(_cx, _cy)
29 {
30  x1 = 0; // no extension to select area
31  y1 = 0;
32  x2 = x3 = 300; // initial size of diagram
33  y2 = 200;
34  Name = "Time";
35  xAxis.limit_min = 0.0; // scroll bar position (needs to be saved in file)
36 
37  calcDiagram();
38 }
39 
41 {
42 }
43 
44 // ------------------------------------------------------------
46 {
47  // paint all lines
48  for(Line *pl = Lines.first(); pl != 0; pl = Lines.next()) {
49  p->Painter->setPen(pl->style);
50  p->drawLine(cx+pl->x1, cy-pl->y1, cx+pl->x2, cy-pl->y2);
51  }
52 
53  p->Painter->setPen(Qt::black);
54  // write whole text
55  for(Text *pt = Texts.first(); pt != 0; pt = Texts.next())
56  p->drawText(pt->s, cx+pt->x, cy-pt->y);
57 
58 
59  if(y1 > 0) { // paint scroll bar ?
60  int x, y, dx, dy;
61  Q3PointArray Points;
62  // draw scroll bar
63  p->fillRect(cx+yAxis.numGraphs, cy+2, zAxis.numGraphs, 14, QColor(192, 192, 192));
64 
65  int bx = cx+yAxis.numGraphs+zAxis.numGraphs;
66  // draw frame for scroll bar
67  p->Painter->setPen(QPen(Qt::black,0));
69  p->drawLine(cx+xAxis.numGraphs+17, cy, cx+xAxis.numGraphs+17, cy+17);
70  p->drawLine(cx+xAxis.numGraphs, cy+17, cx+x2, cy+17);
71  p->drawLine(cx+x2, cy, cx+x2, cy+17);
72  p->drawLine(cx+x2-17, cy, cx+x2-17, cy+17);
73 
74  // draw the arrows above and below the scroll bar
75  p->Painter->setBrush(QColor(192, 192, 192));
76  p->Painter->setPen(QColor(152, 152, 152));
77  p->drawLine(cx+yAxis.numGraphs, cy+15, bx, cy+15);
78  p->drawLine(bx, cy+2, bx, cy+15);
79 
80  p->map(cx+xAxis.numGraphs+3, cy+3, x, y);
81  p->map(cx+xAxis.numGraphs+14, cy+14, dx, dy);
82  Points.setPoints(3, x, (y+dy)>>1, dx, y, dx, dy);
83  p->Painter->drawConvexPolygon(Points);
84  p->Painter->setPen(QColor(224, 224, 224));
85  p->Painter->drawLine(x, (y+dy)>>1, dx, y);
86  p->drawLine(cx+yAxis.numGraphs, cy+2, bx, cy+2);
88 
89  p->Painter->setPen(QColor(152, 152, 152));
90  dx -= x;
91  p->map(cx+x2-3, cy+3, x, y);
92  Points.setPoints(3, x, (y+dy)>>1, x-dx, y, x-dx, dy);
93  p->Painter->drawConvexPolygon(Points);
94  p->Painter->setPen(QColor(208, 208, 208));
95  p->Painter->drawLine(x-dx, y, x, (y+dy)>>1);
96  p->Painter->setPen(QColor(224, 224, 224));
97  p->Painter->drawLine(x-dx, y, x-dx, dy);
98 
99  p->Painter->setBrush(QBrush(Qt::NoBrush));
100  }
101 
102 
103  if(isSelected) {
104  p->Painter->setPen(QPen(Qt::darkGray,3));
105  p->drawRect(cx-5, cy-y2-5, x2+10, y2+10);
106  p->Painter->setPen(QPen(Qt::darkRed,2));
107  p->drawResizeRect(cx, cy-y2); // markers for changing the size
108  p->drawResizeRect(cx, cy);
109  p->drawResizeRect(cx+x2, cy-y2);
110  p->drawResizeRect(cx+x2, cy);
111  }
112 }
113 
114 // ------------------------------------------------------------
116 {
117  Lines.clear();
118  Texts.clear();
119 
120  y1 = 0; // no scroll bar
121  x3 = x2;
122  QFontMetrics metrics(((Schematic*)QucsMain->DocumentTab->currentPage())->font()); // get size of text
123  int tHeight = metrics.lineSpacing();
124  QString Str;
125  int colWidth=0, x=4, y, xStart = 0, z;
126 
127  int NumAll=0; // how many values per row
128  int NumLeft=0; // how many values could not be written
129  int invisibleCount = 0; // how many values are invisible
130 
131  if(y2 < (tHeight + 8))
132  y2 = tHeight + 8;
133  y = y2 - tHeight - 6;
134 
135  // outer frame
136  Lines.append(new Line(0, y2, x2, y2, QPen(Qt::black,0)));
137  Lines.append(new Line(0, y2, 0, 0, QPen(Qt::black,0)));
138  Lines.append(new Line(x2, y2, x2, 0, QPen(Qt::black,0)));
139  Lines.append(new Line(0, 0, x2, 0, QPen(Qt::black,0)));
140  Lines.append(new Line(0, y+2, x2, y+2, QPen(Qt::black,0)));
141 
142  if(xAxis.limit_min < 0.0)
143  xAxis.limit_min = 0.0;
144 
145  Graph *firstGraph;
146  Graph *g = Graphs.first();
147  if(g == 0) { // no variables specified in diagram ?
148  Str = QObject::tr("no variables");
149  colWidth = checkColumnWidth(Str, metrics, colWidth, x, y2);
150  if(colWidth >= 0)
151  Texts.append(new Text(x, y2-2, Str)); // independent variable
152  return 0;
153  }
154 
155 
156  double *px;
157  while(g->cPointsX.isEmpty()) { // any graph with data ?
158  g = Graphs.next();
159  if(g == 0) break;
160  }
161  if(g == 0) {
162  Str = QObject::tr("no data");
163  colWidth = checkColumnWidth(Str, metrics, colWidth, x, y2);
164  if(colWidth < 0) return 0;
165  Texts.append(new Text(x, y2-2, Str));
166  return 0;
167  }
168  firstGraph = g;
169 
170 
171  // First check the maximum bit number of all vectors.
172  colWidth = 0;
173  for(g = Graphs.first(); g!=0; g = Graphs.next())
174  if(g->cPointsY) {
175  if(g->Var.right(2) == ".X") {
176  z = strlen((char*)g->cPointsY);
177  if(z > colWidth)
178  colWidth = z;
179  }
180  else {
181  z = 8;
182  if(z > colWidth)
183  colWidth = z;
184  }
185  }
186  int TimeStepWidth = colWidth * metrics.width("X") + 8;
187  if(TimeStepWidth < 40)
188  TimeStepWidth = 40;
189 
190 
191  colWidth = 0;
192 if(!firstGraph->cPointsX.isEmpty()) {
193  // ................................................
194  if(firstGraph->cPointsX.count() > 1) {
195  Str = QObject::tr("wrong dependency");
196  colWidth = checkColumnWidth(Str, metrics, colWidth, x, y2);
197  if(colWidth >= 0)
198  Texts.append(new Text(x, y2-2, Str)); // independent variable
199  return 0;
200  }
201 
202 
203  // first, write name of independent variable
204  DataX *pD = firstGraph->cPointsX.getFirst();
205  NumAll = pD->count;
206  Str = pD->Var;
207  colWidth = checkColumnWidth(Str, metrics, colWidth, x, y2);
208  if(colWidth < 0) return 1;
209  Texts.append(new Text(x, y2-2, Str));
210 
211 
212  y -= 5;
213  // write all dependent variable names to get width of first column
214  for(g = Graphs.first(); g!=0; g = Graphs.next()) {
215  if(y < tHeight) break;
216  Str = g->Var;
217  colWidth = checkColumnWidth(Str, metrics, colWidth, x, y);
218  if(colWidth < 0) return 1;
219  Texts.append(new Text(x, y, Str)); // dependent variable
220  y -= tHeight + 2;
221  }
222  x += colWidth + 13;
223  xAxis.numGraphs = x -6;
224  Lines.append(new Line(x-6, y2, x-6, 0, QPen(Qt::black,0)));
225  xStart = x;
226 
227 
228  invisibleCount = NumAll - (x2-xAxis.numGraphs)/TimeStepWidth;
229  if(invisibleCount <= 0) xAxis.limit_min = 0.0; // longer than needed
230  else {
231  NumLeft = invisibleCount - int(xAxis.limit_min + 0.5);
232  if(invisibleCount < int(xAxis.limit_min + 0.5))
233  xAxis.limit_min = double(invisibleCount); // adjust limit of scroll bar
234  }
235 
236 
237  // write independent variable values (usually time)
238  y = y2-tHeight-4;
239  px = pD->Points;
240  z = int(xAxis.limit_min + 0.5);
241  px += z;
242  z = pD->count - z;
243  for( ; z>0; z--) {
244  Str = num2str(*(px++));
245  colWidth = metrics.width(Str); // width of text
246  if(x+colWidth+2 >= x2) break;
247 
248  Texts.append(new Text( x, y2-2, Str));
249  Lines.append(new Line(x+5, y, x+5, y-3, QPen(Qt::black,0)));
250  x += TimeStepWidth;
251  }
252 
253 } // of "if no data in graphs"
254 
255 
256  tHeight += 2;
257  // ................................................
258  // work on all dependent variables
259  QPen Pen;
260  int yLast, yNow;
261  y = y2-tHeight-9;
262  for(g = Graphs.first(); g!=0; g = Graphs.next()) {
263  if(y < tHeight) {
264  // mark lack of space with a small arrow
265  Lines.append(new Line(4, 6, 4, -7, QPen(Qt::red,2)));
266  Lines.append(new Line(1, 0, 4, -7, QPen(Qt::red,2)));
267  Lines.append(new Line(7, 0, 4, -7, QPen(Qt::red,2)));
268  break;
269  }
270 
271  x = xStart + 5;
272  colWidth = 0;
273 
274  if(g->cPointsY == 0) {
275  Str = QObject::tr("no data");
276  colWidth = checkColumnWidth(Str, metrics, colWidth, x, y);
277  if(colWidth < 0) goto funcEnd;
278  Texts.append(new Text(x, y, Str));
279  y -= tHeight;
280  continue;
281  }
282 
283  if(!sameDependencies(g, firstGraph)) {
284  Str = QObject::tr("wrong dependency");
285  colWidth = checkColumnWidth(Str, metrics, colWidth, x, y);
286  if(colWidth < 0) goto funcEnd;
287  Texts.append(new Text(x, y, Str));
288  y -= tHeight;
289  continue;
290  }
291 
292  Pen = QPen(g->Color, g->Thick); // default is solid line
293  switch(g->Style) {
294  case 1: Pen.setStyle(Qt::DashLine); break;
295  case 2: Pen.setStyle(Qt::DotLine); break;
296  }
297 
298  z = int(xAxis.limit_min + 0.5);
299  if(g->Var.right(2) != ".X") { // not digital variable ?
300  px = g->cPointsY;
301  px += 2 * z;
302  z = g->cPointsX.getFirst()->count - z;
303  yNow = 1 + ((tHeight - 6) >> 1);
304  Lines.append(new Line(x, y-yNow, x+2, y-1, Pen));
305  Lines.append(new Line(x+2, y-tHeight+5, x, y-yNow, Pen));
306  for( ; z>0; z--) {
307  if(x+TimeStepWidth >= x2) break;
308  Lines.append(new Line(x+2, y-1, x+TimeStepWidth-2, y-1, Pen));
309  Lines.append(new Line(x+2, y-tHeight+5, x+TimeStepWidth-2, y-tHeight+5, Pen));
310 
311  if (*(px+1) == 0.0)
312  // output real number
313  Texts.append(new Text(x+3, y,QString::number(*px)));
314  else
315  // output magnitude of (complex) number
316  Texts.append(new Text(x+3, y,
317  QString::number(sqrt((*px)*(*px) + (*(px+1))*(*(px+1))))));
318 
319  px += 2;
320  x += TimeStepWidth;
321  Lines.append(new Line(x-2, y-tHeight+5, x+2, y-1, Pen));
322  Lines.append(new Line(x+2, y-tHeight+5, x-2, y-1, Pen));
323  }
324  y -= tHeight;
325  continue;
326  }
327 
328 
329  // digital variable !!!
330  char *pcx = (char*)g->cPointsY;
331  pcx += z * (strlen(pcx)+1);
332 
333  if(strlen(pcx) < 2) { // vector or single bit ?
334 
335  // It is single "bit".
336  yLast = 0;
337  if(z > 0) yLast += 2; // vertical line before first value ?
338  switch(*(pcx-yLast)) { // high or low ?
339  case '0': // low
340  yLast = tHeight - 5;
341  break;
342  case '1': // high
343  yLast = 1;
344  break;
345  default:
346  yLast = 1 + ((tHeight - 6) >> 1);
347  }
348 
349  z = g->cPointsX.getFirst()->count - z;
350  for( ; z>0; z--) {
351 
352  switch(*pcx) {
353  case '0': // low
354  yNow = tHeight - 5;
355  break;
356  case '1': // high
357  yNow = 1;
358  break;
359  default:
360  yNow = 1 + ((tHeight - 6) >> 1);
361  }
362 
363  if(yLast != yNow)
364  Lines.append(new Line(x, y-yLast, x, y-yNow, Pen));
365  if(x+TimeStepWidth >= x2) break;
366  if((*pcx & 254) == '0')
367  Lines.append(new Line(x, y-yNow, x+TimeStepWidth, y-yNow, Pen));
368  else {
369  Texts.append(new Text(x+(TimeStepWidth>>1)-3, y, QString(pcx)));
370  Lines.append(new Line(x+3, y-1, x+TimeStepWidth-3, y-1, Pen));
371  Lines.append(new Line(x+3, y-tHeight+5, x+TimeStepWidth-3, y-tHeight+5, Pen));
372  Lines.append(new Line(x, y-yNow, x+3, y-1, Pen));
373  Lines.append(new Line(x, y-yNow, x+3, y-tHeight+5, Pen));
374  Lines.append(new Line(x+TimeStepWidth-3, y-1, x+TimeStepWidth, y-yNow, Pen));
375  Lines.append(new Line(x+TimeStepWidth-3, y-tHeight+5, x+TimeStepWidth, y-yNow, Pen));
376  }
377 
378  yLast = yNow;
379  x += TimeStepWidth;
380  pcx += 2;
381  }
382 
383  }
384  else { // It is a bit vector !!!
385 
386  z = g->cPointsX.getFirst()->count - z;
387  yNow = 1 + ((tHeight - 6) >> 1);
388  Lines.append(new Line(x, y-yNow, x+2, y-1, Pen));
389  Lines.append(new Line(x+2, y-tHeight+5, x, y-yNow, Pen));
390  for( ; z>0; z--) {
391  if(x+TimeStepWidth >= x2) break;
392  Lines.append(new Line(x+2, y-1, x+TimeStepWidth-2, y-1, Pen));
393  Lines.append(new Line(x+2, y-tHeight+5, x+TimeStepWidth-2, y-tHeight+5, Pen));
394 
395  Texts.append(new Text(x+3, y, QString(pcx)));
396 
397  x += TimeStepWidth;
398  pcx += strlen(pcx) + 1;
399  Lines.append(new Line(x-2, y-tHeight+5, x+2, y-1, Pen));
400  Lines.append(new Line(x+2, y-tHeight+5, x-2, y-1, Pen));
401  }
402  }
403 
404  y -= tHeight;
405  } // of "for(Graphs...)"
406 
407 
408 funcEnd:
409  if(invisibleCount > 0) { // could all values be displayed ?
410  x = x2 - xAxis.numGraphs - 37;
411  if(x < MIN_SCROLLBAR_SIZE+2) { // not enough space for scrollbar ?
412  Lines.append(new Line(x2, 0, x2, -17, QPen(Qt::red,0)));
413  Lines.append(new Line(xAxis.numGraphs, -17, x2, -17, QPen(Qt::red,0)));
414  Lines.append(new Line(xAxis.numGraphs, 0, xAxis.numGraphs, -17, QPen(Qt::red,0)));
415  return 1;
416  }
417 
418  y1 = 18; // extend the select area to the bottom
419  z = int(xAxis.limit_min + 0.5);
420  if(NumLeft < 0) NumLeft = 0;
421  y = NumAll - NumLeft - z;
422 
423  // number of data (times)
424  zAxis.limit_max = double(firstGraph->cPointsX.getFirst()->count);
425 
426  // position of scroll bar in pixel
427  yAxis.numGraphs = x * z / NumAll + xAxis.numGraphs + 19;
428 
429  // length of scroll bar
430  zAxis.numGraphs = x * y / NumAll;
433  * z / NumAll;
435 
436  x = x2 - 19 - yAxis.numGraphs - zAxis.numGraphs;
437  if(x < 0) yAxis.numGraphs += x;
438  }
439 
440  xAxis.limit_max = double(y);
441  }
442 
443  return 1;
444 }
445 
446 // ------------------------------------------------------------
447 int TimingDiagram::scroll(int clickPos)
448 {
449  if(y1 <= 0) return 0; // no scroll bar ?
450  int tmp = int(xAxis.limit_min + 0.5);
451 
452  int x = cx;
453  if(clickPos > (cx+x2-20)) { // scroll one value to the right ?
454  xAxis.limit_min++;
455  }
456  else {
457  x += xAxis.numGraphs + 20;
458  if(clickPos < x) { // scroll bar one value to the left ?
459  if(xAxis.limit_min <= 0.0) return 0;
460  xAxis.limit_min--;
461  }
462  else {
463  x = cx + yAxis.numGraphs;
464  if(clickPos < x) // scroll bar one page to the left ?
466  else {
467  x += zAxis.numGraphs;
468  if(clickPos > x) // one page to the right ?
470  else
471  return 2; // click on position bar
472  }
473  }
474  }
475 
476  calcDiagram();
477  if(tmp == int(xAxis.limit_min+0.5))
478  return 0; // did anything change ?
479 
480  return 1;
481 }
482 
483 // ------------------------------------------------------------
484 bool TimingDiagram::scrollTo(int initial, int dx, int)
485 {
486  int tmp = int(xAxis.limit_min + 0.5);
487  xAxis.limit_min = double(initial);
488  xAxis.limit_min += double(dx) / double(x2-xAxis.numGraphs-39) * zAxis.limit_max;
489  xAxis.limit_min = floor(xAxis.limit_min + 0.5);
490 
491  calcDiagram();
492  if(tmp == int(xAxis.limit_min + 0.5))
493  return false; // did anything change ?
494 
495  return true;
496 }
497 
498 // ------------------------------------------------------------
500 {
501  return new TimingDiagram();
502 }
503 
504 // ------------------------------------------------------------
505 Element* TimingDiagram::info(QString& Name, char* &BitmapFile, bool getNewOne)
506 {
507  Name = QObject::tr("Timing Diagram");
508  BitmapFile = (char *) "timing";
509 
510  if(getNewOne) return new TimingDiagram();
511  return 0;
512 }
Axis xAxis
Definition: diagram.h:101
void drawResizeRect(int, int)
QPainter * Painter
Definition: viewpainter.h:58
int Thick
Definition: graph.h:77
void paint(ViewPainter *)
int y1
Definition: element.h:153
int count
Definition: graph.h:53
Definition: graph.h:57
QString Name
Definition: diagram.h:92
void map(int, int, int &, int &)
Definition: viewpainter.cpp:63
#define MIN_SCROLLBAR_SIZE
Definition: diagram.h:31
int y2
Definition: element.h:153
int x1
Definition: element.h:153
bool sameDependencies(Graph *, Graph *)
Definition: diagram.cpp:1136
QString Var
Definition: graph.h:50
void drawLine(int, int, int, int)
Definition: viewpainter.cpp:85
Definition: graph.h:47
double limit_min
Definition: diagram.h:56
QString Var
Definition: graph.h:75
Definitions and declarations for the main application.
QucsApp * QucsMain
Definition: main.cpp:54
int cx
Definition: element.h:153
void fillRect(int, int, int, int, const QColor &)
bool isSelected
Definition: element.h:151
int drawText(const QString &, int, int, int *Height=0)
QString num2str(double Num)
Definition: main.cpp:384
static Element * info(QString &, char *&, bool getNewOne=false)
int numGraphs
Definition: diagram.h:52
Axis zAxis
Definition: diagram.h:101
Q3PtrList< Graph > Graphs
Definition: diagram.h:95
Definition: element.h:82
int x3
Definition: diagram.h:100
int checkColumnWidth(const QString &, const QFontMetrics &, int, int, int)
Definition: diagram.cpp:1154
Definition: element.h:48
void drawRect(int, int, int, int)
Superclass of all schematic drawing elements.
Definition: element.h:142
double limit_max
Definition: diagram.h:56
int Style
Definition: graph.h:78
QTabWidget * DocumentTab
Definition: qucs.h:164
QColor Color
Definition: graph.h:76
Q3PtrList< Text > Texts
Definition: diagram.h:98
TimingDiagram(int _cx=0, int _cy=0)
int cy
Definition: element.h:153
Axis yAxis
Definition: diagram.h:101
bool scrollTo(int, int, int)
double * Points
Definition: graph.h:52
Q3PtrList< DataX > cPointsX
Definition: graph.h:71
int x2
Definition: element.h:153
double * cPointsY
Definition: graph.h:72
Q3PtrList< Line > Lines
Definition: diagram.h:97
Diagram * newOne()