Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/components/component.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                                component.cpp
00003                               ---------------
00004     begin                : Sat Aug 23 2003
00005     copyright            : (C) 2003 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 #include <stdlib.h>
00018 #include <cmath>
00019 
00020 #include "components.h"
00021 #include "node.h"
00022 #include "main.h"
00023 #include "qucs.h"
00024 #include "schematic.h"
00025 #include "viewpainter.h"
00026 #include "module.h"
00027 #include "misc.h"
00028 
00029 #include <QPen>
00030 #include <QString>
00031 #include <QMessageBox>
00032 #include <QPainter>
00033 #include <QDebug>
00034 
00045 Component::Component()
00046 {
00047   Type = isAnalogComponent;
00048 
00049   mirroredX = false;
00050   rotated = 0;
00051   isSelected = false;
00052   isActive = COMP_IS_ACTIVE;
00053   showName = true;
00054 
00055   cx = 0;
00056   cy = 0;
00057   tx = 0;
00058   ty = 0;
00059 
00060   Props.setAutoDelete(true);
00061 
00062   containingSchematic = NULL;
00063 }
00064 
00065 // -------------------------------------------------------
00066 Component* Component::newOne()
00067 {
00068   return new Component();
00069 }
00070 
00071 // -------------------------------------------------------
00072 void Component::Bounding(int& _x1, int& _y1, int& _x2, int& _y2)
00073 {
00074   _x1 = x1+cx;
00075   _y1 = y1+cy;
00076   _x2 = x2+cx;
00077   _y2 = y2+cy;
00078 }
00079 
00080 // -------------------------------------------------------
00081 // Size of component text.
00082 int Component::textSize(int& _dx, int& _dy)
00083 {
00084   // get size of text using the screen-compatible metric
00085   QFontMetrics metrics(QucsSettings.font, 0);
00086 
00087   int tmp, count=0;
00088   _dx = _dy = 0;
00089   if(showName) {
00090     _dx = metrics.width(Name);
00091     _dy = metrics.height();
00092     count++;
00093   }
00094   for(Property *pp = Props.first(); pp != 0; pp = Props.next())
00095     if(pp->display) {
00096       // get width of text
00097       tmp = metrics.width(pp->Name+"="+pp->Value);
00098       if(tmp > _dx)  _dx = tmp;
00099       _dy += metrics.height();
00100       count++;
00101     }
00102   return count;
00103 }
00104 
00105 // -------------------------------------------------------
00106 // Boundings including the component text.
00107 void Component::entireBounds(int& _x1, int& _y1, int& _x2, int& _y2, float Corr)
00108 {
00109   _x1 = x1+cx;
00110   _y1 = y1+cy;
00111   _x2 = x2+cx;
00112   _y2 = y2+cy;
00113 
00114   // text boundings
00115   if(tx < x1) _x1 = tx+cx;
00116   if(ty < y1) _y1 = ty+cy;
00117 
00118   int dx, dy, ny;
00119   ny = textSize(dx, dy);
00120   dy = int(float(ny) / Corr);  // correction for unproportional font scaling
00121 
00122   if((tx+dx) > x2) _x2 = tx+dx+cx;
00123   if((ty+dy) > y2) _y2 = ty+dy+cy;
00124 }
00125 
00126 // -------------------------------------------------------
00127 void Component::setCenter(int x, int y, bool relative)
00128 {
00129   if(relative) { cx += x;  cy += y; }
00130   else { cx = x;  cy = y; }
00131 }
00132 
00133 // -------------------------------------------------------
00134 void Component::getCenter(int& x, int& y)
00135 {
00136   x = cx;
00137   y = cy;
00138 }
00139 
00140 // -------------------------------------------------------
00141 int Component::getTextSelected(int x_, int y_, float Corr)
00142 {
00143   x_ -= cx;
00144   y_ -= cy;
00145   if(x_ < tx) return -1;
00146   if(y_ < ty) return -1;
00147 
00148   x_ -= tx;
00149   y_ -= ty;
00150   int w, dy = int(float(y_) * Corr);  // correction for font scaling
00151   // use the screen-compatible metric
00152   QFontMetrics  metrics(QucsSettings.font, 0);
00153   if(showName) {
00154     w  = metrics.width(Name);
00155     if(dy < 1) {
00156       if(x_ < w) return 0;
00157       return -1;
00158     }
00159     dy--;
00160   }
00161 
00162   Property *pp;
00163   for(pp = Props.first(); pp != 0; pp = Props.next())
00164     if(pp->display)
00165       if((dy--) < 1) break;
00166   if(!pp) return -1;
00167 
00168   // get width of text
00169   w = metrics.width(pp->Name+"="+pp->Value);
00170   if(x_ > w) return -1; // clicked past the property text end - selection invalid
00171   return Props.at()+1;  // number the property
00172 }
00173 
00174 // -------------------------------------------------------
00175 bool Component::getSelected(int x_, int y_)
00176 {
00177   x_ -= cx;
00178   y_ -= cy;
00179   if(x_ >= x1) if(x_ <= x2) if(y_ >= y1) if(y_ <= y2)
00180     return true;
00181 
00182   return false;
00183 }
00184 
00185 // -------------------------------------------------------
00186 void Component::paint(ViewPainter *p)
00187 {
00188   int x, y, a, b, xb, yb;
00189   QFont f = p->Painter->font();   // save current font
00190   QFont newFont = f;
00191   if(Model.at(0) == '.') {   // is simulation component (dc, ac, ...)
00192     newFont.setPointSizeF(p->Scale * Texts.first()->Size);
00193     newFont.setWeight(QFont::DemiBold);
00194     p->Painter->setFont(newFont);
00195     p->map(cx, cy, x, y);
00196 
00197     p->Painter->setPen(QPen(Qt::darkBlue,2));
00198     a = b = 0;
00199     QRect r, t;
00200     foreach(Text *pt, Texts) {
00201       t.setRect(x, y+b, 0, 0);
00202       p->Painter->drawText(t, Qt::AlignLeft|Qt::TextDontClip, pt->s, &r);
00203       b += r.height();
00204       if(a < r.width())  a = r.width();
00205     }
00206     xb = a + int(12.0*p->Scale);
00207     yb = b + int(10.0*p->Scale);
00208     x2 = x1+25 + int(float(a) / p->Scale);
00209     y2 = y1+23 + int(float(b) / p->Scale);
00210     if(ty < y2+1) if(ty > y1-r.height())  ty = y2 + 1;
00211 
00212     p->map(cx-1, cy, x, y);
00213     p->map(cx-6, cy-5, a, b);
00214     p->Painter->drawRect(a, b, xb, yb);
00215     p->Painter->drawLine(x,      y+yb, a,      b+yb);
00216     p->Painter->drawLine(x+xb-1, y+yb, x,      y+yb);
00217     p->Painter->drawLine(x+xb-1, y+yb, a+xb,   b+yb);
00218     p->Painter->drawLine(x+xb-1, y+yb, x+xb-1, y);
00219     p->Painter->drawLine(x+xb-1, y,    a+xb,   b);
00220   }
00221   else {    // normal components go here
00222 
00223     // paint all lines
00224     foreach(Line *p1, Lines) {
00225       p->Painter->setPen(p1->style);
00226       p->drawLine(cx+p1->x1, cy+p1->y1, cx+p1->x2, cy+p1->y2);
00227     }
00228 
00229     // paint all arcs
00230     foreach(Arc *p3, Arcs) {
00231       p->Painter->setPen(p3->style);
00232       p->drawArc(cx+p3->x, cy+p3->y, p3->w, p3->h, p3->angle, p3->arclen);
00233     }
00234 
00235     // paint all rectangles
00236     foreach(Area *pa, Rects) {
00237       p->Painter->setPen(pa->Pen);
00238       p->Painter->setBrush(pa->Brush);
00239       p->drawRect(cx+pa->x, cy+pa->y, pa->w, pa->h);
00240     }
00241 
00242     // paint all ellipses
00243     foreach(Area *pa, Ellips) {
00244       p->Painter->setPen(pa->Pen);
00245       p->Painter->setBrush(pa->Brush);
00246       p->drawEllipse(cx+pa->x, cy+pa->y, pa->w, pa->h);
00247     }
00248     p->Painter->setBrush(Qt::NoBrush);
00249 
00250     newFont.setWeight(QFont::Light);
00251 
00252     // keep track of painter state
00253     p->Painter->save();
00254 
00255     QMatrix wm = p->Painter->worldMatrix();
00256     // write all text
00257     foreach(Text *pt, Texts) {
00258       p->Painter->setWorldMatrix(
00259           QMatrix(pt->mCos, -pt->mSin, pt->mSin, pt->mCos,
00260                    p->DX + float(cx+pt->x) * p->Scale,
00261                    p->DY + float(cy+pt->y) * p->Scale));
00262       newFont.setPointSizeF(p->Scale * pt->Size);
00263       newFont.setOverline(pt->over);
00264       newFont.setUnderline(pt->under);
00265       p->Painter->setFont(newFont);
00266       p->Painter->setPen(pt->Color);
00267       if (0) {
00268   p->Painter->drawText(0, 0, 0, 0, Qt::AlignLeft|Qt::TextDontClip, pt->s);
00269       } else {
00270   int w, h;
00271   w = p->drawTextMapped (pt->s, 0, 0, &h);
00272     Q_UNUSED(w);
00273       }
00274     }
00275     p->Painter->setWorldMatrix(wm);
00276     p->Painter->setWorldMatrixEnabled(false);
00277 
00278     // restore painter state
00279     p->Painter->restore();
00280   }
00281 
00282   // restore old font
00283   p->Painter->setFont(f);
00284 
00285   p->Painter->setPen(QPen(Qt::black,1));
00286   p->map(cx+tx, cy+ty, x, y);
00287   if(showName) {
00288     p->Painter->drawText(x, y, 0, 0, Qt::TextDontClip, Name);
00289     y += p->LineSpacing;
00290   }
00291   // write all properties
00292   for(Property *p4 = Props.first(); p4 != 0; p4 = Props.next())
00293     if(p4->display) {
00294       p->Painter->drawText(x, y, 0, 0, Qt::TextDontClip, p4->Name+"="+p4->Value);
00295       y += p->LineSpacing;
00296     }
00297 
00298   if(isActive == COMP_IS_OPEN)
00299     p->Painter->setPen(QPen(Qt::red,0));
00300   else if(isActive & COMP_IS_SHORTEN)
00301     p->Painter->setPen(QPen(Qt::darkGreen,0));
00302   if(isActive != COMP_IS_ACTIVE) {
00303     p->drawRect(cx+x1, cy+y1, x2-x1+1, y2-y1+1);
00304     p->drawLine(cx+x1, cy+y1, cx+x2, cy+y2);
00305     p->drawLine(cx+x1, cy+y2, cx+x2, cy+y1);
00306   }
00307 
00308   // draw component bounding box
00309   if(isSelected) {
00310     p->Painter->setPen(QPen(Qt::darkGray,3));
00311     p->drawRoundRect(cx+x1, cy+y1, x2-x1, y2-y1);
00312   }
00313 }
00314 
00315 // -------------------------------------------------------
00316 // Paints the component when moved with the mouse.
00317 void Component::paintScheme(Schematic *p)
00318 {
00319   // qDebug() << "paintScheme" << Model;
00320   if(Model.at(0) == '.') {   // is simulation component (dc, ac, ...)
00321     int a, b, xb, yb;
00322     QFont newFont = p->font();
00323 
00324     float Scale =
00325           ((Schematic*)QucsMain->DocumentTab->currentWidget())->Scale;
00326     newFont.setPointSizeF(float(Scale) * QucsSettings.largeFontSize);
00327     newFont.setWeight(QFont::DemiBold);
00328     // here the font metric is already the screen metric, since the font
00329     // is the current font the painter is using
00330     QFontMetrics  metrics(newFont);
00331 
00332     a = b = 0;
00333     QSize r;
00334     foreach(Text *pt, Texts) {
00335       r = metrics.size(0, pt->s);
00336       b += r.height();
00337       if(a < r.width())  a = r.width();
00338     }
00339     xb = a + int(12.0*Scale);
00340     yb = b + int(10.0*Scale);
00341     x2 = x1+25 + int(float(a) / Scale);
00342     y2 = y1+23 + int(float(b) / Scale);
00343     if(ty < y2+1) if(ty > y1-r.height())  ty = y2 + 1;
00344 
00345     p->PostPaintEvent(_Rect,cx-6, cy-5, xb, yb);
00346     p->PostPaintEvent(_Line,cx-1, cy+yb, cx-6, cy+yb-5);
00347     p->PostPaintEvent(_Line,cx+xb-2, cy+yb, cx-1, cy+yb);
00348     p->PostPaintEvent(_Line,cx+xb-2, cy+yb, cx+xb-6, cy+yb-5);
00349     p->PostPaintEvent(_Line,cx+xb-2, cy+yb, cx+xb-2, cy);
00350     p->PostPaintEvent(_Line,cx+xb-2, cy, cx+xb-6, cy-5);
00351     return;
00352   }
00353 
00354   // paint all lines
00355   foreach(Line *p1, Lines)
00356     p->PostPaintEvent(_Line,cx+p1->x1, cy+p1->y1, cx+p1->x2, cy+p1->y2);
00357 
00358   // paint all ports
00359   foreach(Port *p2, Ports)
00360     if(p2->avail) p->PostPaintEvent(_Ellipse,cx+p2->x-4, cy+p2->y-4, 8, 8);
00361 
00362   foreach(Arc *p3, Arcs)   // paint all arcs
00363     p->PostPaintEvent(_Arc,cx+p3->x, cy+p3->y, p3->w, p3->h, p3->angle, p3->arclen);
00364 
00365 
00366   foreach(Area *pa, Rects) // paint all rectangles
00367     p->PostPaintEvent(_Rect,cx+pa->x, cy+pa->y, pa->w, pa->h);
00368 
00369   foreach(Area *pa, Ellips) // paint all ellipses
00370     p->PostPaintEvent(_Ellipse,cx+pa->x, cy+pa->y, pa->w, pa->h);
00371 }
00372 
00373 // -------------------------------------------------------
00374 // For output on a printer device.
00375 void Component::print(ViewPainter *p, float FontScale)
00376 {
00377   foreach(Text *pt, Texts)
00378     pt->Size *= FontScale;
00379 
00380   paint(p);
00381 
00382  foreach(Text *pt, Texts)
00383     pt->Size /= FontScale;
00384 }
00385 
00386 // -------------------------------------------------------
00387 // Rotates the component 90 counter-clockwise around its center
00388 void Component::rotate()
00389 {
00390   // Port count only available after recreate, createSymbol
00391   if ((Model != "Sub") && (Model !="VHDL") && (Model != "Verilog")) // skip port count
00392     if(Ports.count() < 1) return;  // do not rotate components without ports
00393   int tmp, dx, dy;
00394 
00395   // rotate all lines
00396   foreach(Line *p1, Lines) {
00397     tmp = -p1->x1;
00398     p1->x1 = p1->y1;
00399     p1->y1 = tmp;
00400     tmp = -p1->x2;
00401     p1->x2 = p1->y2;
00402     p1->y2 = tmp;
00403   }
00404 
00405   // rotate all ports
00406   foreach(Port *p2, Ports) {
00407     tmp = -p2->x;
00408     p2->x = p2->y;
00409     p2->y = tmp;
00410   }
00411 
00412   // rotate all arcs
00413   foreach(Arc *p3, Arcs) {
00414     tmp = -p3->x;
00415     p3->x = p3->y;
00416     p3->y = tmp - p3->w;
00417     tmp = p3->w;
00418     p3->w = p3->h;
00419     p3->h = tmp;
00420     p3->angle += 16*90;
00421     if(p3->angle >= 16*360) p3->angle -= 16*360;;
00422   }
00423 
00424   // rotate all rectangles
00425   foreach(Area *pa, Rects) {
00426     tmp = -pa->x;
00427     pa->x = pa->y;
00428     pa->y = tmp - pa->w;
00429     tmp = pa->w;
00430     pa->w = pa->h;
00431     pa->h = tmp;
00432   }
00433 
00434   // rotate all ellipses
00435   foreach(Area *pa, Ellips) {
00436     tmp = -pa->x;
00437     pa->x = pa->y;
00438     pa->y = tmp - pa->w;
00439     tmp = pa->w;
00440     pa->w = pa->h;
00441     pa->h = tmp;
00442   }
00443 
00444   // rotate all text
00445   float ftmp;
00446   foreach(Text *pt, Texts) {
00447     tmp = -pt->x;
00448     pt->x = pt->y;
00449     pt->y = tmp;
00450 
00451     ftmp = -pt->mSin;
00452     pt->mSin = pt->mCos;
00453     pt->mCos = ftmp;
00454   }
00455 
00456   tmp = -x1;   // rotate boundings
00457   x1  = y1; y1 = -x2;
00458   x2  = y2; y2 = tmp;
00459 
00460   tmp = -tx;    // rotate text position
00461   tx  = ty;
00462   ty  = tmp;
00463   // use the screen-compatible metric
00464   QFontMetrics  metrics(QucsSettings.font, 0);   // get size of text
00465   dx = dy = 0;
00466   if(showName) {
00467     dx = metrics.width(Name);
00468     dy = metrics.lineSpacing();
00469   }
00470   for(Property *pp = Props.first(); pp != 0; pp = Props.next())
00471     if(pp->display) {
00472       // get width of text
00473       tmp = metrics.width(pp->Name+"="+pp->Value);
00474       if(tmp > dx) dx = tmp;
00475       dy += metrics.lineSpacing();
00476     }
00477   if(tx > x2) ty = y1-ty+y2;    // rotate text position
00478   else if(ty < y1) ty -= dy;
00479   else if(tx < x1) { tx += dy-dx;  ty = y1-ty+y2; }
00480   else ty -= dx;
00481 
00482   rotated++;  // keep track of what's done
00483   rotated &= 3;
00484 }
00485 
00486 // -------------------------------------------------------
00487 // Mirrors the component about the x-axis.
00488 void Component::mirrorX()
00489 {
00490   // Port count only available after recreate, createSymbol
00491   if ((Model != "Sub") && (Model !="VHDL") && (Model != "Verilog")) // skip port count
00492     if(Ports.count() < 1) return;  // do not rotate components without ports
00493 
00494   // mirror all lines
00495   foreach(Line *p1, Lines) {
00496     p1->y1 = -p1->y1;
00497     p1->y2 = -p1->y2;
00498   }
00499 
00500   // mirror all ports
00501   foreach(Port *p2, Ports)
00502     p2->y = -p2->y;
00503 
00504   // mirror all arcs
00505   foreach(Arc *p3, Arcs) {
00506     p3->y = -p3->y - p3->h;
00507     if(p3->angle > 16*180) p3->angle -= 16*360;
00508     p3->angle  = -p3->angle;    // mirror
00509     p3->angle -= p3->arclen;    // go back to end of arc
00510     if(p3->angle < 0) p3->angle += 16*360;  // angle has to be > 0
00511   }
00512 
00513   // mirror all rectangles
00514   foreach(Area *pa, Rects)
00515     pa->y = -pa->y - pa->h;
00516 
00517   // mirror all ellipses
00518   foreach(Area *pa, Ellips)
00519     pa->y = -pa->y - pa->h;
00520 
00521   QFont f = QucsSettings.font;
00522   // mirror all text
00523   foreach(Text *pt, Texts) {
00524     f.setPointSizeF(pt->Size);
00525     // use the screen-compatible metric
00526     QFontMetrics  smallMetrics(f, 0);
00527     QSize s = smallMetrics.size(0, pt->s);   // use size for more lines
00528     pt->y = -pt->y - int(pt->mCos)*s.height() + int(pt->mSin)*s.width();
00529   }
00530 
00531   int tmp = y1;
00532   y1  = -y2; y2 = -tmp;   // mirror boundings
00533   // use the screen-compatible metric
00534   QFontMetrics  metrics(QucsSettings.font, 0);   // get size of text
00535   int dy = 0;
00536   if(showName)
00537     dy = metrics.lineSpacing();   // for "Name"
00538   for(Property *pp = Props.first(); pp != 0; pp = Props.next())
00539     if(pp->display)  dy += metrics.lineSpacing();
00540   if((tx > x1) && (tx < x2)) ty = -ty-dy;     // mirror text position
00541   else ty = y1+ty+y2;
00542 
00543   mirroredX = !mirroredX;    // keep track of what's done
00544   rotated += rotated << 1;
00545   rotated &= 3;
00546 }
00547 
00548 // -------------------------------------------------------
00549 // Mirrors the component about the y-axis.
00550 void Component::mirrorY()
00551 {
00552   // Port count only available after recreate, createSymbol
00553   if ((Model != "Sub") && (Model !="VHDL") && (Model != "Verilog")) // skip port count
00554     if(Ports.count() < 1) return;  // do not rotate components without ports
00555 
00556   // mirror all lines
00557   foreach(Line *p1, Lines) {
00558     p1->x1 = -p1->x1;
00559     p1->x2 = -p1->x2;
00560   }
00561 
00562   // mirror all ports
00563   foreach(Port *p2, Ports)
00564     p2->x = -p2->x;
00565 
00566   // mirror all arcs
00567   foreach(Arc *p3, Arcs) {
00568     p3->x = -p3->x - p3->w;
00569     p3->angle = 16*180 - p3->angle - p3->arclen;  // mirror
00570     if(p3->angle < 0) p3->angle += 16*360;   // angle has to be > 0
00571   }
00572 
00573   // mirror all rectangles
00574   foreach(Area *pa, Rects)
00575     pa->x = -pa->x - pa->w;
00576 
00577   // mirror all ellipses
00578   foreach(Area *pa, Ellips)
00579     pa->x = -pa->x - pa->w;
00580 
00581   int tmp;
00582   QFont f = QucsSettings.font;
00583   // mirror all text
00584   foreach(Text *pt, Texts) {
00585     f.setPointSizeF(pt->Size);
00586     // use the screen-compatible metric
00587     QFontMetrics  smallMetrics(f, 0);
00588     QSize s = smallMetrics.size(0, pt->s);   // use size for more lines
00589     pt->x = -pt->x - int(pt->mSin)*s.height() - int(pt->mCos)*s.width();
00590   }
00591 
00592   tmp = x1;
00593   x1  = -x2; x2 = -tmp;   // mirror boundings
00594   // use the screen-compatible metric
00595   QFontMetrics  metrics(QucsSettings.font, 0);   // get size of text
00596   int dx = 0;
00597   if(showName)
00598     dx = metrics.width(Name);
00599   for(Property *pp = Props.first(); pp != 0; pp = Props.next())
00600     if(pp->display) {
00601       // get width of text
00602       tmp = metrics.width(pp->Name+"="+pp->Value);
00603       if(tmp > dx)  dx = tmp;
00604     }
00605   if((ty > y1) && (ty < y2)) tx = -tx-dx;     // mirror text position
00606   else tx = x1+tx+x2;
00607 
00608   mirroredX = !mirroredX;   // keep track of what's done
00609   rotated += rotated << 1;
00610   rotated += 2;
00611   rotated &= 3;
00612 }
00613 
00614 // -------------------------------------------------------
00615 QString Component::netlist()
00616 {
00617   QString s = Model+":"+Name;
00618 
00619   // output all node names
00620   foreach(Port *p1, Ports)
00621     s += " "+p1->Connection->Name;   // node names
00622 
00623   // output all properties
00624   for(Property *p2 = Props.first(); p2 != 0; p2 = Props.next())
00625     if(p2->Name != "Symbol")
00626       s += " "+p2->Name+"=\""+p2->Value+"\"";
00627 
00628   return s + '\n';
00629 }
00630 
00631 // -------------------------------------------------------
00632 QString Component::getNetlist()
00633 {
00634   switch(isActive) {
00635     case COMP_IS_ACTIVE:
00636       return netlist();
00637     case COMP_IS_OPEN:
00638       return QString("");
00639   }
00640 
00641   // Component is shortened.
00642   int z=0;
00643   QListIterator<Port *> iport(Ports);
00644   Port *pp = iport.next();
00645   QString Node1 = pp->Connection->Name;
00646   QString s = "";
00647   while (iport.hasNext())
00648     s += "R:" + Name + "." + QString::number(z++) + " " +
00649       Node1 + " " + iport.next()->Connection->Name + " R=\"0\"\n";
00650   return s;
00651 }
00652 
00653 // -------------------------------------------------------
00654 QString Component::verilogCode(int)
00655 {
00656   return QString("");   // no digital model
00657 }
00658 
00659 // -------------------------------------------------------
00660 QString Component::get_Verilog_Code(int NumPorts)
00661 {
00662   switch(isActive) {
00663     case COMP_IS_OPEN:
00664       return QString("");
00665     case COMP_IS_ACTIVE:
00666       return verilogCode(NumPorts);
00667   }
00668 
00669   // Component is shortened.
00670   QListIterator<Port *> iport(Ports);
00671   Port *pp = iport.next();
00672   QString Node1 = pp->Connection->Name;
00673   QString s = "";
00674   while (iport.hasNext())
00675     s += "  assign " + iport.next()->Connection->Name + " = " + Node1 + ";\n";
00676   return s;
00677 }
00678 
00679 // -------------------------------------------------------
00680 QString Component::vhdlCode(int)
00681 {
00682   return QString("");   // no digital model
00683 }
00684 
00685 // -------------------------------------------------------
00686 QString Component::get_VHDL_Code(int NumPorts)
00687 {
00688   switch(isActive) {
00689     case COMP_IS_OPEN:
00690       return QString("");
00691     case COMP_IS_ACTIVE:
00692       return vhdlCode(NumPorts);
00693   }
00694 
00695   // Component is shortened.
00696   // This puts the signal of the second port onto the first port.
00697   // This is logically correct for the inverter only, but makes
00698   // some sense for the gates (OR, AND etc.).
00699   // Has anyone a better idea?
00700   QString Node1 = Ports.at(0)->Connection->Name;
00701   return "  " + Node1 + " <= " + Ports.at(1)->Connection->Name + ";\n";
00702 }
00703 
00704 // -------------------------------------------------------
00705 QString Component::save()
00706 {
00707 #if XML
00708   QDomDocument doc;
00709   QDomElement el = doc.createElement (Model);
00710   doc.appendChild (el);
00711   el.setTagName (Model);
00712   el.setAttribute ("inst", Name.isEmpty() ? "*" : Name);
00713   el.setAttribute ("display", isActive | (showName ? 4 : 0));
00714   el.setAttribute ("cx", cx);
00715   el.setAttribute ("cy", cy);
00716   el.setAttribute ("tx", tx);
00717   el.setAttribute ("ty", ty);
00718   el.setAttribute ("mirror", mirroredX);
00719   el.setAttribute ("rotate", rotated);
00720 
00721   for (Property *pr = Props.first(); pr != 0; pr = Props.next()) {
00722     el.setAttribute (pr->Name, (pr->display ? "1@" : "0@") + pr->Value);
00723   }
00724   qDebug (doc.toString());
00725 #endif
00726   QString s = "<" + Model;
00727 
00728   if(Name.isEmpty()) s += " * ";
00729   else s += " "+Name+" ";
00730 
00731   int i=0;
00732   if(!showName)
00733     i = 4;
00734   i |= isActive;
00735   s += QString::number(i);
00736   s += " "+QString::number(cx)+" "+QString::number(cy);
00737   s += " "+QString::number(tx)+" "+QString::number(ty);
00738   if(mirroredX) s += " 1";
00739   else s += " 0";
00740   s += " "+QString::number(rotated);
00741 
00742   // write all properties
00743   for(Property *p1 = Props.first(); p1 != 0; p1 = Props.next()) {
00744     if(p1->Description.isEmpty())
00745       s += " \""+p1->Name+"="+p1->Value+"\"";   // e.g. for equations
00746     else s += " \""+p1->Value+"\"";
00747     if(p1->display) s += " 1";
00748     else s += " 0";
00749   }
00750 
00751   return s+">";
00752 }
00753 
00754 // -------------------------------------------------------
00755 bool Component::load(const QString& _s)
00756 {
00757   bool ok;
00758   int  ttx, tty, tmp;
00759   QString s = _s;
00760 
00761   if(s.at(0) != '<') return false;
00762   if(s.at(s.length()-1) != '>') return false;
00763   s = s.mid(1, s.length()-2);   // cut off start and end character
00764 
00765   QString n;
00766   Name = s.section(' ',1,1);    // Name
00767   if(Name == "*") Name = "";
00768 
00769   n  = s.section(' ',2,2);      // isActive
00770   tmp = n.toInt(&ok);
00771   if(!ok) return false;
00772   isActive = tmp & 3;
00773 
00774   if(tmp & 4)
00775     showName = false;
00776   else
00777     showName = true;
00778 
00779   n  = s.section(' ',3,3);    // cx
00780   cx = n.toInt(&ok);
00781   if(!ok) return false;
00782 
00783   n  = s.section(' ',4,4);    // cy
00784   cy = n.toInt(&ok);
00785   if(!ok) return false;
00786 
00787   n  = s.section(' ',5,5);    // tx
00788   ttx = n.toInt(&ok);
00789   if(!ok) return false;
00790 
00791   n  = s.section(' ',6,6);    // ty
00792   tty = n.toInt(&ok);
00793   if(!ok) return false;
00794 
00795   if(Model.at(0) != '.') {  // is simulation component (dc, ac, ...) ?
00796 
00797     n  = s.section(' ',7,7);    // mirroredX
00798     if(n.toInt(&ok) == 1) mirrorX();
00799     if(!ok) return false;
00800 
00801     n  = s.section(' ',8,8);    // rotated
00802     tmp = n.toInt(&ok);
00803     if(!ok) return false;
00804     if(rotated > tmp)  // neccessary because of historical flaw in ...
00805       tmp += 4;        // ... components like "volt_dc"
00806     for(int z=rotated; z<tmp; z++) rotate();
00807 
00808   }
00809 
00810   tx = ttx; ty = tty; // restore text position (was changed by rotate/mirror)
00811 
00812   unsigned int z=0, counts = s.count('"');
00813   if(Model == "Sub")
00814     tmp = 2;   // first property (File) already exists
00815   else if(Model == "Lib")
00816     tmp = 3;
00817   else if(Model == "EDD")
00818     tmp = 5;
00819   else if(Model == "RFEDD")
00820     tmp = 8;
00821   else if(Model == "VHDL")
00822     tmp = 2;
00823   else if(Model == "MUTX")
00824     tmp = 5; // number of properties for the default MUTX (2 inductors)
00825   else tmp = counts + 1;    // "+1" because "counts" could be zero
00826 
00827   for(; tmp<=(int)counts/2; tmp++)
00828     Props.append(new Property("p", "", true, " "));
00829 
00830   // load all properties
00831   Property *p1;
00832   for(p1 = Props.first(); p1 != 0; p1 = Props.next()) {
00833     z++;
00834     n = s.section('"',z,z);    // property value
00835     z++;
00836     //qDebug() << "LOAD: " << p1->Description;
00837 
00838     // not all properties have to be mentioned (backward compatible)
00839     if(z > counts) {
00840       if(p1->Description.isEmpty())
00841         Props.remove();    // remove if allocated in vain
00842 
00843       if(Model == "Diode") {
00844   if(counts < 56) {  // backward compatible
00845           counts >>= 1;
00846           p1 = Props.at(counts-1);
00847           for(; p1 != 0; p1 = Props.current()) {
00848             if(counts-- < 19)
00849               break;
00850 
00851             n = Props.prev()->Value;
00852             p1->Value = n;
00853           }
00854 
00855           p1 = Props.at(17);
00856           p1->Value = Props.at(11)->Value;
00857           Props.current()->Value = "0";
00858         }
00859       }
00860       else if(Model == "AND" || Model == "NAND" || Model == "NOR" ||
00861         Model == "OR" ||  Model == "XNOR"|| Model == "XOR") {
00862   if(counts < 10) {   // backward compatible
00863           counts >>= 1;
00864           p1 = Props.at(counts);
00865           for(; p1 != 0; p1 = Props.current()) {
00866             if(counts-- < 4)
00867               break;
00868             n = Props.prev()->Value;
00869             p1->Value = n;
00870           }
00871           Props.current()->Value = "10";
00872   }
00873       }
00874       else if(Model == "Buf" || Model == "Inv") {
00875   if(counts < 8) {   // backward compatible
00876           counts >>= 1;
00877           p1 = Props.at(counts);
00878           for(; p1 != 0; p1 = Props.current()) {
00879             if(counts-- < 3)
00880               break;
00881             n = Props.prev()->Value;
00882             p1->Value = n;
00883           }
00884           Props.current()->Value = "10";
00885   }
00886       }
00887 
00888       return true;
00889     }
00890 
00891     // for equations
00892     if(Model != "EDD" && Model != "RFEDD" && Model != "RFEDD2P")
00893     if(p1->Description.isEmpty()) {  // unknown number of properties ?
00894       p1->Name = n.section('=',0,0);
00895       n = n.section('=',1);
00896       // allocate memory for a new property (e.g. for equations)
00897       if(Props.count() < (counts>>1)) {
00898         Props.insert(z >> 1, new Property("y", "1", true));
00899         Props.prev();
00900       }
00901     }
00902     if(z == 6)  if(counts == 6)     // backward compatible
00903       if(Model == "R") {
00904         Props.getLast()->Value = n;
00905         return true;
00906       }
00907     p1->Value = n;
00908 
00909     n  = s.section('"',z,z);    // display
00910     p1->display = (n.at(1) == '1');
00911   }
00912 
00913   return true;
00914 }
00915 
00916 // *******************************************************************
00917 // ***  The following functions are used to load the schematic symbol
00918 // ***  from file. (e.g. subcircuit, library component)
00919 
00920 int Component::analyseLine(const QString& Row, int numProps)
00921 {
00922   QPen Pen;
00923   QBrush Brush;
00924   QColor Color;
00925   QString s;
00926   int i1, i2, i3, i4, i5, i6;
00927 
00928   s = Row.section(' ',0,0);    // component type
00929   if((s == "PortSym") || (s == ".PortSym")) {  // backward compatible
00930     if(!getIntegers(Row, &i1, &i2, &i3))
00931       return -1;
00932     for(i6 = Ports.count(); i6<i3; i6++)  // if ports not in numerical order
00933       Ports.append(new Port(0, 0, false));
00934 
00935     Port *po = Ports.at(i3-1);
00936     po->x  = i1;
00937     po->y = i2;
00938     po->avail = true;
00939 
00940     if(i1 < x1)  x1 = i1;  // keep track of component boundings
00941     if(i1 > x2)  x2 = i1;
00942     if(i2 < y1)  y1 = i2;
00943     if(i2 > y2)  y2 = i2;
00944     return 0;   // do not count Ports
00945   }
00946   else if(s == "Line") {
00947     if(!getIntegers(Row, &i1, &i2, &i3, &i4))  return -1;
00948     if(!getPen(Row, Pen, 5))  return -1;
00949     i3 += i1;
00950     i4 += i2;
00951     Lines.append(new Line(i1, i2, i3, i4, Pen));
00952 
00953     if(i1 < x1)  x1 = i1;  // keep track of component boundings
00954     if(i1 > x2)  x2 = i1;
00955     if(i2 < y1)  y1 = i2;
00956     if(i2 > y2)  y2 = i2;
00957     if(i3 < x1)  x1 = i3;
00958     if(i3 > x2)  x2 = i3;
00959     if(i4 < y1)  y1 = i4;
00960     if(i4 > y2)  y2 = i4;
00961     return 1;
00962   }
00963   else if(s == "EArc") {
00964     if(!getIntegers(Row, &i1, &i2, &i3, &i4, &i5, &i6))
00965       return -1;
00966     if(!getPen(Row, Pen, 7))  return -1;
00967     Arcs.append(new struct Arc(i1, i2, i3, i4, i5, i6, Pen));
00968 
00969     if(i1 < x1)  x1 = i1;  // keep track of component boundings
00970     if(i1+i3 > x2)  x2 = i1+i3;
00971     if(i2 < y1)  y1 = i2;
00972     if(i2+i4 > y2)  y2 = i2+i4;
00973     return 1;
00974   }
00975   else if(s == ".ID") {
00976     if(!getIntegers(Row, &i1, &i2))  return -1;
00977     tx = i1;
00978     ty = i2;
00979     Name = Row.section(' ',3,3);
00980     if(Name.isEmpty())  Name = "SUB";
00981 
00982     i1 = 1;
00983     Property *pp = Props.at(numProps-1);
00984     for(;;) {
00985       s = Row.section('"', i1,i1);
00986       if(s.isEmpty())  break;
00987 
00988       pp = Props.next();
00989       if(pp == 0) {
00990         pp = new Property();
00991         Props.append(pp);
00992 
00993         pp->display = (s.at(0) == '1');
00994         pp->Value = s.section('=', 2,2);
00995       }
00996 
00997       pp->Name  = s.section('=', 1,1);
00998       pp->Description = s.section('=', 3,3);
00999       if(pp->Description.isEmpty())
01000         pp->Description = " ";
01001 
01002       i1 += 2;
01003     }
01004 
01005     while(pp != Props.last())
01006       Props.remove();
01007     return 0;   // do not count IDs
01008   }
01009   else if(s == "Arrow") {
01010     if(!getIntegers(Row, &i1, &i2, &i3, &i4, &i5, &i6))  return -1;
01011     if(!getPen(Row, Pen, 7))  return -1;
01012 
01013     double beta   = atan2(double(i6), double(i5));
01014     double phi    = atan2(double(i4), double(i3));
01015     double Length = sqrt(double(i6*i6 + i5*i5));
01016 
01017     i3 += i1;
01018     i4 += i2;
01019     if(i1 < x1)  x1 = i1;  // keep track of component boundings
01020     if(i1 > x2)  x2 = i1;
01021     if(i3 < x1)  x1 = i3;
01022     if(i3 > x2)  x2 = i3;
01023     if(i2 < y1)  y1 = i2;
01024     if(i2 > y2)  y2 = i2;
01025     if(i4 < y1)  y1 = i4;
01026     if(i4 > y2)  y2 = i4;
01027 
01028     Lines.append(new Line(i1, i2, i3, i4, Pen));   // base line
01029 
01030     double w = beta+phi;
01031     i5 = i3-int(Length*cos(w));
01032     i6 = i4-int(Length*sin(w));
01033     Lines.append(new Line(i3, i4, i5, i6, Pen)); // arrow head
01034     if(i5 < x1)  x1 = i5;  // keep track of component boundings
01035     if(i5 > x2)  x2 = i5;
01036     if(i6 < y1)  y1 = i6;
01037     if(i6 > y2)  y2 = i6;
01038 
01039     w = phi-beta;
01040     i5 = i3-int(Length*cos(w));
01041     i6 = i4-int(Length*sin(w));
01042     Lines.append(new Line(i3, i4, i5, i6, Pen));
01043     if(i5 < x1)  x1 = i5;  // keep track of component boundings
01044     if(i5 > x2)  x2 = i5;
01045     if(i6 < y1)  y1 = i6;
01046     if(i6 > y2)  y2 = i6;
01047 
01048     return 1;
01049   }
01050   else if(s == "Ellipse") {
01051     if(!getIntegers(Row, &i1, &i2, &i3, &i4))  return -1;
01052     if(!getPen(Row, Pen, 5))  return -1;
01053     if(!getBrush(Row, Brush, 8))  return -1;
01054     Ellips.append(new Area(i1, i2, i3, i4, Pen, Brush));
01055 
01056     if(i1 < x1)  x1 = i1;  // keep track of component boundings
01057     if(i1 > x2)  x2 = i1;
01058     if(i2 < y1)  y1 = i2;
01059     if(i2 > y2)  y2 = i2;
01060     if(i1+i3 < x1)  x1 = i1+i3;
01061     if(i1+i3 > x2)  x2 = i1+i3;
01062     if(i2+i4 < y1)  y1 = i2+i4;
01063     if(i2+i4 > y2)  y2 = i2+i4;
01064     return 1;
01065   }
01066   else if(s == "Rectangle") {
01067     if(!getIntegers(Row, &i1, &i2, &i3, &i4))  return -1;
01068     if(!getPen(Row, Pen, 5))  return -1;
01069     if(!getBrush(Row, Brush, 8))  return -1;
01070     Rects.append(new Area(i1, i2, i3, i4, Pen, Brush));
01071 
01072     if(i1 < x1)  x1 = i1;  // keep track of component boundings
01073     if(i1 > x2)  x2 = i1;
01074     if(i2 < y1)  y1 = i2;
01075     if(i2 > y2)  y2 = i2;
01076     if(i1+i3 < x1)  x1 = i1+i3;
01077     if(i1+i3 > x2)  x2 = i1+i3;
01078     if(i2+i4 < y1)  y1 = i2+i4;
01079     if(i2+i4 > y2)  y2 = i2+i4;
01080     return 1;
01081   }
01082   else if(s == "Text") {  // must be last in order to reuse "s" *********
01083     if(!getIntegers(Row, &i1, &i2, &i3, 0, &i4))  return -1;
01084     Color.setNamedColor(Row.section(' ',4,4));
01085     if(!Color.isValid()) return -1;
01086 
01087     s = Row.mid(Row.indexOf('"')+1);    // Text (can contain " !!!)
01088     s = s.left(s.length()-1);
01089     if(s.isEmpty()) return -1;
01090     misc::convert2Unicode(s);
01091 
01092     Texts.append(new Text(i1, i2, s, Color, float(i3),
01093                           float(cos(float(i4)*pi/180.0)),
01094                           float(sin(float(i4)*pi/180.0))));
01095 
01096     QFont Font(QucsSettings.font);
01097     Font.setPointSizeF(float(i3));
01098     QFontMetrics  metrics(Font, 0); // use the screen-compatible metric
01099     QSize r = metrics.size(0, s);    // get size of text
01100     i3 = i1 + int(float(r.width())  * Texts.last()->mCos)
01101             + int(float(r.height()) * Texts.last()->mSin);
01102     i4 = i2 + int(float(r.width())  * -Texts.last()->mSin)
01103             + int(float(r.height()) * Texts.last()->mCos);
01104 
01105     if(i1 < x1)  x1 = i1;  // keep track of component boundings
01106     if(i2 < y1)  y1 = i2;
01107     if(i1 > x2)  x2 = i1;
01108     if(i2 > y2)  y2 = i2;
01109 
01110     if(i3 < x1)  x1 = i3;
01111     if(i4 < y1)  y1 = i4;
01112     if(i3 > x2)  x2 = i3;
01113     if(i4 > y2)  y2 = i4;
01114     return 1;
01115   }
01116 
01117   return 0;
01118 }
01119 
01120 // ---------------------------------------------------------------------
01121 bool Component::getIntegers(const QString& s, int *i1, int *i2, int *i3,
01122            int *i4, int *i5, int *i6)
01123 {
01124   bool ok;
01125   QString n;
01126 
01127   if(!i1) return true;
01128   n  = s.section(' ',1,1);
01129   *i1 = n.toInt(&ok);
01130   if(!ok) return false;
01131 
01132   if(!i2) return true;
01133   n  = s.section(' ',2,2);
01134   *i2 = n.toInt(&ok);
01135   if(!ok) return false;
01136 
01137   if(!i3) return true;
01138   n  = s.section(' ',3,3);
01139   *i3 = n.toInt(&ok);
01140   if(!ok) return false;
01141 
01142   if(i4) {
01143     n  = s.section(' ',4,4);
01144     *i4 = n.toInt(&ok);
01145     if(!ok) return false;
01146   }
01147 
01148   if(!i5) return true;
01149   n  = s.section(' ',5,5);
01150   *i5 = n.toInt(&ok);
01151   if(!ok) return false;
01152 
01153   if(!i6) return true;
01154   n  = s.section(' ',6,6);
01155   *i6 = n.toInt(&ok);
01156   if(!ok) return false;
01157 
01158   return true;
01159 }
01160 
01161 // ---------------------------------------------------------------------
01162 bool Component::getPen(const QString& s, QPen& Pen, int i)
01163 {
01164   bool ok;
01165   QString n;
01166 
01167   n = s.section(' ',i,i);    // color
01168   QColor co;
01169   co.setNamedColor(n);
01170   Pen.setColor(co);
01171   if(!Pen.color().isValid()) return false;
01172 
01173   i++;
01174   n = s.section(' ',i,i);    // thickness
01175   Pen.setWidth(n.toInt(&ok));
01176   if(!ok) return false;
01177 
01178   i++;
01179   n = s.section(' ',i,i);    // line style
01180   Pen.setStyle((Qt::PenStyle)n.toInt(&ok));
01181   if(!ok) return false;
01182 
01183   return true;
01184 }
01185 
01186 // ---------------------------------------------------------------------
01187 bool Component::getBrush(const QString& s, QBrush& Brush, int i)
01188 {
01189   bool ok;
01190   QString n;
01191 
01192   n = s.section(' ',i,i);    // fill color
01193   QColor co;
01194   co.setNamedColor(n);
01195   Brush.setColor(co);
01196   if(!Brush.color().isValid()) return false;
01197 
01198   i++;
01199   n = s.section(' ',i,i);    // fill style
01200   Brush.setStyle((Qt::BrushStyle)n.toInt(&ok));
01201   if(!ok) return false;
01202 
01203   i++;
01204   n = s.section(' ',i,i);    // filled
01205   if(n.toInt(&ok) == 0) Brush.setStyle(Qt::NoBrush);
01206   if(!ok) return false;
01207 
01208   return true;
01209 }
01210 
01211 // ---------------------------------------------------------------------
01212 Property * Component::getProperty(const QString& name)
01213 {
01214   for(Property *pp = Props.first(); pp != 0; pp = Props.next())
01215     if(pp->Name == name) {
01216       return pp;
01217     }
01218   return NULL;
01219 }
01220 
01221 // ---------------------------------------------------------------------
01222 void Component::copyComponent(Component *pc)
01223 {
01224   Type = pc->Type;
01225   x1 = pc->x1;
01226   y1 = pc->y1;
01227   x2 = pc->x2;
01228   y2 = pc->y2;
01229 
01230   Model = pc->Model;
01231   Name  = pc->Name;
01232   showName = pc->showName;
01233   Description = pc->Description;
01234 
01235   isActive = pc->isActive;
01236   rotated  = pc->rotated;
01237   mirroredX = pc->mirroredX;
01238   tx = pc->tx;
01239   ty = pc->ty;
01240 
01241   Props  = pc->Props;
01242   Ports  = pc->Ports;
01243   Lines  = pc->Lines;
01244   Arcs   = pc->Arcs;
01245   Rects  = pc->Rects;
01246   Ellips = pc->Ellips;
01247   Texts  = pc->Texts;
01248 }
01249 
01250 
01251 // ***********************************************************************
01252 // ********                                                       ********
01253 // ********          Functions of class MultiViewComponent        ********
01254 // ********                                                       ********
01255 // ***********************************************************************
01256 void MultiViewComponent::recreate(Schematic *Doc)
01257 {
01258   if(Doc) {
01259     Doc->Components->setAutoDelete(false);
01260     Doc->deleteComp(this);
01261   }
01262 
01263   Ellips.clear();
01264   Texts.clear();
01265   Ports.clear();
01266   Lines.clear();
01267   Rects.clear();
01268   Arcs.clear();
01269   createSymbol();
01270 
01271   bool mmir = mirroredX;
01272   int  rrot = rotated;
01273   if (mmir && rrot==2) // mirrorX and rotate 180 = mirrorY
01274     mirrorY();
01275   else  {
01276     if(mmir)
01277       mirrorX();   // mirror
01278     if (rrot)
01279       for(int z=0; z<rrot; z++)  rotate(); // rotate
01280   }
01281 
01282   rotated = rrot;   // restore properties (were changed by rotate/mirror)
01283   mirroredX = mmir;
01284 
01285   if(Doc) {
01286     Doc->insertRawComponent(this);
01287     Doc->Components->setAutoDelete(true);
01288   }
01289 }
01290 
01291 
01292 // ***********************************************************************
01293 // ********                                                       ********
01294 // ********            Functions of class GateComponent           ********
01295 // ********                                                       ********
01296 // ***********************************************************************
01297 GateComponent::GateComponent()
01298 {
01299   Type = isComponent;   // both analog and digital
01300   Name  = "Y";
01301 
01302   // the list order must be preserved !!!
01303   Props.append(new Property("in", "2", false,
01304     QObject::tr("number of input ports")));
01305   Props.append(new Property("V", "1 V", false,
01306     QObject::tr("voltage of high level")));
01307   Props.append(new Property("t", "0", false,
01308     QObject::tr("delay time")));
01309   Props.append(new Property("TR", "10", false,
01310     QObject::tr("transfer function scaling factor")));
01311 
01312   // this must be the last property in the list !!!
01313   Props.append(new Property("Symbol", "old", false,
01314     QObject::tr("schematic symbol")+" [old, DIN40900]"));
01315 }
01316 
01317 // -------------------------------------------------------
01318 QString GateComponent::netlist()
01319 {
01320   QString s = Model+":"+Name;
01321 
01322   // output all node names
01323   foreach(Port *pp, Ports)
01324     s += " "+pp->Connection->Name;   // node names
01325 
01326   // output all properties
01327   Property *p = Props.at(1);
01328   s += " " + p->Name + "=\"" + p->Value + "\"";
01329   p = Props.next();
01330   s += " " + p->Name + "=\"" + p->Value + "\"";
01331   p = Props.next();
01332   s += " " + p->Name + "=\"" + p->Value + "\"\n";
01333   return s;
01334 }
01335 
01336 // -------------------------------------------------------
01337 QString GateComponent::vhdlCode(int NumPorts)
01338 {
01339   QListIterator<Port *> iport(Ports);
01340   Port *pp = iport.next();
01341   QString s = "  " + pp->Connection->Name + " <= ";  // output port
01342 
01343   // xnor NOT defined for std_logic, so here use not and xor
01344   if (Model == "XNOR") {
01345     QString Op = " xor ";
01346 
01347     // first input port
01348     pp = iport.next();
01349     QString rhs = pp->Connection->Name;
01350 
01351     // output all input ports with node names
01352     while(iport.hasNext()) {
01353       pp = iport.next();
01354       rhs = "not ((" + rhs + ")" + Op + pp->Connection->Name + ")";
01355     }
01356     s += rhs;
01357   }
01358   else {
01359     QString Op = ' ' + Model.toLower() + ' ';
01360     if(Model.at(0) == 'N') {
01361       s += "not (";    // nor, nand is NOT assoziative !!! but xnor is !!!
01362       Op = Op.remove(1, 1);
01363     }
01364 
01365     pp = iport.next();
01366     s += pp->Connection->Name;   // first input port
01367 
01368     // output all input ports with node names
01369     while(iport.hasNext()) {
01370       pp = iport.next();
01371       s += Op + pp->Connection->Name;
01372     }
01373     if(Model.at(0) == 'N')
01374       s += ')';
01375   }
01376 
01377   if(NumPorts <= 0) { // no truth table simulation ?
01378     QString td = Props.at(2)->Value;        // delay time
01379     if(!misc::VHDL_Delay(td, Name)) return td;
01380     s += td;
01381   }
01382 
01383   s += ";\n";
01384   return s;
01385 }
01386 
01387 // -------------------------------------------------------
01388 QString GateComponent::verilogCode(int NumPorts)
01389 {
01390   bool synthesize = true;
01391   QListIterator<Port *> iport(Ports);
01392   Port *pp = iport.next();
01393   QString s("");
01394 
01395   if(synthesize) {
01396     QString op = Model.toLower();
01397     if(op == "and" || op == "nand")
01398       op = "&";
01399     else if (op == "or" || op == "nor")
01400       op = "|";
01401     else if (op == "xor")
01402       op = "^";
01403     else if (op == "xnor")
01404       op = "^~";
01405 
01406     s = "  assign";
01407 
01408     if(NumPorts <= 0) { // no truth table simulation ?
01409       QString td = Props.at(2)->Value;        // delay time
01410       if(!misc::Verilog_Delay(td, Name)) return td;
01411       s += td;
01412     }
01413     s += " " + pp->Connection->Name + " = ";  // output port
01414     if(Model.at(0) == 'N') s += "~(";
01415 
01416     pp = iport.next();
01417     s += pp->Connection->Name;   // first input port
01418 
01419     // output all input ports with node names
01420     while (iport.hasNext()) {
01421       pp = iport.next();
01422       s += " " + op + " " + pp->Connection->Name;
01423     }
01424 
01425     if(Model.at(0) == 'N') s += ")";
01426     s += ";\n";
01427   }
01428   else {
01429     s = "  " + Model.toLower();
01430 
01431     if(NumPorts <= 0) { // no truth table simulation ?
01432       QString td = Props.at(2)->Value;        // delay time
01433       if(!misc::Verilog_Delay(td, Name)) return td;
01434       s += td;
01435     }
01436     s += " " + Name + " (" + pp->Connection->Name;  // output port
01437 
01438     pp = iport.next();
01439     s += ", " + pp->Connection->Name;   // first input port
01440 
01441     // output all input ports with node names
01442     while (iport.hasNext()) {
01443       pp = iport.next();
01444       s += ", " + pp->Connection->Name;
01445     }
01446 
01447     s += ");\n";
01448   }
01449   return s;
01450 }
01451 
01452 // -------------------------------------------------------
01453 void GateComponent::createSymbol()
01454 {
01455   int Num = Props.getFirst()->Value.toInt();
01456   if(Num < 2) Num = 2;
01457   else if(Num > 8) Num = 8;
01458   Props.getFirst()->Value = QString::number(Num);
01459 
01460   int xl, xr, y = 10*Num, z;
01461   x1 = -30; y1 = -y-3;
01462   x2 =  30; y2 =  y+3;
01463 
01464   tx = x1+4;
01465   ty = y2+4;
01466 
01467   z = 0;
01468   if(Model.at(0) == 'N')  z = 1;
01469 
01470   if(Props.getLast()->Value.at(0) == 'D') {  // DIN symbol
01471     xl = -15;
01472     xr =  15;
01473     Lines.append(new Line( 15,-y, 15, y,QPen(Qt::darkBlue,2)));
01474     Lines.append(new Line(-15,-y, 15,-y,QPen(Qt::darkBlue,2)));
01475     Lines.append(new Line(-15, y, 15, y,QPen(Qt::darkBlue,2)));
01476     Lines.append(new Line(-15,-y,-15, y,QPen(Qt::darkBlue,2)));
01477     Lines.append(new Line( 15, 0, 30, 0,QPen(Qt::darkBlue,2)));
01478 
01479     if(Model.at(z) == 'O') {
01480       Lines.append(new Line(-11, 6-y,-6, 9-y,QPen(Qt::darkBlue,0)));
01481       Lines.append(new Line(-11,12-y,-6, 9-y,QPen(Qt::darkBlue,0)));
01482       Lines.append(new Line(-11,14-y,-6,14-y,QPen(Qt::darkBlue,0)));
01483       Lines.append(new Line(-11,16-y,-6,16-y,QPen(Qt::darkBlue,0)));
01484       Texts.append(new Text( -4, 3-y, "1", Qt::darkBlue, 15.0));
01485     }
01486     else if(Model.at(z) == 'A')
01487       Texts.append(new Text( -10, 3-y, "&", Qt::darkBlue, 15.0));
01488     else if(Model.at(0) == 'X') {
01489       if(Model.at(1) == 'N') {
01490   Ellips.append(new Area(xr,-4, 8, 8,
01491                   QPen(Qt::darkBlue,0), QBrush(Qt::darkBlue)));
01492         Texts.append(new Text( -11, 3-y, "=1", Qt::darkBlue, 15.0));
01493       }
01494       else
01495         Texts.append(new Text( -11, 3-y, "=1", Qt::darkBlue, 15.0));
01496     }
01497   }
01498   else {   // old symbol
01499 
01500     if(Model.at(z) == 'O')  xl = 10;
01501     else  xl = -10;
01502     xr = 10;
01503     Lines.append(new Line(-10,-y,-10, y,QPen(Qt::darkBlue,2)));
01504     Lines.append(new Line( 10, 0, 30, 0,QPen(Qt::darkBlue,2)));
01505     Arcs.append(new Arc(-30,-y, 40, 30, 0, 16*90,QPen(Qt::darkBlue,2)));
01506     Arcs.append(new Arc(-30,y-30, 40, 30, 0,-16*90,QPen(Qt::darkBlue,2)));
01507     Lines.append(new Line( 10,15-y, 10, y-15,QPen(Qt::darkBlue,2)));
01508 
01509     if(Model.at(0) == 'X') {
01510       Lines.append(new Line(-5, 0, 5, 0,QPen(Qt::darkBlue,1)));
01511       if(Model.at(1) == 'N') {
01512         Lines.append(new Line(-5,-3, 5,-3,QPen(Qt::darkBlue,1)));
01513         Lines.append(new Line(-5, 3, 5, 3,QPen(Qt::darkBlue,1)));
01514       }
01515       else {
01516         Arcs.append(new Arc(-5,-5, 10, 10, 0, 16*360,QPen(Qt::darkBlue,1)));
01517         Lines.append(new Line( 0,-5, 0, 5,QPen(Qt::darkBlue,1)));
01518       }
01519     }
01520   }
01521 
01522   if(Model.at(0) == 'N')
01523     Ellips.append(new Area(xr,-4, 8, 8,
01524                   QPen(Qt::darkBlue,0), QBrush(Qt::darkBlue)));
01525 
01526   Ports.append(new Port( 30,  0));
01527   y += 10;
01528   for(z=0; z<Num; z++) {
01529     y -= 20;
01530     Ports.append(new Port(-30, y));
01531     if(xl == 10) if((z == 0) || (z == Num-1)) {
01532       Lines.append(new Line(-30, y, 9, y,QPen(Qt::darkBlue,2)));
01533       continue;
01534     }
01535     Lines.append(new Line(-30, y, xl, y,QPen(Qt::darkBlue,2)));
01536   }
01537 }
01538 
01539 
01540 // ***********************************************************************
01541 // ********                                                       ********
01542 // ******** The following function does not belong to any class.  ********
01543 // ******** It creates a component by getting the identification  ********
01544 // ******** string used in the schematic file and for copy/paste. ********
01545 // ********                                                       ********
01546 // ***********************************************************************
01547 
01548 Component* getComponentFromName(QString& Line, Schematic* p)
01549 {
01550   Component *c = 0;
01551 
01552   Line = Line.trimmed();
01553   if(Line.at(0) != '<') {
01554     QMessageBox::critical(0, QObject::tr("Error"),
01555       QObject::tr("Format Error:\nWrong line start!"));
01556     return 0;
01557   }
01558 
01559   QString cstr = Line.section (' ',0,0); // component type
01560   cstr.remove (0,1);    // remove leading "<"
01561   if (cstr == "Lib") c = new LibComp ();
01562   else if (cstr == "Eqn") c = new Equation ();
01563   else if (cstr == "SPICE") c = new SpiceFile();
01564   else if (cstr == "Rus") c = new Resistor (false);  // backward compatible
01565   else if (cstr.left (6) == "SPfile" && cstr != "SPfile") {
01566     // backward compatible
01567     c = new SParamFile ();
01568     c->Props.getLast()->Value = cstr.mid (6); }
01569   else
01570     c = Module::getComponent (cstr);
01571 
01572   if(!c) {
01574     QMessageBox::critical(0, QObject::tr("Error"),
01575   QObject::tr("Format Error:\nUnknown component!\n"
01576                 "%1\n\n"
01577                 "Do you make use of loadable components?").arg(cstr));
01578     return 0;
01579   }
01580 
01581   if(!c->load(Line)) {
01582     QMessageBox::critical(0, QObject::tr("Error"),
01583   QObject::tr("Format Error:\nWrong 'component' line format!"));
01584     delete c;
01585     return 0;
01586   }
01587 
01588   cstr = c->Name;   // is perhaps changed in "recreate" (e.g. subcircuit)
01589   int x = c->tx, y = c->ty;
01590   c->setSchematic (p);
01591   c->recreate(0);
01592   c->Name = cstr;
01593   c->tx = x;  c->ty = y;
01594   return c;
01595 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines