Qucs-GUI
0.0.19
|
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 }