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