My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
component.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  component.cpp
3  ---------------
4  begin : Sat Aug 23 2003
5  copyright : (C) 2003 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 <stdlib.h>
19 
20 #include <qdir.h>
21 #include <qpen.h>
22 #include <qpoint.h>
23 #include <qstring.h>
24 #include <qpainter.h>
25 #include <qtabwidget.h>
26 #include <qmessagebox.h>
27 #include <qdom.h>
28 #include <qdict.h>
29 
30 #include "components.h"
31 #include "node.h"
32 #include "main.h"
33 #include "qucs.h"
34 #include "schematic.h"
35 #include "viewpainter.h"
36 #include "module.h"
37 
38 // ***********************************************************************
39 // ********** **********
40 // ********** class "Component" **********
41 // ********** **********
42 // ***********************************************************************
44 {
46 
47  mirroredX = false;
48  rotated = 0;
49  isSelected = false;
51  showName = true;
52 
53  cx = 0;
54  cy = 0;
55  tx = 0;
56  ty = 0;
57 
58  Arcs.setAutoDelete(true);
59  Lines.setAutoDelete(true);
60  Rects.setAutoDelete(true);
61  Ellips.setAutoDelete(true);
62  Ports.setAutoDelete(true);
63  Texts.setAutoDelete(true);
64  Props.setAutoDelete(true);
65 }
66 
67 // -------------------------------------------------------
69 {
70  return new Component();
71 }
72 
73 // -------------------------------------------------------
74 void Component::Bounding(int& _x1, int& _y1, int& _x2, int& _y2)
75 {
76  _x1 = x1+cx;
77  _y1 = y1+cy;
78  _x2 = x2+cx;
79  _y2 = y2+cy;
80 }
81 
82 // -------------------------------------------------------
83 // Size of component text.
84 int Component::textSize(int& _dx, int& _dy)
85 {
86  QFontMetrics metrics(QucsSettings.font); // get size of text
87  int tmp, count=0;
88  _dx = _dy = 0;
89  if(showName) {
90  _dx = metrics.width(Name);
91  _dy = metrics.height();
92  count++;
93  }
94  for(Property *pp = Props.first(); pp != 0; pp = Props.next())
95  if(pp->display) {
96  // get width of text
97  tmp = metrics.width(pp->Name+"="+pp->Value);
98  if(tmp > _dx) _dx = tmp;
99  _dy += metrics.height();
100  count++;
101  }
102  return count;
103 }
104 
105 // -------------------------------------------------------
106 // Boundings including the component text.
107 void Component::entireBounds(int& _x1, int& _y1, int& _x2, int& _y2, float Corr)
108 {
109  _x1 = x1+cx;
110  _y1 = y1+cy;
111  _x2 = x2+cx;
112  _y2 = y2+cy;
113 
114  // text boundings
115  if(tx < x1) _x1 = tx+cx;
116  if(ty < y1) _y1 = ty+cy;
117 
118  int dx, dy, ny;
119  ny = textSize(dx, dy);
120  dy = int(float(ny) / Corr); // correction for unproportional font scaling
121 
122  if((tx+dx) > x2) _x2 = tx+dx+cx;
123  if((ty+dy) > y2) _y2 = ty+dy+cy;
124 }
125 
126 // -------------------------------------------------------
127 void Component::setCenter(int x, int y, bool relative)
128 {
129  if(relative) { cx += x; cy += y; }
130  else { cx = x; cy = y; }
131 }
132 
133 // -------------------------------------------------------
134 void Component::getCenter(int& x, int& y)
135 {
136  x = cx;
137  y = cy;
138 }
139 
140 // -------------------------------------------------------
141 int Component::getTextSelected(int x_, int y_, float Corr)
142 {
143  x_ -= cx;
144  y_ -= cy;
145  if(x_ < tx) return -1;
146  if(y_ < ty) return -1;
147 
148  x_ -= tx;
149  y_ -= ty;
150  int w, dy = int(float(y_) * Corr); // correction for font scaling
151  QFontMetrics metrics(QucsSettings.font);
152  if(showName) {
153  w = metrics.width(Name);
154  if(dy < 1) {
155  if(x_ < w) return 0;
156  return -1;
157  }
158  dy--;
159  }
160 
161  Property *pp;
162  for(pp = Props.first(); pp != 0; pp = Props.next())
163  if(pp->display)
164  if((dy--) < 1) break;
165  if(!pp) return -1;
166 
167  // get width of text
168  w = metrics.width(pp->Name+"="+pp->Value);
169  if(x_ > w) return -1;
170  return Props.at()+1; // number the property
171 }
172 
173 // -------------------------------------------------------
174 bool Component::getSelected(int x_, int y_)
175 {
176  x_ -= cx;
177  y_ -= cy;
178  if(x_ >= x1) if(x_ <= x2) if(y_ >= y1) if(y_ <= y2)
179  return true;
180 
181  return false;
182 }
183 
184 // -------------------------------------------------------
186 {
187  Text *pt;
188  int x, y, a, b, xb, yb;
189  QFont f = p->Painter->font(); // save current font
190  QFont newFont = f;
191 
192  if(Model.at(0) == '.') { // is simulation component (dc, ac, ...)
193  newFont.setPointSizeFloat(p->Scale * Texts.getFirst()->Size);
194  newFont.setWeight(QFont::DemiBold);
195  p->Painter->setFont(newFont);
196  p->map(cx, cy, x, y);
197 
198  p->Painter->setPen(QPen(QPen::darkBlue,2));
199  a = b = 0;
200  QRect r, t;
201  for(pt = Texts.first(); pt != 0; pt = Texts.next()) {
202  t.setRect(x, y+b, 0, 0);
203  p->Painter->drawText(t, Qt::AlignLeft|Qt::DontClip, pt->s, -1, &r);
204  b += r.height();
205  if(a < r.width()) a = r.width();
206  }
207  xb = a + int(12.0*p->Scale);
208  yb = b + int(10.0*p->Scale);
209  x2 = x1+25 + int(float(a) / p->Scale);
210  y2 = y1+23 + int(float(b) / p->Scale);
211  if(ty < y2+1) if(ty > y1-r.height()) ty = y2 + 1;
212 
213  p->map(cx-1, cy, x, y);
214  p->map(cx-6, cy-5, a, b);
215  p->Painter->drawRect(a, b, xb, yb);
216  p->Painter->drawLine(x, y+yb, a, b+yb);
217  p->Painter->drawLine(x+xb-1, y+yb, x, y+yb);
218  p->Painter->drawLine(x+xb-1, y+yb, a+xb, b+yb);
219  p->Painter->drawLine(x+xb-1, y+yb, x+xb-1, y);
220  p->Painter->drawLine(x+xb-1, y, a+xb, b);
221  }
222  else { // normal components go here
223 
224  // paint all lines
225  for(Line *p1 = Lines.first(); p1 != 0; p1 = Lines.next()) {
226  p->Painter->setPen(p1->style);
227  p->drawLine(cx+p1->x1, cy+p1->y1, cx+p1->x2, cy+p1->y2);
228  }
229 
230  // paint all arcs
231  for(Arc *p3 = Arcs.first(); p3 != 0; p3 = Arcs.next()) {
232  p->Painter->setPen(p3->style);
233  p->drawArc(cx+p3->x, cy+p3->y, p3->w, p3->h, p3->angle, p3->arclen);
234  }
235 
236  // paint all rectangles
237  Area *pa;
238  for(pa = Rects.first(); pa != 0; pa = Rects.next()) {
239  p->Painter->setPen(pa->Pen);
240  p->Painter->setBrush(pa->Brush);
241  p->drawRect(cx+pa->x, cy+pa->y, pa->w, pa->h);
242  }
243 
244  // paint all ellipses
245  for(pa = Ellips.first(); pa != 0; pa = Ellips.next()) {
246  p->Painter->setPen(pa->Pen);
247  p->Painter->setBrush(pa->Brush);
248  p->drawEllipse(cx+pa->x, cy+pa->y, pa->w, pa->h);
249  }
250  p->Painter->setBrush(QBrush::NoBrush);
251 
252  newFont.setWeight(QFont::Light);
253  QWMatrix wm = p->Painter->worldMatrix();
254  // write all text
255  for(pt = Texts.first(); pt != 0; pt = Texts.next()) {
256  p->Painter->setWorldMatrix(
257  QWMatrix(pt->mCos, -pt->mSin, pt->mSin, pt->mCos,
258  p->DX + float(cx+pt->x) * p->Scale,
259  p->DY + float(cy+pt->y) * p->Scale));
260  newFont.setPointSizeFloat(p->Scale * pt->Size);
261  newFont.setOverline(pt->over);
262  newFont.setUnderline(pt->under);
263  p->Painter->setFont(newFont);
264  p->Painter->setPen(pt->Color);
265  if (0) {
266  p->Painter->drawText(0, 0, 0, 0, Qt::AlignLeft|Qt::DontClip, pt->s);
267  } else {
268  int w, h;
269  w = p->drawTextMapped (pt->s, 0, 0, &h);
270  }
271  }
272  p->Painter->setWorldMatrix(wm);
273  p->Painter->setWorldXForm(false);
274  }
275 
276  // restore old font
277  p->Painter->setFont(f);
278 
279  p->Painter->setPen(QPen(QPen::black,1));
280  p->map(cx+tx, cy+ty, x, y);
281  if(showName) {
282  p->Painter->drawText(x, y, 0, 0, Qt::DontClip, Name);
283  y += p->LineSpacing;
284  }
285  // write all properties
286  for(Property *p4 = Props.first(); p4 != 0; p4 = Props.next())
287  if(p4->display) {
288  p->Painter->drawText(x, y, 0, 0, Qt::DontClip, p4->Name+"="+p4->Value);
289  y += p->LineSpacing;
290  }
291 
292  if(isActive == COMP_IS_OPEN)
293  p->Painter->setPen(QPen(QPen::red,0));
294  else if(isActive & COMP_IS_SHORTEN)
295  p->Painter->setPen(QPen(QPen::darkGreen,0));
296  if(isActive != COMP_IS_ACTIVE) {
297  p->drawRect(cx+x1, cy+y1, x2-x1+1, y2-y1+1);
298  p->drawLine(cx+x1, cy+y1, cx+x2, cy+y2);
299  p->drawLine(cx+x1, cy+y2, cx+x2, cy+y1);
300  }
301 
302  if(isSelected) {
303  p->Painter->setPen(QPen(QPen::darkGray,3));
304  p->drawRoundRect(cx+x1, cy+y1, x2-x1, y2-y1);
305  }
306 }
307 
308 // -------------------------------------------------------
309 // Paints the component when moved with the mouse.
310 void Component::paintScheme(QPainter *p)
311 {
312  if(Model.at(0) == '.') { // is simulation component (dc, ac, ...)
313  Text *pt;
314  int a, b, xb, yb;
315  QFont newFont = p->font();
316 
317  float Scale =
318  ((Schematic*)QucsMain->DocumentTab->currentPage())->Scale;
319  newFont.setPointSizeFloat(float(Scale) * QucsSettings.largeFontSize);
320  newFont.setWeight(QFont::DemiBold);
321  QFontMetrics metrics(newFont);
322 
323  a = b = 0;
324  QSize r;
325  for(pt = Texts.first(); pt != 0; pt = Texts.next()) {
326  r = metrics.size(0, pt->s);
327  b += r.height();
328  if(a < r.width()) a = r.width();
329  }
330  xb = a + int(12.0*Scale);
331  yb = b + int(10.0*Scale);
332  x2 = x1+25 + int(float(a) / Scale);
333  y2 = y1+23 + int(float(b) / Scale);
334  if(ty < y2+1) if(ty > y1-r.height()) ty = y2 + 1;
335 
336  p->drawRect(cx-6, cy-5, xb, yb);
337  p->drawLine(cx-1, cy+yb, cx-6, cy+yb-5);
338  p->drawLine(cx+xb-2, cy+yb, cx-1, cy+yb);
339  p->drawLine(cx+xb-2, cy+yb, cx+xb-6, cy+yb-5);
340  p->drawLine(cx+xb-2, cy+yb, cx+xb-2, cy);
341  p->drawLine(cx+xb-2, cy, cx+xb-6, cy-5);
342  return;
343  }
344 
345  // paint all lines
346  for(Line *p1 = Lines.first(); p1 != 0; p1 = Lines.next())
347  p->drawLine(cx+p1->x1, cy+p1->y1, cx+p1->x2, cy+p1->y2);
348 
349  // paint all ports
350  for(Port *p2 = Ports.first(); p2 != 0; p2 = Ports.next())
351  if(p2->avail) p->drawEllipse(cx+p2->x-4, cy+p2->y-4, 8, 8);
352 
353  for(Arc *p3 = Arcs.first(); p3 != 0; p3 = Arcs.next()) // paint all arcs
354  p->drawArc(cx+p3->x, cy+p3->y, p3->w, p3->h, p3->angle, p3->arclen);
355 
356  Area *pa;
357  for(pa = Rects.first(); pa != 0; pa = Rects.next()) // paint all rectangles
358  p->drawRect(cx+pa->x, cy+pa->y, pa->w, pa->h);
359 
360  for(pa = Ellips.first(); pa != 0; pa = Ellips.next()) // paint all ellipses
361  p->drawEllipse(cx+pa->x, cy+pa->y, pa->w, pa->h);
362 }
363 
364 // -------------------------------------------------------
365 // For output on a printer device.
366 void Component::print(ViewPainter *p, float FontScale)
367 {
368  Text *pt;
369  for(pt = Texts.first(); pt != 0; pt = Texts.next())
370  pt->Size *= FontScale;
371 
372  paint(p);
373 
374  for(pt = Texts.first(); pt != 0; pt = Texts.next())
375  pt->Size /= FontScale;
376 }
377 
378 // -------------------------------------------------------
379 // Rotates the component 90 counter-clockwise around its center
381 {
382  if(Ports.count() < 1) return; // do not rotate components without ports
383  int tmp, dx, dy;
384 
385  // rotate all lines
386  for(Line *p1 = Lines.first(); p1 != 0; p1 = Lines.next()) {
387  tmp = -p1->x1;
388  p1->x1 = p1->y1;
389  p1->y1 = tmp;
390  tmp = -p1->x2;
391  p1->x2 = p1->y2;
392  p1->y2 = tmp;
393  }
394 
395  // rotate all ports
396  for(Port *p2 = Ports.first(); p2 != 0; p2 = Ports.next()) {
397  tmp = -p2->x;
398  p2->x = p2->y;
399  p2->y = tmp;
400  }
401 
402  // rotate all arcs
403  for(Arc *p3 = Arcs.first(); p3 != 0; p3 = Arcs.next()) {
404  tmp = -p3->x;
405  p3->x = p3->y;
406  p3->y = tmp - p3->w;
407  tmp = p3->w;
408  p3->w = p3->h;
409  p3->h = tmp;
410  p3->angle += 16*90;
411  if(p3->angle >= 16*360) p3->angle -= 16*360;;
412  }
413 
414  Area *pa;
415  // rotate all rectangles
416  for(pa = Rects.first(); pa != 0; pa = Rects.next()) {
417  tmp = -pa->x;
418  pa->x = pa->y;
419  pa->y = tmp - pa->w;
420  tmp = pa->w;
421  pa->w = pa->h;
422  pa->h = tmp;
423  }
424 
425  // rotate all ellipses
426  for(pa = Ellips.first(); pa != 0; pa = Ellips.next()) {
427  tmp = -pa->x;
428  pa->x = pa->y;
429  pa->y = tmp - pa->w;
430  tmp = pa->w;
431  pa->w = pa->h;
432  pa->h = tmp;
433  }
434 
435  // rotate all text
436  float ftmp;
437  for(Text *pt = Texts.first(); pt != 0; pt = Texts.next()) {
438  tmp = -pt->x;
439  pt->x = pt->y;
440  pt->y = tmp;
441 
442  ftmp = -pt->mSin;
443  pt->mSin = pt->mCos;
444  pt->mCos = ftmp;
445  }
446 
447  tmp = -x1; // rotate boundings
448  x1 = y1; y1 = -x2;
449  x2 = y2; y2 = tmp;
450 
451  tmp = -tx; // rotate text position
452  tx = ty;
453  ty = tmp;
454  QFontMetrics metrics(QucsSettings.font); // get size of text
455  dx = dy = 0;
456  if(showName) {
457  dx = metrics.width(Name);
458  dy = metrics.lineSpacing();
459  }
460  for(Property *pp = Props.first(); pp != 0; pp = Props.next())
461  if(pp->display) {
462  // get width of text
463  tmp = metrics.width(pp->Name+"="+pp->Value);
464  if(tmp > dx) dx = tmp;
465  dy += metrics.lineSpacing();
466  }
467  if(tx > x2) ty = y1-ty+y2; // rotate text position
468  else if(ty < y1) ty -= dy;
469  else if(tx < x1) { tx += dy-dx; ty = y1-ty+y2; }
470  else ty -= dx;
471 
472  rotated++; // keep track of what's done
473  rotated &= 3;
474 }
475 
476 // -------------------------------------------------------
477 // Mirrors the component about the x-axis.
479 {
480  if(Ports.count() < 1) return; // do not rotate components without ports
481 
482  // mirror all lines
483  for(Line *p1 = Lines.first(); p1 != 0; p1 = Lines.next()) {
484  p1->y1 = -p1->y1;
485  p1->y2 = -p1->y2;
486  }
487 
488  // mirror all ports
489  for(Port *p2 = Ports.first(); p2 != 0; p2 = Ports.next())
490  p2->y = -p2->y;
491 
492  // mirror all arcs
493  for(Arc *p3 = Arcs.first(); p3 != 0; p3 = Arcs.next()) {
494  p3->y = -p3->y - p3->h;
495  if(p3->angle > 16*180) p3->angle -= 16*360;
496  p3->angle = -p3->angle; // mirror
497  p3->angle -= p3->arclen; // go back to end of arc
498  if(p3->angle < 0) p3->angle += 16*360; // angle has to be > 0
499  }
500 
501  Area *pa;
502  // mirror all rectangles
503  for(pa = Rects.first(); pa != 0; pa = Rects.next())
504  pa->y = -pa->y - pa->h;
505 
506  // mirror all ellipses
507  for(pa = Ellips.first(); pa != 0; pa = Ellips.next())
508  pa->y = -pa->y - pa->h;
509 
510  QFont f = QucsSettings.font;
511  // mirror all text
512  for(Text *pt = Texts.first(); pt != 0; pt = Texts.next()) {
513  f.setPointSizeFloat(pt->Size);
514  QFontMetrics smallMetrics(f);
515  QSize s = smallMetrics.size(0, pt->s); // use size for more lines
516  pt->y = -pt->y - int(pt->mCos)*s.height() + int(pt->mSin)*s.width();
517  }
518 
519  int tmp = y1;
520  y1 = -y2; y2 = -tmp; // mirror boundings
521 
522  QFontMetrics metrics(QucsSettings.font); // get size of text
523  int dy = 0;
524  if(showName)
525  dy = metrics.lineSpacing(); // for "Name"
526  for(Property *pp = Props.first(); pp != 0; pp = Props.next())
527  if(pp->display) dy += metrics.lineSpacing();
528  if((tx > x1) && (tx < x2)) ty = -ty-dy; // mirror text position
529  else ty = y1+ty+y2;
530 
531  mirroredX = !mirroredX; // keep track of what's done
532  rotated += rotated << 1;
533  rotated &= 3;
534 }
535 
536 // -------------------------------------------------------
537 // Mirrors the component about the y-axis.
539 {
540  if(Ports.count() < 1) return; // do not rotate components without ports
541 
542  // mirror all lines
543  for(Line *p1 = Lines.first(); p1 != 0; p1 = Lines.next()) {
544  p1->x1 = -p1->x1;
545  p1->x2 = -p1->x2;
546  }
547 
548  // mirror all ports
549  for(Port *p2 = Ports.first(); p2 != 0; p2 = Ports.next())
550  p2->x = -p2->x;
551 
552  // mirror all arcs
553  for(Arc *p3 = Arcs.first(); p3 != 0; p3 = Arcs.next()) {
554  p3->x = -p3->x - p3->w;
555  p3->angle = 16*180 - p3->angle - p3->arclen; // mirror
556  if(p3->angle < 0) p3->angle += 16*360; // angle has to be > 0
557  }
558 
559  Area *pa;
560  // mirror all rectangles
561  for(pa = Rects.first(); pa != 0; pa = Rects.next())
562  pa->x = -pa->x - pa->w;
563 
564  // mirror all ellipses
565  for(pa = Ellips.first(); pa != 0; pa = Ellips.next())
566  pa->x = -pa->x - pa->w;
567 
568  int tmp;
569  QFont f = QucsSettings.font;
570  // mirror all text
571  for(Text *pt = Texts.first(); pt != 0; pt = Texts.next()) {
572  f.setPointSizeFloat(pt->Size);
573  QFontMetrics smallMetrics(f);
574  QSize s = smallMetrics.size(0, pt->s); // use size for more lines
575  pt->x = -pt->x - int(pt->mSin)*s.height() - int(pt->mCos)*s.width();
576  }
577 
578  tmp = x1;
579  x1 = -x2; x2 = -tmp; // mirror boundings
580 
581  QFontMetrics metrics(QucsSettings.font); // get size of text
582  int dx = 0;
583  if(showName)
584  dx = metrics.width(Name);
585  for(Property *pp = Props.first(); pp != 0; pp = Props.next())
586  if(pp->display) {
587  // get width of text
588  tmp = metrics.width(pp->Name+"="+pp->Value);
589  if(tmp > dx) dx = tmp;
590  }
591  if((ty > y1) && (ty < y2)) tx = -tx-dx; // mirror text position
592  else tx = x1+tx+x2;
593 
594  mirroredX = !mirroredX; // keep track of what's done
595  rotated += rotated << 1;
596  rotated += 2;
597  rotated &= 3;
598 }
599 
600 // -------------------------------------------------------
602 {
603  QString s = Model+":"+Name;
604 
605  // output all node names
606  for(Port *p1 = Ports.first(); p1 != 0; p1 = Ports.next())
607  s += " "+p1->Connection->Name; // node names
608 
609  // output all properties
610  for(Property *p2 = Props.first(); p2 != 0; p2 = Props.next())
611  if(p2->Name != "Symbol")
612  s += " "+p2->Name+"=\""+p2->Value+"\"";
613 
614  return s + '\n';
615 }
616 
617 // -------------------------------------------------------
619 {
620  switch(isActive) {
621  case COMP_IS_ACTIVE:
622  return netlist();
623  case COMP_IS_OPEN:
624  return QString("");
625  }
626 
627  // Component is shortened.
628  int z=0;
629  QString s;
630  QString Node1 = Ports.first()->Connection->Name;
631  for(Port *pp = Ports.next(); pp != 0; pp = Ports.next())
632  s += "R:" + Name + "." + QString::number(z++) + " " +
633  Node1 + " " + pp->Connection->Name + " R=\"0\"\n";
634  return s;
635 }
636 
637 // -------------------------------------------------------
639 {
640  return QString(""); // no digital model
641 }
642 
643 // -------------------------------------------------------
644 QString Component::get_Verilog_Code(int NumPorts)
645 {
646  switch(isActive) {
647  case COMP_IS_OPEN:
648  return QString("");
649  case COMP_IS_ACTIVE:
650  return verilogCode(NumPorts);
651  }
652 
653  // Component is shortened.
654  Port *p = Ports.first();
655  QString Node1 = p->Connection->Name;
656  QString s = "";
657  for(p = Ports.next(); p != 0; p = Ports.next())
658  s += " assign " + p->Connection->Name + " = " + Node1 + ";\n";
659  return s;
660 }
661 
662 // -------------------------------------------------------
664 {
665  return QString(""); // no digital model
666 }
667 
668 // -------------------------------------------------------
669 QString Component::get_VHDL_Code(int NumPorts)
670 {
671  switch(isActive) {
672  case COMP_IS_OPEN:
673  return QString("");
674  case COMP_IS_ACTIVE:
675  return vhdlCode(NumPorts);
676  }
677 
678  // Component is shortened.
679  // This puts the signal of the second port onto the first port.
680  // This is locigally correct for the inverter only, but makes
681  // some sense for the gates (OR, AND etc.).
682  // Has anyone a better idea?
683  QString Node1 = Ports.first()->Connection->Name;
684  return " " + Node1 + " <= " + Ports.next()->Connection->Name + ";\n";
685 }
686 
687 // -------------------------------------------------------
689 {
690 #if XML
691  QDomDocument doc;
692  QDomElement el = doc.createElement (Model);
693  doc.appendChild (el);
694  el.setTagName (Model);
695  el.setAttribute ("inst", Name.isEmpty() ? "*" : Name);
696  el.setAttribute ("display", isActive | (showName ? 4 : 0));
697  el.setAttribute ("cx", cx);
698  el.setAttribute ("cy", cy);
699  el.setAttribute ("tx", tx);
700  el.setAttribute ("ty", ty);
701  el.setAttribute ("mirror", mirroredX);
702  el.setAttribute ("rotate", rotated);
703 
704  for (Property *pr = Props.first(); pr != 0; pr = Props.next()) {
705  el.setAttribute (pr->Name, (pr->display ? "1@" : "0@") + pr->Value);
706  }
707  qDebug (doc.toString());
708 #endif
709  QString s = "<" + Model;
710 
711  if(Name.isEmpty()) s += " * ";
712  else s += " "+Name+" ";
713 
714  int i=0;
715  if(!showName)
716  i = 4;
717  i |= isActive;
718  s += QString::number(i);
719  s += " "+QString::number(cx)+" "+QString::number(cy);
720  s += " "+QString::number(tx)+" "+QString::number(ty);
721  if(mirroredX) s += " 1";
722  else s += " 0";
723  s += " "+QString::number(rotated);
724 
725  // write all properties
726  for(Property *p1 = Props.first(); p1 != 0; p1 = Props.next()) {
727  if(p1->Description.isEmpty())
728  s += " \""+p1->Name+"="+p1->Value+"\""; // e.g. for equations
729  else s += " \""+p1->Value+"\"";
730  if(p1->display) s += " 1";
731  else s += " 0";
732  }
733 
734  return s+">";
735 }
736 
737 // -------------------------------------------------------
738 bool Component::load(const QString& _s)
739 {
740  bool ok;
741  int ttx, tty, tmp;
742  QString s = _s;
743 
744  if(s.at(0) != '<') return false;
745  if(s.at(s.length()-1) != '>') return false;
746  s = s.mid(1, s.length()-2); // cut off start and end character
747 
748  QString n;
749  Name = s.section(' ',1,1); // Name
750  if(Name == "*") Name = "";
751 
752  n = s.section(' ',2,2); // isActive
753  tmp = n.toInt(&ok);
754  if(!ok) return false;
755  isActive = tmp & 3;
756 
757  if(tmp & 4)
758  showName = false;
759  else
760  showName = true;
761 
762  n = s.section(' ',3,3); // cx
763  cx = n.toInt(&ok);
764  if(!ok) return false;
765 
766  n = s.section(' ',4,4); // cy
767  cy = n.toInt(&ok);
768  if(!ok) return false;
769 
770  n = s.section(' ',5,5); // tx
771  ttx = n.toInt(&ok);
772  if(!ok) return false;
773 
774  n = s.section(' ',6,6); // ty
775  tty = n.toInt(&ok);
776  if(!ok) return false;
777 
778  if(Model.at(0) != '.') { // is simulation component (dc, ac, ...) ?
779 
780  n = s.section(' ',7,7); // mirroredX
781  if(n.toInt(&ok) == 1) mirrorX();
782  if(!ok) return false;
783 
784  n = s.section(' ',8,8); // rotated
785  tmp = n.toInt(&ok);
786  if(!ok) return false;
787  if(rotated > tmp) // neccessary because of historical flaw in ...
788  tmp += 4; // ... components like "volt_dc"
789  for(int z=rotated; z<tmp; z++) rotate();
790 
791  }
792 
793  tx = ttx; ty = tty; // restore text position (was changed by rotate/mirror)
794 
795  unsigned int z=0, counts = s.contains('"');
796  if(Model == "Sub")
797  tmp = 2; // first property (File) already exists
798  else if(Model == "Lib")
799  tmp = 3;
800  else if(Model == "EDD")
801  tmp = 5;
802  else if(Model == "RFEDD")
803  tmp = 8;
804  else if(Model == "VHDL")
805  tmp = 2;
806  else tmp = counts + 1; // "+1" because "counts" could be zero
807 
808  for(; tmp<=(int)counts/2; tmp++)
809  Props.append(new Property("p", "", true, " "));
810 
811  // load all properties
812  Property *p1;
813  for(p1 = Props.first(); p1 != 0; p1 = Props.next()) {
814  z++;
815  n = s.section('"',z,z); // property value
816  z++;
817  // not all properties have to be mentioned (backward compatible)
818  if(z > counts) {
819  if(p1->Description.isEmpty())
820  Props.remove(); // remove if allocated in vain
821 
822  if(Model == "Diode") {
823  if(counts < 56) { // backward compatible
824  counts >>= 1;
825  p1 = Props.at(counts-1);
826  for(; p1 != 0; p1 = Props.current()) {
827  if(counts-- < 19)
828  break;
829 
830  n = Props.prev()->Value;
831  p1->Value = n;
832  }
833 
834  p1 = Props.at(17);
835  p1->Value = Props.at(11)->Value;
836  Props.current()->Value = "0";
837  }
838  }
839  else if(Model == "AND" || Model == "NAND" || Model == "NOR" ||
840  Model == "OR" || Model == "XNOR"|| Model == "XOR") {
841  if(counts < 10) { // backward compatible
842  counts >>= 1;
843  p1 = Props.at(counts);
844  for(; p1 != 0; p1 = Props.current()) {
845  if(counts-- < 4)
846  break;
847  n = Props.prev()->Value;
848  p1->Value = n;
849  }
850  Props.current()->Value = "10";
851  }
852  }
853  else if(Model == "Buf" || Model == "Inv") {
854  if(counts < 8) { // backward compatible
855  counts >>= 1;
856  p1 = Props.at(counts);
857  for(; p1 != 0; p1 = Props.current()) {
858  if(counts-- < 3)
859  break;
860  n = Props.prev()->Value;
861  p1->Value = n;
862  }
863  Props.current()->Value = "10";
864  }
865  }
866 
867  return true;
868  }
869 
870  // for equations
871  if(Model != "EDD" && Model != "RFEDD" && Model != "RFEDD2P")
872  if(p1->Description.isEmpty()) { // unknown number of properties ?
873  p1->Name = n.section('=',0,0);
874  n = n.section('=',1);
875  // allocate memory for a new property (e.g. for equations)
876  if(Props.count() < (counts>>1)) {
877  Props.insert(z >> 1, new Property("y", "1", true));
878  Props.prev();
879  }
880  }
881  if(z == 6) if(counts == 6) // backward compatible
882  if(Model == "R") {
883  Props.getLast()->Value = n;
884  return true;
885  }
886  p1->Value = n;
887 
888  n = s.section('"',z,z); // display
889  p1->display = (n.at(1) == '1');
890  }
891 
892  return true;
893 }
894 
895 // *******************************************************************
896 // *** The following functions are used to load the schematic symbol
897 // *** from file. (e.g. subcircuit, library component)
898 
899 int Component::analyseLine(const QString& Row, int numProps)
900 {
901  QPen Pen;
902  QBrush Brush;
903  QColor Color;
904  QString s;
905  int i1, i2, i3, i4, i5, i6;
906 
907  s = Row.section(' ',0,0); // component type
908  if((s == "PortSym") || (s == ".PortSym")) { // backward compatible
909  if(!getIntegers(Row, &i1, &i2, &i3))
910  return -1;
911  for(i6 = Ports.count(); i6<i3; i6++) // if ports not in numerical order
912  Ports.append(new Port(0, 0, false));
913 
914  Ports.at(i3-1)->x = i1;
915  Ports.current()->y = i2;
916  Ports.current()->avail = true;
917 
918  if(i1 < x1) x1 = i1; // keep track of component boundings
919  if(i1 > x2) x2 = i1;
920  if(i2 < y1) y1 = i2;
921  if(i2 > y2) y2 = i2;
922  return 0; // do not count Ports
923  }
924  else if(s == "Line") {
925  if(!getIntegers(Row, &i1, &i2, &i3, &i4)) return -1;
926  if(!getPen(Row, Pen, 5)) return -1;
927  i3 += i1;
928  i4 += i2;
929  Lines.append(new Line(i1, i2, i3, i4, Pen));
930 
931  if(i1 < x1) x1 = i1; // keep track of component boundings
932  if(i1 > x2) x2 = i1;
933  if(i2 < y1) y1 = i2;
934  if(i2 > y2) y2 = i2;
935  if(i3 < x1) x1 = i3;
936  if(i3 > x2) x2 = i3;
937  if(i4 < y1) y1 = i4;
938  if(i4 > y2) y2 = i4;
939  return 1;
940  }
941  else if(s == "EArc") {
942  if(!getIntegers(Row, &i1, &i2, &i3, &i4, &i5, &i6))
943  return -1;
944  if(!getPen(Row, Pen, 7)) return -1;
945  Arcs.append(new struct Arc(i1, i2, i3, i4, i5, i6, Pen));
946 
947  if(i1 < x1) x1 = i1; // keep track of component boundings
948  if(i1+i3 > x2) x2 = i1+i3;
949  if(i2 < y1) y1 = i2;
950  if(i2+i4 > y2) y2 = i2+i4;
951  return 1;
952  }
953  else if(s == ".ID") {
954  if(!getIntegers(Row, &i1, &i2)) return -1;
955  tx = i1;
956  ty = i2;
957  Name = Row.section(' ',3,3);
958  if(Name.isEmpty()) Name = "SUB";
959 
960  i1 = 1;
961  Property *pp = Props.at(numProps-1);
962  for(;;) {
963  s = Row.section('"', i1,i1);
964  if(s.isEmpty()) break;
965 
966  pp = Props.next();
967  if(pp == 0) {
968  pp = new Property();
969  Props.append(pp);
970 
971  pp->display = (s.at(0) == '1');
972  pp->Value = s.section('=', 2,2);
973  }
974 
975  pp->Name = s.section('=', 1,1);
976  pp->Description = s.section('=', 3,3);
977  if(pp->Description.isEmpty())
978  pp->Description = " ";
979 
980  i1 += 2;
981  }
982 
983  while(pp != Props.last())
984  Props.remove();
985  return 0; // do not count IDs
986  }
987  else if(s == "Arrow") {
988  if(!getIntegers(Row, &i1, &i2, &i3, &i4, &i5, &i6)) return -1;
989  if(!getPen(Row, Pen, 7)) return -1;
990 
991  double beta = atan2(double(i6), double(i5));
992  double phi = atan2(double(i4), double(i3));
993  double Length = sqrt(double(i6*i6 + i5*i5));
994 
995  i3 += i1;
996  i4 += i2;
997  if(i1 < x1) x1 = i1; // keep track of component boundings
998  if(i1 > x2) x2 = i1;
999  if(i3 < x1) x1 = i3;
1000  if(i3 > x2) x2 = i3;
1001  if(i2 < y1) y1 = i2;
1002  if(i2 > y2) y2 = i2;
1003  if(i4 < y1) y1 = i4;
1004  if(i4 > y2) y2 = i4;
1005 
1006  Lines.append(new Line(i1, i2, i3, i4, Pen)); // base line
1007 
1008  double w = beta+phi;
1009  i5 = i3-int(Length*cos(w));
1010  i6 = i4-int(Length*sin(w));
1011  Lines.append(new Line(i3, i4, i5, i6, Pen)); // arrow head
1012  if(i5 < x1) x1 = i5; // keep track of component boundings
1013  if(i5 > x2) x2 = i5;
1014  if(i6 < y1) y1 = i6;
1015  if(i6 > y2) y2 = i6;
1016 
1017  w = phi-beta;
1018  i5 = i3-int(Length*cos(w));
1019  i6 = i4-int(Length*sin(w));
1020  Lines.append(new Line(i3, i4, i5, i6, Pen));
1021  if(i5 < x1) x1 = i5; // keep track of component boundings
1022  if(i5 > x2) x2 = i5;
1023  if(i6 < y1) y1 = i6;
1024  if(i6 > y2) y2 = i6;
1025 
1026  return 1;
1027  }
1028  else if(s == "Ellipse") {
1029  if(!getIntegers(Row, &i1, &i2, &i3, &i4)) return -1;
1030  if(!getPen(Row, Pen, 5)) return -1;
1031  if(!getBrush(Row, Brush, 8)) return -1;
1032  Ellips.append(new Area(i1, i2, i3, i4, Pen, Brush));
1033 
1034  if(i1 < x1) x1 = i1; // keep track of component boundings
1035  if(i1 > x2) x2 = i1;
1036  if(i2 < y1) y1 = i2;
1037  if(i2 > y2) y2 = i2;
1038  if(i1+i3 < x1) x1 = i1+i3;
1039  if(i1+i3 > x2) x2 = i1+i3;
1040  if(i2+i4 < y1) y1 = i2+i4;
1041  if(i2+i4 > y2) y2 = i2+i4;
1042  return 1;
1043  }
1044  else if(s == "Rectangle") {
1045  if(!getIntegers(Row, &i1, &i2, &i3, &i4)) return -1;
1046  if(!getPen(Row, Pen, 5)) return -1;
1047  if(!getBrush(Row, Brush, 8)) return -1;
1048  Rects.append(new Area(i1, i2, i3, i4, Pen, Brush));
1049 
1050  if(i1 < x1) x1 = i1; // keep track of component boundings
1051  if(i1 > x2) x2 = i1;
1052  if(i2 < y1) y1 = i2;
1053  if(i2 > y2) y2 = i2;
1054  if(i1+i3 < x1) x1 = i1+i3;
1055  if(i1+i3 > x2) x2 = i1+i3;
1056  if(i2+i4 < y1) y1 = i2+i4;
1057  if(i2+i4 > y2) y2 = i2+i4;
1058  return 1;
1059  }
1060  else if(s == "Text") { // must be last in order to reuse "s" *********
1061  if(!getIntegers(Row, &i1, &i2, &i3, 0, &i4)) return -1;
1062  Color.setNamedColor(Row.section(' ',4,4));
1063  if(!Color.isValid()) return -1;
1064 
1065  s = Row.mid(Row.find('"')+1); // Text (can contain " !!!)
1066  s = s.left(s.length()-1);
1067  if(s.isEmpty()) return -1;
1068  convert2Unicode(s);
1069 
1070  Texts.append(new Text(i1, i2, s, Color, float(i3),
1071  float(cos(float(i4)*M_PI/180.0)),
1072  float(sin(float(i4)*M_PI/180.0))));
1073 
1074  QFont Font(QucsSettings.font);
1075  Font.setPointSizeFloat(float(i3));
1076  QFontMetrics metrics(Font);
1077  QSize r = metrics.size(0, s); // get size of text
1078  i3 = i1 + int(float(r.width()) * Texts.current()->mCos)
1079  + int(float(r.height()) * Texts.current()->mSin);
1080  i4 = i2 + int(float(r.width()) * -Texts.current()->mSin)
1081  + int(float(r.height()) * Texts.current()->mCos);
1082 
1083  if(i1 < x1) x1 = i1; // keep track of component boundings
1084  if(i2 < y1) y1 = i2;
1085  if(i1 > x2) x2 = i1;
1086  if(i2 > y2) y2 = i2;
1087 
1088  if(i3 < x1) x1 = i3;
1089  if(i4 < y1) y1 = i4;
1090  if(i3 > x2) x2 = i3;
1091  if(i4 > y2) y2 = i4;
1092  return 1;
1093  }
1094 
1095  return 0;
1096 }
1097 
1098 // ---------------------------------------------------------------------
1099 bool Component::getIntegers(const QString& s, int *i1, int *i2, int *i3,
1100  int *i4, int *i5, int *i6)
1101 {
1102  bool ok;
1103  QString n;
1104 
1105  if(!i1) return true;
1106  n = s.section(' ',1,1);
1107  *i1 = n.toInt(&ok);
1108  if(!ok) return false;
1109 
1110  if(!i2) return true;
1111  n = s.section(' ',2,2);
1112  *i2 = n.toInt(&ok);
1113  if(!ok) return false;
1114 
1115  if(!i3) return true;
1116  n = s.section(' ',3,3);
1117  *i3 = n.toInt(&ok);
1118  if(!ok) return false;
1119 
1120  if(i4) {
1121  n = s.section(' ',4,4);
1122  *i4 = n.toInt(&ok);
1123  if(!ok) return false;
1124  }
1125 
1126  if(!i5) return true;
1127  n = s.section(' ',5,5);
1128  *i5 = n.toInt(&ok);
1129  if(!ok) return false;
1130 
1131  if(!i6) return true;
1132  n = s.section(' ',6,6);
1133  *i6 = n.toInt(&ok);
1134  if(!ok) return false;
1135 
1136  return true;
1137 }
1138 
1139 // ---------------------------------------------------------------------
1140 bool Component::getPen(const QString& s, QPen& Pen, int i)
1141 {
1142  bool ok;
1143  QString n;
1144 
1145  n = s.section(' ',i,i); // color
1146  QColor co;
1147  co.setNamedColor(n);
1148  Pen.setColor(co);
1149  if(!Pen.color().isValid()) return false;
1150 
1151  i++;
1152  n = s.section(' ',i,i); // thickness
1153  Pen.setWidth(n.toInt(&ok));
1154  if(!ok) return false;
1155 
1156  i++;
1157  n = s.section(' ',i,i); // line style
1158  Pen.setStyle((Qt::PenStyle)n.toInt(&ok));
1159  if(!ok) return false;
1160 
1161  return true;
1162 }
1163 
1164 // ---------------------------------------------------------------------
1165 bool Component::getBrush(const QString& s, QBrush& Brush, int i)
1166 {
1167  bool ok;
1168  QString n;
1169 
1170  n = s.section(' ',i,i); // fill color
1171  QColor co;
1172  co.setNamedColor(n);
1173  Brush.setColor(co);
1174  if(!Brush.color().isValid()) return false;
1175 
1176  i++;
1177  n = s.section(' ',i,i); // fill style
1178  Brush.setStyle((Qt::BrushStyle)n.toInt(&ok));
1179  if(!ok) return false;
1180 
1181  i++;
1182  n = s.section(' ',i,i); // filled
1183  if(n.toInt(&ok) == 0) Brush.setStyle(QBrush::NoBrush);
1184  if(!ok) return false;
1185 
1186  return true;
1187 }
1188 
1189 // ---------------------------------------------------------------------
1190 Property * Component::getProperty(const QString& name)
1191 {
1192  for(Property *pp = Props.first(); pp != 0; pp = Props.next())
1193  if(pp->Name == name) {
1194  return pp;
1195  }
1196  return NULL;
1197 }
1198 
1199 // ---------------------------------------------------------------------
1201 {
1202  Type = pc->Type;
1203  x1 = pc->x1;
1204  y1 = pc->y1;
1205  x2 = pc->x2;
1206  y2 = pc->y2;
1207 
1208  Model = pc->Model;
1209  Name = pc->Name;
1210  showName = pc->showName;
1211  Description = pc->Description;
1212 
1213  isActive = pc->isActive;
1214  rotated = pc->rotated;
1215  mirroredX = pc->mirroredX;
1216  tx = pc->tx;
1217  ty = pc->ty;
1218 
1219  Props = pc->Props;
1220  Ports = pc->Ports;
1221  Lines = pc->Lines;
1222  Arcs = pc->Arcs;
1223  Rects = pc->Rects;
1224  Ellips = pc->Ellips;
1225  Texts = pc->Texts;
1226 }
1227 
1228 
1229 // ***********************************************************************
1230 // ******** ********
1231 // ******** Functions of class MultiViewComponent ********
1232 // ******** ********
1233 // ***********************************************************************
1235 {
1236  if(Doc) {
1237  Doc->Components->setAutoDelete(false);
1238  Doc->deleteComp(this);
1239  }
1240 
1241  Ellips.clear();
1242  Texts.clear();
1243  Ports.clear();
1244  Lines.clear();
1245  Rects.clear();
1246  Arcs.clear();
1247  createSymbol();
1248 
1249  bool mmir = mirroredX;
1250  int rrot = rotated;
1251  if(mmir) mirrorX(); // mirror
1252  for(int z=0; z<rrot; z++) rotate(); // rotate
1253 
1254  rotated = rrot; // restore properties (were changed by rotate/mirror)
1255  mirroredX = mmir;
1256 
1257  if(Doc) {
1258  Doc->insertRawComponent(this);
1259  Doc->Components->setAutoDelete(true);
1260  }
1261 }
1262 
1263 
1264 // ***********************************************************************
1265 // ******** ********
1266 // ******** Functions of class GateComponent ********
1267 // ******** ********
1268 // ***********************************************************************
1270 {
1271  Type = isComponent; // both analog and digital
1272  Name = "Y";
1273 
1274  // the list order must be preserved !!!
1275  Props.append(new Property("in", "2", false,
1276  QObject::tr("number of input ports")));
1277  Props.append(new Property("V", "1 V", false,
1278  QObject::tr("voltage of high level")));
1279  Props.append(new Property("t", "0", false,
1280  QObject::tr("delay time")));
1281  Props.append(new Property("TR", "10", false,
1282  QObject::tr("transfer function scaling factor")));
1283 
1284  // this must be the last property in the list !!!
1285  Props.append(new Property("Symbol", "old", false,
1286  QObject::tr("schematic symbol")+" [old, DIN40900]"));
1287 }
1288 
1289 // -------------------------------------------------------
1291 {
1292  QString s = Model+":"+Name;
1293 
1294  // output all node names
1295  for(Port *pp = Ports.first(); pp != 0; pp = Ports.next())
1296  s += " "+pp->Connection->Name; // node names
1297 
1298  // output all properties
1299  Property *p = Props.at(1);
1300  s += " " + p->Name + "=\"" + p->Value + "\"";
1301  p = Props.next();
1302  s += " " + p->Name + "=\"" + p->Value + "\"";
1303  p = Props.next();
1304  s += " " + p->Name + "=\"" + p->Value + "\"\n";
1305  return s;
1306 }
1307 
1308 // -------------------------------------------------------
1309 QString GateComponent::vhdlCode(int NumPorts)
1310 {
1311  Port *pp = Ports.first();
1312  QString s = " " + pp->Connection->Name + " <= "; // output port
1313 
1314  // xnor NOT defined for std_logic, so here use not and xor
1315  if (Model == "XNOR") {
1316  QString Op = " xor ";
1317 
1318  // first input port
1319  pp = Ports.next();
1320  QString rhs = pp->Connection->Name;
1321 
1322  // output all input ports with node names
1323  for (pp = Ports.next (); pp != 0; pp = Ports.next ())
1324  rhs = "not ((" + rhs + ")" + Op + pp->Connection->Name + ")";
1325  s += rhs;
1326  }
1327  else {
1328  QString Op = ' ' + Model.lower() + ' ';
1329  if(Model.at(0) == 'N') {
1330  s += "not ("; // nor, nand is NOT assoziative !!! but xnor is !!!
1331  Op = Op.remove(1, 1);
1332  }
1333 
1334  pp = Ports.next();
1335  s += pp->Connection->Name; // first input port
1336 
1337  // output all input ports with node names
1338  for(pp = Ports.next(); pp != 0; pp = Ports.next())
1339  s += Op + pp->Connection->Name;
1340  if(Model.at(0) == 'N')
1341  s += ')';
1342  }
1343 
1344  if(NumPorts <= 0) { // no truth table simulation ?
1345  QString td = Props.at(2)->Value; // delay time
1346  if(!VHDL_Delay(td, Name)) return td;
1347  s += td;
1348  }
1349 
1350  s += ";\n";
1351  return s;
1352 }
1353 
1354 // -------------------------------------------------------
1355 QString GateComponent::verilogCode(int NumPorts)
1356 {
1357  bool synthesize = true;
1358  Port *pp = Ports.first();
1359  QString s("");
1360 
1361  if(synthesize) {
1362  QString op = Model.lower();
1363  if(op == "and" || op == "nand")
1364  op = "&";
1365  else if (op == "or" || op == "nor")
1366  op = "|";
1367  else if (op == "xor")
1368  op = "^";
1369  else if (op == "xnor")
1370  op = "^~";
1371 
1372  s = " assign";
1373 
1374  if(NumPorts <= 0) { // no truth table simulation ?
1375  QString td = Props.at(2)->Value; // delay time
1376  if(!Verilog_Delay(td, Name)) return td;
1377  s += td;
1378  }
1379  s += " " + pp->Connection->Name + " = "; // output port
1380  if(Model.at(0) == 'N') s += "~(";
1381 
1382  pp = Ports.next();
1383  s += pp->Connection->Name; // first input port
1384 
1385  // output all input ports with node names
1386  for(pp = Ports.next(); pp != 0; pp = Ports.next())
1387  s += " " + op + " " + pp->Connection->Name;
1388 
1389  if(Model.at(0) == 'N') s += ")";
1390  s += ";\n";
1391  }
1392  else {
1393  s = " " + Model.lower();
1394 
1395  if(NumPorts <= 0) { // no truth table simulation ?
1396  QString td = Props.at(2)->Value; // delay time
1397  if(!Verilog_Delay(td, Name)) return td;
1398  s += td;
1399  }
1400  s += " " + Name + " (" + pp->Connection->Name; // output port
1401 
1402  pp = Ports.next();
1403  s += ", " + pp->Connection->Name; // first input port
1404 
1405  // output all input ports with node names
1406  for(pp = Ports.next(); pp != 0; pp = Ports.next())
1407  s += ", " + pp->Connection->Name;
1408 
1409  s += ");\n";
1410  }
1411  return s;
1412 }
1413 
1414 // -------------------------------------------------------
1416 {
1417  int Num = Props.getFirst()->Value.toInt();
1418  if(Num < 2) Num = 2;
1419  else if(Num > 8) Num = 8;
1420  Props.getFirst()->Value = QString::number(Num);
1421 
1422  int xl, xr, y = 10*Num, z;
1423  x1 = -30; y1 = -y-3;
1424  x2 = 30; y2 = y+3;
1425 
1426  tx = x1+4;
1427  ty = y2+4;
1428 
1429  z = 0;
1430  if(Model.at(0) == 'N') z = 1;
1431 
1432  if(Props.getLast()->Value.at(0) == 'D') { // DIN symbol
1433  xl = -15;
1434  xr = 15;
1435  Lines.append(new Line( 15,-y, 15, y,QPen(QPen::darkBlue,2)));
1436  Lines.append(new Line(-15,-y, 15,-y,QPen(QPen::darkBlue,2)));
1437  Lines.append(new Line(-15, y, 15, y,QPen(QPen::darkBlue,2)));
1438  Lines.append(new Line(-15,-y,-15, y,QPen(QPen::darkBlue,2)));
1439  Lines.append(new Line( 15, 0, 30, 0,QPen(QPen::darkBlue,2)));
1440 
1441  if(Model.at(z) == 'O') {
1442  Lines.append(new Line(-11, 6-y,-6, 9-y,QPen(QPen::darkBlue,0)));
1443  Lines.append(new Line(-11,12-y,-6, 9-y,QPen(QPen::darkBlue,0)));
1444  Lines.append(new Line(-11,14-y,-6,14-y,QPen(QPen::darkBlue,0)));
1445  Lines.append(new Line(-11,16-y,-6,16-y,QPen(QPen::darkBlue,0)));
1446  Texts.append(new Text( -4, 3-y, "1", QPen::darkBlue, 15.0));
1447  }
1448  else if(Model.at(z) == 'A')
1449  Texts.append(new Text( -10, 3-y, "&", QPen::darkBlue, 15.0));
1450  else if(Model.at(0) == 'X') {
1451  if(Model.at(1) == 'N') {
1452  Ellips.append(new Area(xr,-4, 8, 8,
1453  QPen(QPen::darkBlue,0), QBrush(QPen::darkBlue)));
1454  Texts.append(new Text( -11, 3-y, "=1", QPen::darkBlue, 15.0));
1455  }
1456  else
1457  Texts.append(new Text( -11, 3-y, "=1", QPen::darkBlue, 15.0));
1458  }
1459  }
1460  else { // old symbol
1461 
1462  if(Model.at(z) == 'O') xl = 10;
1463  else xl = -10;
1464  xr = 10;
1465  Lines.append(new Line(-10,-y,-10, y,QPen(QPen::darkBlue,2)));
1466  Lines.append(new Line( 10, 0, 30, 0,QPen(QPen::darkBlue,2)));
1467  Arcs.append(new Arc(-30,-y, 40, 30, 0, 16*90,QPen(QPen::darkBlue,2)));
1468  Arcs.append(new Arc(-30,y-30, 40, 30, 0,-16*90,QPen(QPen::darkBlue,2)));
1469  Lines.append(new Line( 10,15-y, 10, y-15,QPen(QPen::darkBlue,2)));
1470 
1471  if(Model.at(0) == 'X') {
1472  Lines.append(new Line(-5, 0, 5, 0,QPen(QPen::darkBlue,1)));
1473  if(Model.at(1) == 'N') {
1474  Lines.append(new Line(-5,-3, 5,-3,QPen(QPen::darkBlue,1)));
1475  Lines.append(new Line(-5, 3, 5, 3,QPen(QPen::darkBlue,1)));
1476  }
1477  else {
1478  Arcs.append(new Arc(-5,-5, 10, 10, 0, 16*360,QPen(QPen::darkBlue,1)));
1479  Lines.append(new Line( 0,-5, 0, 5,QPen(QPen::darkBlue,1)));
1480  }
1481  }
1482  }
1483 
1484  if(Model.at(0) == 'N')
1485  Ellips.append(new Area(xr,-4, 8, 8,
1486  QPen(QPen::darkBlue,0), QBrush(QPen::darkBlue)));
1487 
1488  Ports.append(new Port( 30, 0));
1489  y += 10;
1490  for(z=0; z<Num; z++) {
1491  y -= 20;
1492  Ports.append(new Port(-30, y));
1493  if(xl == 10) if((z == 0) || (z == Num-1)) {
1494  Lines.append(new Line(-30, y, 9, y,QPen(QPen::darkBlue,2)));
1495  continue;
1496  }
1497  Lines.append(new Line(-30, y, xl, y,QPen(QPen::darkBlue,2)));
1498  }
1499 }
1500 
1501 
1502 // ***********************************************************************
1503 // ******** ********
1504 // ******** The following function does not below to any class. ********
1505 // ******** It creates a component by getting the identification ********
1506 // ******** string used in the schematic file and for copy/paste. ********
1507 // ******** ********
1508 // ***********************************************************************
1509 
1511 {
1512  Component *c = 0;
1513 
1514  Line = Line.stripWhiteSpace();
1515  if(Line.at(0) != '<') {
1516  QMessageBox::critical(0, QObject::tr("Error"),
1517  QObject::tr("Format Error:\nWrong line start!"));
1518  return 0;
1519  }
1520 
1521  QString cstr = Line.section (' ',0,0); // component type
1522  cstr.remove (0,1); // remove leading "<"
1523  if (cstr == "Lib") c = new LibComp ();
1524  else if (cstr == "Eqn") c = new Equation ();
1525  else if (cstr == "Rus") c = new Resistor (false); // backward compatible
1526  else if (cstr.left (6) == "SPfile" && cstr != "SPfile") {
1527  // backward compatible
1528  c = new SParamFile ();
1529  c->Props.getLast()->Value = cstr.mid (6); }
1530  else
1531  c = Module::getComponent (cstr);
1532 
1533  if(!c) {
1534  QMessageBox::critical(0, QObject::tr("Error"),
1535  QObject::tr("Format Error:\nUnknown component!"));
1536  return 0;
1537  }
1538 
1539  if(!c->load(Line)) {
1540  QMessageBox::critical(0, QObject::tr("Error"),
1541  QObject::tr("Format Error:\nWrong 'component' line format!"));
1542  delete c;
1543  return 0;
1544  }
1545 
1546  cstr = c->Name; // is perhaps changed in "recreate" (e.g. subcircuit)
1547  int x = c->tx, y = c->ty;
1548  c->recreate(0);
1549  c->Name = cstr;
1550  c->tx = x; c->ty = y;
1551  return c;
1552 }