Qucs-GUI
0.0.19
|
00001 /*************************************************************************** 00002 schematic_element.cpp 00003 ----------------------- 00004 begin : Sat Mar 3 2006 00005 copyright : (C) 2006 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 <limits.h> 00019 00020 #include "schematic.h" 00021 #include <Q3PtrList> 00022 #include <QDebug> 00023 00024 00025 /* ******************************************************************* 00026 ***** ***** 00027 ***** Actions handling the nodes ***** 00028 ***** ***** 00029 ******************************************************************* */ 00030 00031 // Inserts a port into the schematic and connects it to another node if 00032 // the coordinates are identical. The node is returned. 00033 Node* Schematic::insertNode(int x, int y, Element *e) 00034 { 00035 Node *pn; 00036 // check if new node lies upon existing node 00037 for(pn = Nodes->first(); pn != 0; pn = Nodes->next()) // check every node 00038 if(pn->cx == x) if(pn->cy == y) 00039 { 00040 pn->Connections.append(e); 00041 break; 00042 } 00043 00044 if(pn == 0) // create new node, if no existing one lies at this position 00045 { 00046 pn = new Node(x, y); 00047 Nodes->append(pn); 00048 pn->Connections.append(e); // connect schematic node to component node 00049 } 00050 else return pn; // return, if node is not new 00051 00052 // check if the new node lies upon an existing wire 00053 for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next()) 00054 { 00055 if(pw->x1 == x) 00056 { 00057 if(pw->y1 > y) continue; 00058 if(pw->y2 < y) continue; 00059 } 00060 else if(pw->y1 == y) 00061 { 00062 if(pw->x1 > x) continue; 00063 if(pw->x2 < x) continue; 00064 } 00065 else continue; 00066 00067 // split the wire into two wires 00068 splitWire(pw, pn); 00069 return pn; 00070 } 00071 00072 return pn; 00073 } 00074 00075 // --------------------------------------------------- 00076 Node* Schematic::selectedNode(int x, int y) 00077 { 00078 for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next()) // test nodes 00079 if(pn->getSelected(x, y)) 00080 return pn; 00081 00082 return 0; 00083 } 00084 00085 00086 /* ******************************************************************* 00087 ***** ***** 00088 ***** Actions handling the wires ***** 00089 ***** ***** 00090 ******************************************************************* */ 00091 00092 // Inserts a port into the schematic and connects it to another node if the 00093 // coordinates are identical. If 0 is returned, no new wire is inserted. 00094 // If 2 is returned, the wire line ended. 00095 int Schematic::insertWireNode1(Wire *w) 00096 { 00097 Node *pn; 00098 // check if new node lies upon an existing node 00099 for(pn = Nodes->first(); pn != 0; pn = Nodes->next()) // check every node 00100 if(pn->cx == w->x1) if(pn->cy == w->y1) break; 00101 00102 if(pn != 0) 00103 { 00104 pn->Connections.append(w); 00105 w->Port1 = pn; 00106 return 2; // node is not new 00107 } 00108 00109 00110 00111 // check if the new node lies upon an existing wire 00112 for(Wire *ptr2 = Wires->first(); ptr2 != 0; ptr2 = Wires->next()) 00113 { 00114 if(ptr2->x1 == w->x1) 00115 { 00116 if(ptr2->y1 > w->y1) continue; 00117 if(ptr2->y2 < w->y1) continue; 00118 00119 if(ptr2->isHorizontal() == w->isHorizontal()) // ptr2-wire is vertical 00120 { 00121 if(ptr2->y2 >= w->y2) 00122 { 00123 delete w; // new wire lies within an existing wire 00124 return 0; 00125 } 00126 else 00127 { 00128 // one part of the wire lies within an existing wire 00129 // the other part not 00130 if(ptr2->Port2->Connections.count() == 1) 00131 { 00132 w->y1 = ptr2->y1; 00133 w->Port1 = ptr2->Port1; 00134 if(ptr2->Label) 00135 { 00136 w->Label = ptr2->Label; 00137 w->Label->pOwner = w; 00138 } 00139 ptr2->Port1->Connections.removeRef(ptr2); // two -> one wire 00140 ptr2->Port1->Connections.append(w); 00141 Nodes->removeRef(ptr2->Port2); 00142 Wires->removeRef(ptr2); 00143 return 2; 00144 } 00145 else 00146 { 00147 w->y1 = ptr2->y2; 00148 w->Port1 = ptr2->Port2; 00149 ptr2->Port2->Connections.append(w); // shorten new wire 00150 return 2; 00151 } 00152 } 00153 } 00154 } 00155 else if(ptr2->y1 == w->y1) 00156 { 00157 if(ptr2->x1 > w->x1) continue; 00158 if(ptr2->x2 < w->x1) continue; 00159 00160 if(ptr2->isHorizontal() == w->isHorizontal()) // ptr2-wire is horizontal 00161 { 00162 if(ptr2->x2 >= w->x2) 00163 { 00164 delete w; // new wire lies within an existing wire 00165 return 0; 00166 } 00167 else 00168 { 00169 // one part of the wire lies within an existing wire 00170 // the other part not 00171 if(ptr2->Port2->Connections.count() == 1) 00172 { 00173 w->x1 = ptr2->x1; 00174 w->Port1 = ptr2->Port1; 00175 if(ptr2->Label) 00176 { 00177 w->Label = ptr2->Label; 00178 w->Label->pOwner = w; 00179 } 00180 ptr2->Port1->Connections.removeRef(ptr2); // two -> one wire 00181 ptr2->Port1->Connections.append(w); 00182 Nodes->removeRef(ptr2->Port2); 00183 Wires->removeRef(ptr2); 00184 return 2; 00185 } 00186 else 00187 { 00188 w->x1 = ptr2->x2; 00189 w->Port1 = ptr2->Port2; 00190 ptr2->Port2->Connections.append(w); // shorten new wire 00191 return 2; 00192 } 00193 } 00194 } 00195 } 00196 else continue; 00197 00198 pn = new Node(w->x1, w->y1); // create new node 00199 Nodes->append(pn); 00200 pn->Connections.append(w); // connect schematic node to the new wire 00201 w->Port1 = pn; 00202 00203 // split the wire into two wires 00204 splitWire(ptr2, pn); 00205 return 2; 00206 } 00207 00208 pn = new Node(w->x1, w->y1); // create new node 00209 Nodes->append(pn); 00210 pn->Connections.append(w); // connect schematic node to the new wire 00211 w->Port1 = pn; 00212 return 1; 00213 } 00214 00215 // --------------------------------------------------- 00216 // if possible, connect two horizontal wires to one 00217 bool Schematic::connectHWires1(Wire *w) 00218 { 00219 Wire *pw; 00220 Node *n = w->Port1; 00221 00222 pw = (Wire*)n->Connections.last(); // last connection is the new wire itself 00223 for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev()) 00224 { 00225 if(pw->Type != isWire) continue; 00226 if(!pw->isHorizontal()) continue; 00227 if(pw->x1 < w->x1) 00228 { 00229 if(n->Connections.count() != 2) continue; 00230 if(pw->Label) 00231 { 00232 w->Label = pw->Label; 00233 w->Label->pOwner = w; 00234 } 00235 else if(n->Label) 00236 { 00237 w->Label = n->Label; 00238 w->Label->pOwner = w; 00239 w->Label->Type = isHWireLabel; 00240 } 00241 w->x1 = pw->x1; 00242 w->Port1 = pw->Port1; // new wire lengthens an existing one 00243 Nodes->removeRef(n); 00244 w->Port1->Connections.removeRef(pw); 00245 w->Port1->Connections.append(w); 00246 Wires->removeRef(pw); 00247 return true; 00248 } 00249 if(pw->x2 >= w->x2) // new wire lies within an existing one ? 00250 { 00251 w->Port1->Connections.removeRef(w); // second node not yet made 00252 delete w; 00253 return false; 00254 } 00255 if(pw->Port2->Connections.count() < 2) 00256 { 00257 // existing wire lies within the new one 00258 if(pw->Label) 00259 { 00260 w->Label = pw->Label; 00261 w->Label->pOwner = w; 00262 } 00263 pw->Port1->Connections.removeRef(pw); 00264 Nodes->removeRef(pw->Port2); 00265 Wires->removeRef(pw); 00266 return true; 00267 } 00268 w->x1 = pw->x2; // shorten new wire according to an existing one 00269 w->Port1->Connections.removeRef(w); 00270 w->Port1 = pw->Port2; 00271 w->Port1->Connections.append(w); 00272 return true; 00273 } 00274 00275 return true; 00276 } 00277 00278 // --------------------------------------------------- 00279 // if possible, connect two vertical wires to one 00280 bool Schematic::connectVWires1(Wire *w) 00281 { 00282 Wire *pw; 00283 Node *n = w->Port1; 00284 00285 pw = (Wire*)n->Connections.last(); // last connection is the new wire itself 00286 for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev()) 00287 { 00288 if(pw->Type != isWire) continue; 00289 if(pw->isHorizontal()) continue; 00290 if(pw->y1 < w->y1) 00291 { 00292 if(n->Connections.count() != 2) continue; 00293 if(pw->Label) 00294 { 00295 w->Label = pw->Label; 00296 w->Label->pOwner = w; 00297 } 00298 else if(n->Label) 00299 { 00300 w->Label = n->Label; 00301 w->Label->pOwner = w; 00302 w->Label->Type = isVWireLabel; 00303 } 00304 w->y1 = pw->y1; 00305 w->Port1 = pw->Port1; // new wire lengthens an existing one 00306 Nodes->removeRef(n); 00307 w->Port1->Connections.removeRef(pw); 00308 w->Port1->Connections.append(w); 00309 Wires->removeRef(pw); 00310 return true; 00311 } 00312 if(pw->y2 >= w->y2) // new wire lies complete within an existing one ? 00313 { 00314 w->Port1->Connections.removeRef(w); // second node not yet made 00315 delete w; 00316 return false; 00317 } 00318 if(pw->Port2->Connections.count() < 2) 00319 { 00320 // existing wire lies within the new one 00321 if(pw->Label) 00322 { 00323 w->Label = pw->Label; 00324 w->Label->pOwner = w; 00325 } 00326 pw->Port1->Connections.removeRef(pw); 00327 Nodes->removeRef(pw->Port2); 00328 Wires->removeRef(pw); 00329 return true; 00330 } 00331 w->y1 = pw->y2; // shorten new wire according to an existing one 00332 w->Port1->Connections.removeRef(w); 00333 w->Port1 = pw->Port2; 00334 w->Port1->Connections.append(w); 00335 return true; 00336 } 00337 00338 return true; 00339 } 00340 00341 // --------------------------------------------------- 00342 // Inserts a port into the schematic and connects it to another node if the 00343 // coordinates are identical. If 0 is returned, no new wire is inserted. 00344 // If 2 is returned, the wire line ended. 00345 int Schematic::insertWireNode2(Wire *w) 00346 { 00347 Node *pn; 00348 // check if new node lies upon an existing node 00349 for(pn = Nodes->first(); pn != 0; pn = Nodes->next()) // check every node 00350 if(pn->cx == w->x2) if(pn->cy == w->y2) break; 00351 00352 if(pn != 0) 00353 { 00354 pn->Connections.append(w); 00355 w->Port2 = pn; 00356 return 2; // node is not new 00357 } 00358 00359 00360 00361 // check if the new node lies upon an existing wire 00362 for(Wire *ptr2 = Wires->first(); ptr2 != 0; ptr2 = Wires->next()) 00363 { 00364 if(ptr2->x1 == w->x2) 00365 { 00366 if(ptr2->y1 > w->y2) continue; 00367 if(ptr2->y2 < w->y2) continue; 00368 00369 // (if new wire lies within an existing wire, was already check before) 00370 if(ptr2->isHorizontal() == w->isHorizontal()) // ptr2-wire is vertical 00371 { 00372 // one part of the wire lies within an existing wire 00373 // the other part not 00374 if(ptr2->Port1->Connections.count() == 1) 00375 { 00376 if(ptr2->Label) 00377 { 00378 w->Label = ptr2->Label; 00379 w->Label->pOwner = w; 00380 } 00381 w->y2 = ptr2->y2; 00382 w->Port2 = ptr2->Port2; 00383 ptr2->Port2->Connections.removeRef(ptr2); // two -> one wire 00384 ptr2->Port2->Connections.append(w); 00385 Nodes->removeRef(ptr2->Port1); 00386 Wires->removeRef(ptr2); 00387 return 2; 00388 } 00389 else 00390 { 00391 w->y2 = ptr2->y1; 00392 w->Port2 = ptr2->Port1; 00393 ptr2->Port1->Connections.append(w); // shorten new wire 00394 return 2; 00395 } 00396 } 00397 } 00398 else if(ptr2->y1 == w->y2) 00399 { 00400 if(ptr2->x1 > w->x2) continue; 00401 if(ptr2->x2 < w->x2) continue; 00402 00403 // (if new wire lies within an existing wire, was already check before) 00404 if(ptr2->isHorizontal() == w->isHorizontal()) // ptr2-wire is horizontal 00405 { 00406 // one part of the wire lies within an existing wire 00407 // the other part not 00408 if(ptr2->Port1->Connections.count() == 1) 00409 { 00410 if(ptr2->Label) 00411 { 00412 w->Label = ptr2->Label; 00413 w->Label->pOwner = w; 00414 } 00415 w->x2 = ptr2->x2; 00416 w->Port2 = ptr2->Port2; 00417 ptr2->Port2->Connections.removeRef(ptr2); // two -> one wire 00418 ptr2->Port2->Connections.append(w); 00419 Nodes->removeRef(ptr2->Port1); 00420 Wires->removeRef(ptr2); 00421 return 2; 00422 } 00423 else 00424 { 00425 w->x2 = ptr2->x1; 00426 w->Port2 = ptr2->Port1; 00427 ptr2->Port1->Connections.append(w); // shorten new wire 00428 return 2; 00429 } 00430 } 00431 } 00432 else continue; 00433 00434 pn = new Node(w->x2, w->y2); // create new node 00435 Nodes->append(pn); 00436 pn->Connections.append(w); // connect schematic node to the new wire 00437 w->Port2 = pn; 00438 00439 // split the wire into two wires 00440 splitWire(ptr2, pn); 00441 return 2; 00442 } 00443 00444 pn = new Node(w->x2, w->y2); // create new node 00445 Nodes->append(pn); 00446 pn->Connections.append(w); // connect schematic node to the new wire 00447 w->Port2 = pn; 00448 return 1; 00449 } 00450 00451 // --------------------------------------------------- 00452 // if possible, connect two horizontal wires to one 00453 bool Schematic::connectHWires2(Wire *w) 00454 { 00455 Wire *pw; 00456 Node *n = w->Port2; 00457 00458 pw = (Wire*)n->Connections.last(); // last connection is the new wire itself 00459 for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev()) 00460 { 00461 if(pw->Type != isWire) continue; 00462 if(!pw->isHorizontal()) continue; 00463 if(pw->x2 > w->x2) 00464 { 00465 if(n->Connections.count() != 2) continue; 00466 if(pw->Label) 00467 { 00468 w->Label = pw->Label; 00469 w->Label->pOwner = w; 00470 } 00471 w->x2 = pw->x2; 00472 w->Port2 = pw->Port2; // new wire lengthens an existing one 00473 Nodes->removeRef(n); 00474 w->Port2->Connections.removeRef(pw); 00475 w->Port2->Connections.append(w); 00476 Wires->removeRef(pw); 00477 return true; 00478 } 00479 // (if new wire lies complete within an existing one, was already 00480 // checked before) 00481 00482 if(pw->Port1->Connections.count() < 2) 00483 { 00484 // existing wire lies within the new one 00485 if(pw->Label) 00486 { 00487 w->Label = pw->Label; 00488 w->Label->pOwner = w; 00489 } 00490 pw->Port2->Connections.removeRef(pw); 00491 Nodes->removeRef(pw->Port1); 00492 Wires->removeRef(pw); 00493 return true; 00494 } 00495 w->x2 = pw->x1; // shorten new wire according to an existing one 00496 w->Port2->Connections.removeRef(w); 00497 w->Port2 = pw->Port1; 00498 w->Port2->Connections.append(w); 00499 return true; 00500 } 00501 00502 return true; 00503 } 00504 00505 // --------------------------------------------------- 00506 // if possible, connect two vertical wires to one 00507 bool Schematic::connectVWires2(Wire *w) 00508 { 00509 Wire *pw; 00510 Node *n = w->Port2; 00511 00512 pw = (Wire*)n->Connections.last(); // last connection is the new wire itself 00513 for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev()) 00514 { 00515 if(pw->Type != isWire) continue; 00516 if(pw->isHorizontal()) continue; 00517 if(pw->y2 > w->y2) 00518 { 00519 if(n->Connections.count() != 2) continue; 00520 if(pw->Label) 00521 { 00522 w->Label = pw->Label; 00523 w->Label->pOwner = w; 00524 } 00525 w->y2 = pw->y2; 00526 w->Port2 = pw->Port2; // new wire lengthens an existing one 00527 Nodes->removeRef(n); 00528 w->Port2->Connections.removeRef(pw); 00529 w->Port2->Connections.append(w); 00530 Wires->removeRef(pw); 00531 return true; 00532 } 00533 // (if new wire lies complete within an existing one, was already 00534 // checked before) 00535 00536 if(pw->Port1->Connections.count() < 2) 00537 { 00538 // existing wire lies within the new one 00539 if(pw->Label) 00540 { 00541 w->Label = pw->Label; 00542 w->Label->pOwner = w; 00543 } 00544 pw->Port2->Connections.removeRef(pw); 00545 Nodes->removeRef(pw->Port1); 00546 Wires->removeRef(pw); 00547 return true; 00548 } 00549 w->y2 = pw->y1; // shorten new wire according to an existing one 00550 w->Port2->Connections.removeRef(w); 00551 w->Port2 = pw->Port1; 00552 w->Port2->Connections.append(w); 00553 return true; 00554 } 00555 00556 return true; 00557 } 00558 00559 // --------------------------------------------------- 00560 // Inserts a vertical or horizontal wire into the schematic and connects 00561 // the ports that hit together. Returns whether the beginning and ending 00562 // (the ports of the wire) are connected or not. 00563 int Schematic::insertWire(Wire *w) 00564 { 00565 int tmp, con = 0; 00566 bool ok; 00567 00568 // change coordinates if necessary (port 1 coordinates must be less 00569 // port 2 coordinates) 00570 if(w->x1 > w->x2) 00571 { 00572 tmp = w->x1; 00573 w->x1 = w->x2; 00574 w->x2 = tmp; 00575 } 00576 else if(w->y1 > w->y2) 00577 { 00578 tmp = w->y1; 00579 w->y1 = w->y2; 00580 w->y2 = tmp; 00581 } 00582 else con = 0x100; 00583 00584 00585 00586 tmp = insertWireNode1(w); 00587 if(tmp == 0) return 3; // no new wire and no open connection 00588 if(tmp > 1) con |= 2; // insert node and remember if it remains open 00589 00590 if(w->isHorizontal()) ok = connectHWires1(w); 00591 else ok = connectVWires1(w); 00592 if(!ok) return 3; 00593 00594 00595 00596 00597 tmp = insertWireNode2(w); 00598 if(tmp == 0) return 3; // no new wire and no open connection 00599 if(tmp > 1) con |= 1; // insert node and remember if it remains open 00600 00601 if(w->isHorizontal()) ok = connectHWires2(w); 00602 else ok = connectVWires2(w); 00603 if(!ok) return 3; 00604 00605 00606 00607 // change node 1 and 2 00608 if(con > 255) con = ((con >> 1) & 1) | ((con << 1) & 2); 00609 00610 Wires->append(w); // add wire to the schematic 00611 00612 00613 00614 00615 int n1, n2; 00616 Wire *pw, *nw; 00617 Node *pn, *pn2; 00618 Element *pe; 00619 // ................................................................ 00620 // Check if the new line covers existing nodes. 00621 // In order to also check new appearing wires -> use "for"-loop 00622 for(pw = Wires->current(); pw != 0; pw = Wires->next()) 00623 for(pn = Nodes->first(); pn != 0; ) // check every node 00624 { 00625 if(pn->cx == pw->x1) 00626 { 00627 if(pn->cy <= pw->y1) 00628 { 00629 pn = Nodes->next(); 00630 continue; 00631 } 00632 if(pn->cy >= pw->y2) 00633 { 00634 pn = Nodes->next(); 00635 continue; 00636 } 00637 } 00638 else if(pn->cy == pw->y1) 00639 { 00640 if(pn->cx <= pw->x1) 00641 { 00642 pn = Nodes->next(); 00643 continue; 00644 } 00645 if(pn->cx >= pw->x2) 00646 { 00647 pn = Nodes->next(); 00648 continue; 00649 } 00650 } 00651 else 00652 { 00653 pn = Nodes->next(); 00654 continue; 00655 } 00656 00657 n1 = 2; 00658 n2 = 3; 00659 pn2 = pn; 00660 // check all connections of the current node 00661 for(pe=pn->Connections.first(); pe!=0; pe=pn->Connections.next()) 00662 { 00663 if(pe->Type != isWire) continue; 00664 nw = (Wire*)pe; 00665 // wire lies within the new ? 00666 if(pw->isHorizontal() != nw->isHorizontal()) continue; 00667 00668 pn = nw->Port1; 00669 pn2 = nw->Port2; 00670 n1 = pn->Connections.count(); 00671 n2 = pn2->Connections.count(); 00672 if(n1 == 1) 00673 { 00674 Nodes->removeRef(pn); // delete node 1 if open 00675 pn2->Connections.removeRef(nw); // remove connection 00676 pn = pn2; 00677 } 00678 00679 if(n2 == 1) 00680 { 00681 pn->Connections.removeRef(nw); // remove connection 00682 Nodes->removeRef(pn2); // delete node 2 if open 00683 pn2 = pn; 00684 } 00685 00686 if(pn == pn2) 00687 { 00688 if(nw->Label) 00689 { 00690 pw->Label = nw->Label; 00691 pw->Label->pOwner = pw; 00692 } 00693 Wires->removeRef(nw); // delete wire 00694 Wires->findRef(pw); // set back to current wire 00695 } 00696 break; 00697 } 00698 if(n1 == 1) if(n2 == 1) continue; 00699 00700 // split wire into two wires 00701 if((pw->x1 != pn->cx) || (pw->y1 != pn->cy)) 00702 { 00703 nw = new Wire(pw->x1, pw->y1, pn->cx, pn->cy, pw->Port1, pn); 00704 pn->Connections.append(nw); 00705 Wires->append(nw); 00706 Wires->findRef(pw); 00707 pw->Port1->Connections.append(nw); 00708 } 00709 pw->Port1->Connections.removeRef(pw); 00710 pw->x1 = pn2->cx; 00711 pw->y1 = pn2->cy; 00712 pw->Port1 = pn2; 00713 pn2->Connections.append(pw); 00714 00715 pn = Nodes->next(); 00716 } 00717 00718 if (Wires->containsRef (w)) // if two wire lines with different labels ... 00719 oneLabel(w->Port1); // ... are connected, delete one label 00720 return con | 0x0200; // sent also end flag 00721 } 00722 00723 // --------------------------------------------------- 00724 // Follows a wire line and selects it. 00725 void Schematic::selectWireLine(Element *pe, Node *pn, bool ctrl) 00726 { 00727 Node *pn_1st = pn; 00728 while(pn->Connections.count() == 2) 00729 { 00730 if(pn->Connections.first() == pe) pe = pn->Connections.last(); 00731 else pe = pn->Connections.first(); 00732 00733 if(pe->Type != isWire) break; 00734 if(ctrl) pe->isSelected ^= ctrl; 00735 else pe->isSelected = true; 00736 00737 if(((Wire*)pe)->Port1 == pn) pn = ((Wire*)pe)->Port2; 00738 else pn = ((Wire*)pe)->Port1; 00739 if(pn == pn_1st) break; // avoid endless loop in wire loops 00740 } 00741 } 00742 00743 // --------------------------------------------------- 00744 Wire* Schematic::selectedWire(int x, int y) 00745 { 00746 for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next()) 00747 if(pw->getSelected(x, y)) 00748 return pw; 00749 00750 return 0; 00751 } 00752 00753 // --------------------------------------------------- 00754 // Splits the wire "*pw" into two pieces by the node "*pn". 00755 Wire* Schematic::splitWire(Wire *pw, Node *pn) 00756 { 00757 Wire *newWire = new Wire(pn->cx, pn->cy, pw->x2, pw->y2, pn, pw->Port2); 00758 newWire->isSelected = pw->isSelected; 00759 00760 pw->x2 = pn->cx; 00761 pw->y2 = pn->cy; 00762 pw->Port2 = pn; 00763 00764 newWire->Port2->Connections.prepend(newWire); 00765 pn->Connections.prepend(pw); 00766 pn->Connections.prepend(newWire); 00767 newWire->Port2->Connections.removeRef(pw); 00768 Wires->append(newWire); 00769 00770 if(pw->Label) 00771 if((pw->Label->cx > pn->cx) || (pw->Label->cy > pn->cy)) 00772 { 00773 newWire->Label = pw->Label; // label goes to the new wire 00774 pw->Label = 0; 00775 newWire->Label->pOwner = newWire; 00776 } 00777 00778 return newWire; 00779 } 00780 00781 // --------------------------------------------------- 00782 // If possible, make one wire out of two wires. 00783 bool Schematic::oneTwoWires(Node *n) 00784 { 00785 Wire *e3; 00786 Wire *e1 = (Wire*)n->Connections.getFirst(); // two wires -> one wire 00787 Wire *e2 = (Wire*)n->Connections.getLast(); 00788 00789 if(e1->Type == isWire) if(e2->Type == isWire) 00790 if(e1->isHorizontal() == e2->isHorizontal()) 00791 { 00792 if(e1->x1 == e2->x2) if(e1->y1 == e2->y2) 00793 { 00794 e3 = e1; 00795 e1 = e2; 00796 e2 = e3; // e1 must have lesser coordinates 00797 } 00798 if(e2->Label) // take over the node name label ? 00799 { 00800 e1->Label = e2->Label; 00801 e1->Label->pOwner = e1; 00802 } 00803 else if(n->Label) 00804 { 00805 e1->Label = n->Label; 00806 e1->Label->pOwner = e1; 00807 if(e1->isHorizontal()) 00808 e1->Label->Type = isHWireLabel; 00809 else 00810 e1->Label->Type = isVWireLabel; 00811 } 00812 00813 e1->x2 = e2->x2; 00814 e1->y2 = e2->y2; 00815 e1->Port2 = e2->Port2; 00816 Nodes->removeRef(n); // delete node (is auto delete) 00817 e1->Port2->Connections.removeRef(e2); 00818 e1->Port2->Connections.append(e1); 00819 Wires->removeRef(e2); 00820 return true; 00821 } 00822 return false; 00823 } 00824 00825 // --------------------------------------------------- 00826 // Deletes the wire 'w'. 00827 void Schematic::deleteWire(Wire *w) 00828 { 00829 if(w->Port1->Connections.count() == 1) 00830 { 00831 if(w->Port1->Label) delete w->Port1->Label; 00832 Nodes->removeRef(w->Port1); // delete node 1 if open 00833 } 00834 else 00835 { 00836 w->Port1->Connections.removeRef(w); // remove connection 00837 if(w->Port1->Connections.count() == 2) 00838 oneTwoWires(w->Port1); // two wires -> one wire 00839 } 00840 00841 if(w->Port2->Connections.count() == 1) 00842 { 00843 if(w->Port2->Label) delete w->Port2->Label; 00844 Nodes->removeRef(w->Port2); // delete node 2 if open 00845 } 00846 else 00847 { 00848 w->Port2->Connections.removeRef(w); // remove connection 00849 if(w->Port2->Connections.count() == 2) 00850 oneTwoWires(w->Port2); // two wires -> one wire 00851 } 00852 00853 if(w->Label) 00854 { 00855 delete w->Label; 00856 w->Label = 0; 00857 } 00858 Wires->removeRef(w); 00859 } 00860 00861 // --------------------------------------------------- 00862 int Schematic::copyWires(int& x1, int& y1, int& x2, int& y2, 00863 QList<Element *> *ElementCache) 00864 { 00865 int count=0; 00866 Node *pn; 00867 Wire *pw; 00868 WireLabel *pl; 00869 for(pw = Wires->first(); pw != 0; ) // find bounds of all selected wires 00870 if(pw->isSelected) 00871 { 00872 if(pw->x1 < x1) x1 = pw->x1; 00873 if(pw->x2 > x2) x2 = pw->x2; 00874 if(pw->y1 < y1) y1 = pw->y1; 00875 if(pw->y2 > y2) y2 = pw->y2; 00876 00877 count++; 00878 ElementCache->append(pw); 00879 00880 // rescue non-selected node labels 00881 pn = pw->Port1; 00882 if(pn->Label) 00883 if(pn->Connections.count() < 2) 00884 { 00885 ElementCache->append(pn->Label); 00886 00887 // Don't set pn->Label->pOwner=0 , so text position stays unchanged. 00888 // But remember its wire. 00889 pn->Label->pOwner = (Node*)pw; 00890 pn->Label = 0; 00891 } 00892 pn = pw->Port2; 00893 if(pn->Label) 00894 if(pn->Connections.count() < 2) 00895 { 00896 ElementCache->append(pn->Label); 00897 00898 // Don't set pn->Label->pOwner=0 , so text position stays unchanged. 00899 // But remember its wire. 00900 pn->Label->pOwner = (Node*)pw; 00901 pn->Label = 0; 00902 } 00903 00904 pl = pw->Label; 00905 pw->Label = 0; 00906 deleteWire(pw); 00907 pw->Label = pl; // restore wire label 00908 pw = Wires->current(); 00909 } 00910 else pw = Wires->next(); 00911 00912 return count; 00913 } 00914 00915 00916 /* ******************************************************************* 00917 ***** ***** 00918 ***** Actions with markers ***** 00919 ***** ***** 00920 ******************************************************************* */ 00921 00922 Marker* Schematic::setMarker(int x, int y) 00923 { 00924 // only diagrams ... 00925 for(Diagram *pd = Diagrams->last(); pd != 0; pd = Diagrams->prev()){ 00926 if(Marker* m=pd->setMarker(x,y)){ 00927 setChanged(true, true); 00928 return m; 00929 } 00930 } 00931 return NULL; 00932 } 00933 00934 // --------------------------------------------------- 00935 // Moves the marker pointer left/right on the graph. 00936 void Schematic::markerLeftRight(bool left, Q3PtrList<Element> *Elements) 00937 { 00938 bool acted = false; 00939 for(auto i : *Elements) { 00940 Marker* pm = prechecked_cast<Marker*>(i); 00941 assert(pm); 00942 if(pm->moveLeftRight(left)) 00943 acted = true; 00944 } 00945 00946 if(acted) setChanged(true, true, 'm'); 00947 } 00948 00949 // --------------------------------------------------- 00950 // Moves the marker pointer up/down on the more-dimensional graph. 00951 void Schematic::markerUpDown(bool up, Q3PtrList<Element> *Elements) 00952 { 00953 Marker *pm; 00954 bool acted = false; 00955 for(pm = (Marker*)Elements->first(); pm!=0; pm = (Marker*)Elements->next()) 00956 { 00957 if(pm->moveUpDown(up)) 00958 acted = true; 00959 } 00960 00961 if(acted) setChanged(true, true, 'm'); 00962 } 00963 00964 00965 /* ******************************************************************* 00966 ***** ***** 00967 ***** Actions with all elements ***** 00968 ***** ***** 00969 ******************************************************************* */ 00970 00971 /* Selects the element that contains the coordinates x/y. 00972 Returns the pointer to the element. 00973 00974 If 'flag' is true, the element can be deselected. If 00975 'flag' is false the element cannot be deselected. The 00976 purpose of this is to prevent deselection in cases such 00977 as right-clicking on a selected element to get a context 00978 menu. 00979 */ 00980 Element* Schematic::selectElement(float fX, float fY, bool flag, int *index) 00981 { 00982 int n, x = int(fX), y = int(fY); 00983 Element *pe_1st = 0; 00984 Element *pe_sel = 0; 00985 WireLabel *pl = 0; 00986 float Corr = textCorr(); // for selecting text 00987 00988 // test all nodes and their labels 00989 for(Node *pn = Nodes->last(); pn != 0; pn = Nodes->prev()) 00990 { 00991 if(!flag) 00992 { 00993 // The element cannot be deselected 00994 if(index) 00995 { 00996 // 'index' is only true if called from MouseActions::MPressSelect() 00997 if(pn->getSelected(x, y)) 00998 { 00999 // Return the node pointer, as the selection cannot change 01000 return pn; 01001 } 01002 } 01003 } 01004 01005 pl = pn->Label; // Get any wire label associated with the Node 01006 if(pl) 01007 { 01008 if(pl->getSelected(x, y)) 01009 { 01010 if(flag) 01011 { 01012 // The element can be deselected, so toggle its isSelected member 01013 // TODO: I don't see a need for the xor here, a simple ! on the current value 01014 // would be clearer and have the same effect? 01015 pl->isSelected ^= flag; 01016 return pl; 01017 } 01018 if(pe_sel) 01019 { 01020 // There is another currently 01021 pe_sel->isSelected = false; 01022 return pl; 01023 } 01024 if(pe_1st == 0) 01025 { 01026 // give access to elements lying beneath by storing this label. 01027 // If no label pointer (or other element) has previously been 01028 // stored, the current label pointer is stored here. 01029 // pe_1st is returned if no other selected element 01030 pe_1st = pl; 01031 } 01032 if(pl->isSelected) 01033 { 01034 // if current label is already selected, store a pointer to it. 01035 // This can be used to cycle through 01036 pe_sel = pl; 01037 } 01038 } 01039 } 01040 } 01041 01042 // test all wires and wire labels 01043 for(Wire *pw = Wires->last(); pw != 0; pw = Wires->prev()) 01044 { 01045 if(pw->getSelected(x, y)) 01046 { 01047 if(flag) 01048 { 01049 // The element can be deselected 01050 pw->isSelected ^= flag; 01051 return pw; 01052 } 01053 if(pe_sel) 01054 { 01055 pe_sel->isSelected = false; 01056 return pw; 01057 } 01058 if(pe_1st == 0) 01059 { 01060 pe_1st = pw; // give access to elements lying beneath 01061 } 01062 if(pw->isSelected) 01063 { 01064 pe_sel = pw; 01065 } 01066 } 01067 pl = pw->Label; // test any label associated with the wire 01068 if(pl) 01069 { 01070 if(pl->getSelected(x, y)) 01071 { 01072 if(flag) 01073 { 01074 // The element can be deselected 01075 pl->isSelected ^= flag; 01076 return pl; 01077 } 01078 if(pe_sel) 01079 { 01080 pe_sel->isSelected = false; 01081 return pl; 01082 } 01083 if(pe_1st == 0) 01084 { 01085 // give access to elements lying beneath 01086 pe_1st = pl; 01087 } 01088 if(pl->isSelected) 01089 { 01090 pe_sel = pl; 01091 } 01092 } 01093 } 01094 } 01095 01096 // test all components 01097 for(Component *pc = Components->last(); pc != 0; pc = Components->prev()) 01098 { 01099 if(pc->getSelected(x, y)) 01100 { 01101 if(flag) 01102 { 01103 // The element can be deselected 01104 pc->isSelected ^= flag; 01105 return pc; 01106 } 01107 if(pe_sel) 01108 { 01109 pe_sel->isSelected = false; 01110 return pc; 01111 } 01112 if(pe_1st == 0) 01113 { 01114 pe_1st = pc; 01115 } // give access to elements lying beneath 01116 if(pc->isSelected) 01117 { 01118 pe_sel = pc; 01119 } 01120 } 01121 else 01122 { 01123 n = pc->getTextSelected(x, y, Corr); 01124 if(n >= 0) // was property text clicked ? 01125 { 01126 pc->Type = isComponentText; 01127 if(index) *index = n; 01128 return pc; 01129 } 01130 } 01131 } 01132 01133 Corr = 5.0 / Scale; // size of line select and area for resizing 01134 // test all diagrams 01135 for(Diagram *pd = Diagrams->last(); pd != 0; pd = Diagrams->prev()) 01136 { 01137 01138 foreach(Graph *pg, pd->Graphs) 01139 { 01140 // test markers of graphs 01141 foreach(Marker *pm, pg->Markers) 01142 { 01143 if(pm->getSelected(x-pd->cx, y-pd->cy)) 01144 { 01145 if(flag) 01146 { 01147 // The element can be deselected 01148 pm->isSelected ^= flag; 01149 return pm; 01150 } 01151 if(pe_sel) 01152 { 01153 pe_sel->isSelected = false; 01154 return pm; 01155 } 01156 if(pe_1st == 0) 01157 { 01158 pe_1st = pm; // give access to elements beneath 01159 } 01160 if(pm->isSelected) 01161 { 01162 pe_sel = pm; 01163 } 01164 } 01165 } 01166 } 01167 01168 // resize area clicked ? 01169 if(pd->isSelected) 01170 { 01171 if(pd->resizeTouched(fX, fY, Corr)) 01172 { 01173 if(pe_1st == 0) 01174 { 01175 pd->Type = isDiagramResize; 01176 return pd; 01177 } 01178 } 01179 } 01180 01181 if(pd->getSelected(x, y)) 01182 { 01183 if(pd->Name[0] == 'T') // tabular, timing diagram or truth table ? 01184 { 01185 if(pd->Name[1] == 'i') 01186 { 01187 if(y > pd->cy) 01188 { 01189 if(x < pd->cx+pd->xAxis.numGraphs) continue; 01190 pd->Type = isDiagramHScroll; 01191 return pd; 01192 } 01193 } 01194 else 01195 { 01196 if(x < pd->cx) // clicked on scroll bar ? 01197 { 01198 pd->Type = isDiagramVScroll; 01199 return pd; 01200 } 01201 } 01202 } 01203 01204 // test graphs of diagram 01205 foreach(Graph *pg, pd->Graphs) 01206 { 01207 if(pg->getSelected(x-pd->cx, pd->cy-y) >= 0) 01208 { 01209 if(flag) 01210 { 01211 // The element can be deselected 01212 pg->isSelected ^= flag; 01213 return pg; 01214 } 01215 if(pe_sel) 01216 { 01217 pe_sel->isSelected = false; 01218 return pg; 01219 } 01220 if(pe_1st == 0) 01221 { 01222 pe_1st = pg; // access to elements lying beneath 01223 } 01224 if(pg->isSelected) 01225 { 01226 pe_sel = pg; 01227 } 01228 } 01229 } 01230 01231 if(flag) 01232 { 01233 // The element can be deselected 01234 pd->isSelected ^= flag; 01235 return pd; 01236 } 01237 if(pe_sel) 01238 { 01239 pe_sel->isSelected = false; 01240 return pd; 01241 } 01242 if(pe_1st == 0) 01243 { 01244 pe_1st = pd; // give access to elements lying beneath 01245 } 01246 if(pd->isSelected) 01247 { 01248 pe_sel = pd; 01249 } 01250 } 01251 } 01252 01253 // test all paintings 01254 for(Painting *pp = Paintings->last(); pp != 0; pp = Paintings->prev()) 01255 { 01256 if(pp->isSelected) 01257 { 01258 if(pp->resizeTouched(fX, fY, Corr)) 01259 { 01260 if(pe_1st == 0) 01261 { 01262 pp->Type = isPaintingResize; 01263 return pp; 01264 } 01265 } 01266 } 01267 01268 if(pp->getSelected(fX, fY, Corr)) 01269 { 01270 if(flag) 01271 { 01272 // The element can be deselected 01273 pp->isSelected ^= flag; 01274 return pp; 01275 } 01276 if(pe_sel) 01277 { 01278 pe_sel->isSelected = false; 01279 return pp; 01280 } 01281 if(pe_1st == 0) 01282 { 01283 pe_1st = pp; // give access to elements lying beneath 01284 } 01285 if(pp->isSelected) 01286 { 01287 pe_sel = pp; 01288 } 01289 } 01290 } 01291 01292 return pe_1st; 01293 } 01294 01295 void Schematic::highlightWireLabels () 01296 { 01297 WireLabel *pltestinner = 0; 01298 WireLabel *pltestouter = 0; 01299 01300 // First set highlighting for all wire labels to false 01301 for(Wire *pwouter = Wires->last(); pwouter != 0; pwouter = Wires->prev()) 01302 { 01303 pltestouter = pwouter->Label; // test any label associated with the wire 01304 if (pltestouter) 01305 { 01306 pltestouter->setHighlighted (false); 01307 } 01308 } 01309 01310 // Then test every wire's label to see if we need to highlight it 01311 // and matching labels 01312 for(Wire *pwouter = Wires->last(); pwouter != 0; pwouter = Wires->prev()) 01313 { 01314 // get any label associated with the wire 01315 pltestouter = pwouter->Label; 01316 if (pltestouter) 01317 { 01318 if (pltestouter->isSelected) 01319 { 01320 // Search for matching labels 01321 for(Wire *pwinner = Wires->last(); pwinner != 0; pwinner = Wires->prev()) 01322 { 01323 pltestinner = pwinner->Label; // test any label associated with the wire 01324 if (pltestinner) 01325 { 01326 // Highlight the label if it has the same name as the selected label 01327 if (strcmp(pltestouter->Name, pltestinner->Name) == 0) 01328 { 01329 pltestinner->setHighlighted (true); 01330 } 01331 } 01332 } 01333 } 01334 } 01335 } 01336 } 01337 01338 // --------------------------------------------------- 01339 // Deselects all elements except 'e'. 01340 void Schematic::deselectElements(Element *e) 01341 { 01342 // test all components 01343 for(Component *pc = Components->first(); pc != 0; pc = Components->next()) 01344 if(e != pc) pc->isSelected = false; 01345 01346 // test all wires 01347 for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next()) 01348 { 01349 if(e != pw) pw->isSelected = false; 01350 if(pw->Label) if(pw->Label != e) pw->Label->isSelected = false; 01351 } 01352 01353 // test all node labels 01354 for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next()) 01355 if(pn->Label) if(pn->Label != e) pn->Label->isSelected = false; 01356 01357 // test all diagrams 01358 for(Diagram *pd = Diagrams->first(); pd != 0; pd = Diagrams->next()) 01359 { 01360 if(e != pd) pd->isSelected = false; 01361 01362 // test graphs of diagram 01363 foreach(Graph *pg, pd->Graphs) 01364 { 01365 if(e != pg) pg->isSelected = false; 01366 01367 // test markers of graph 01368 foreach(Marker *pm, pg->Markers) 01369 if(e != pm) pm->isSelected = false; 01370 } 01371 01372 } 01373 01374 // test all paintings 01375 for(Painting *pp = Paintings->first(); pp != 0; pp = Paintings->next()) 01376 if(e != pp) pp->isSelected = false; 01377 } 01378 01379 // --------------------------------------------------- 01380 // Selects elements that lie within the rectangle x1/y1, x2/y2. 01381 int Schematic::selectElements(int x1, int y1, int x2, int y2, bool flag) 01382 { 01383 int z=0; // counts selected elements 01384 int cx1, cy1, cx2, cy2; 01385 01386 // exchange rectangle coordinates to obtain x1 < x2 and y1 < y2 01387 cx1 = (x1 < x2) ? x1 : x2; 01388 cx2 = (x1 > x2) ? x1 : x2; 01389 cy1 = (y1 < y2) ? y1 : y2; 01390 cy2 = (y1 > y2) ? y1 : y2; 01391 x1 = cx1; 01392 x2 = cx2; 01393 y1 = cy1; 01394 y2 = cy2; 01395 01396 // test all components 01397 for(Component *pc = Components->first(); pc != 0; pc = Components->next()) 01398 { 01399 pc->Bounding(cx1, cy1, cx2, cy2); 01400 if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2) 01401 { 01402 pc->isSelected = true; 01403 z++; 01404 continue; 01405 } 01406 if(pc->isSelected &= flag) z++; 01407 } 01408 01409 01410 Wire *pw; 01411 for(pw = Wires->first(); pw != 0; pw = Wires->next()) // test all wires 01412 { 01413 if(pw->x1 >= x1) if(pw->x2 <= x2) if(pw->y1 >= y1) if(pw->y2 <= y2) 01414 { 01415 pw->isSelected = true; 01416 z++; 01417 continue; 01418 } 01419 if(pw->isSelected &= flag) z++; 01420 } 01421 01422 01423 // test all wire labels ********************************* 01424 WireLabel *pl=0; 01425 for(pw = Wires->first(); pw != 0; pw = Wires->next()) 01426 { 01427 if(pw->Label) 01428 { 01429 pl = pw->Label; 01430 if(pl->x1 >= x1) if((pl->x1+pl->x2) <= x2) 01431 if(pl->y1 >= y1) if((pl->y1+pl->y2) <= y2) 01432 { 01433 pl->isSelected = true; 01434 z++; 01435 continue; 01436 } 01437 if(pl->isSelected &= flag) z++; 01438 } 01439 } 01440 01441 01442 // test all node labels ************************************* 01443 for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next()) 01444 { 01445 pl = pn->Label; 01446 if(pl) 01447 { 01448 if(pl->x1 >= x1) if((pl->x1+pl->x2) <= x2) 01449 if((pl->y1-pl->y2) >= y1) if(pl->y1 <= y2) 01450 { 01451 pl->isSelected = true; 01452 z++; 01453 continue; 01454 } 01455 if(pl->isSelected &= flag) z++; 01456 } 01457 } 01458 01459 01460 // test all diagrams ******************************************* 01461 for(Diagram *pd = Diagrams->first(); pd != 0; pd = Diagrams->next()) 01462 { 01463 // test graphs of diagram 01464 foreach(Graph *pg, pd->Graphs) 01465 { 01466 if(pg->isSelected &= flag) z++; 01467 01468 // test markers of graph 01469 foreach(Marker *pm, pg->Markers) 01470 { 01471 pm->Bounding(cx1, cy1, cx2, cy2); 01472 if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2) 01473 { 01474 pm->isSelected = true; 01475 z++; 01476 continue; 01477 } 01478 if(pm->isSelected &= flag) z++; 01479 } 01480 } 01481 01482 // test diagram itself 01483 pd->Bounding(cx1, cy1, cx2, cy2); 01484 if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2) 01485 { 01486 pd->isSelected = true; 01487 z++; 01488 continue; 01489 } 01490 if(pd->isSelected &= flag) z++; 01491 } 01492 01493 // test all paintings ******************************************* 01494 for(Painting *pp = Paintings->first(); pp != 0; pp = Paintings->next()) 01495 { 01496 pp->Bounding(cx1, cy1, cx2, cy2); 01497 if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2) 01498 { 01499 pp->isSelected = true; 01500 z++; 01501 continue; 01502 } 01503 if(pp->isSelected &= flag) z++; 01504 } 01505 01506 return z; 01507 } 01508 01509 // --------------------------------------------------- 01510 // Selects all markers. 01511 void Schematic::selectMarkers() 01512 { 01513 for(Diagram *pd = Diagrams->first(); pd != 0; pd = Diagrams->next()) 01514 foreach(Graph *pg, pd->Graphs) 01515 foreach(Marker *pm, pg->Markers) 01516 pm->isSelected = true; 01517 } 01518 01519 // --------------------------------------------------- 01520 // For moving elements: If the moving element is connected to a not 01521 // moving element, insert two wires. If the connected element is already 01522 // a wire, use this wire. Otherwise create new wire. 01523 void Schematic::newMovingWires(Q3PtrList<Element> *p, Node *pn, int pos) 01524 { 01525 Element *pe; 01526 01527 if(pn->State & 8) // Were new wires already inserted ? 01528 return; 01529 pn->State |= 8; 01530 01531 for (;;) 01532 { 01533 if(pn->State & 16) // node was already worked on 01534 break; 01535 01536 pe = pn->Connections.getFirst(); 01537 if(pe == 0) return; 01538 01539 if(pn->Connections.count() > 1) 01540 break; 01541 if(pe->Type != isWire) // is it connected to exactly one wire ? 01542 break; 01543 01544 // ................................................. 01545 long mask = 1, invMask = 3; 01546 Wire *pw2=0, *pw = (Wire*)pe; 01547 01548 Node *pn2 = pw->Port1; 01549 if(pn2 == pn) pn2 = pw->Port2; 01550 01551 if(pn2->Connections.count() == 2) // two existing wires connected ? 01552 if((pn2->State & (8+4)) == 0) 01553 { 01554 Element *pe2 = pn2->Connections.getFirst(); 01555 if(pe2 == pe) pe2 = pn2->Connections.getLast(); 01556 // connected wire connected to exactly one wire ? 01557 if(pe2->Type == isWire) 01558 pw2 = (Wire*)pe2; 01559 } 01560 01561 // ................................................. 01562 // reuse one wire 01563 p->insert(pos, pw); 01564 pw->Port1->Connections.removeRef(pw); // remove connection 1 01565 pw->Port1->State |= 16+4; 01566 pw->Port2->Connections.removeRef(pw); // remove connection 2 01567 pw->Port2->State |= 16+4; 01568 Wires->take(Wires->findRef(pw)); 01569 01570 if(pw->isHorizontal()) mask = 2; 01571 01572 if(pw2 == 0) // place new wire between component and old wire 01573 { 01574 pn = pn2; 01575 mask ^= 3; 01576 invMask = 0; 01577 } 01578 01579 if(pw->Port1 != pn) 01580 { 01581 pw->Port1->State |= mask; 01582 pw->Port1 = (Node*)mask; 01583 pw->Port2->State |= invMask; 01584 pw->Port2 = (Node*)invMask; // move port 2 completely 01585 } 01586 else 01587 { 01588 pw->Port1->State |= invMask; 01589 pw->Port1 = (Node*)invMask; 01590 pw->Port2->State |= mask; 01591 pw->Port2 = (Node*)mask; 01592 } 01593 01594 invMask ^= 3; 01595 // ................................................. 01596 // create new wire ? 01597 if(pw2 == 0) 01598 { 01599 if(pw->Port1 != (Node*)mask) 01600 p->insert(pos, 01601 new Wire(pw->x2, pw->y2, pw->x2, pw->y2, (Node*)mask, (Node*)invMask)); 01602 else 01603 p->insert(pos, 01604 new Wire(pw->x1, pw->y1, pw->x1, pw->y1, (Node*)mask, (Node*)invMask)); 01605 return; 01606 } 01607 01608 01609 // ................................................. 01610 // reuse a second wire 01611 p->insert(pos, pw2); 01612 pw2->Port1->Connections.removeRef(pw2); // remove connection 1 01613 pw2->Port1->State |= 16+4; 01614 pw2->Port2->Connections.removeRef(pw2); // remove connection 2 01615 pw2->Port2->State |= 16+4; 01616 Wires->take(Wires->findRef(pw2)); 01617 01618 if(pw2->Port1 != pn2) 01619 { 01620 pw2->Port1 = (Node*)0; 01621 pw2->Port2->State |= mask; 01622 pw2->Port2 = (Node*)mask; 01623 } 01624 else 01625 { 01626 pw2->Port1->State |= mask; 01627 pw2->Port1 = (Node*)mask; 01628 pw2->Port2 = (Node*)0; 01629 } 01630 return; 01631 } 01632 01633 // only x2 moving 01634 p->insert(pos, new Wire(pn->cx, pn->cy, pn->cx, pn->cy, (Node*)0, (Node*)1)); 01635 // x1, x2, y2 moving 01636 p->insert(pos, new Wire(pn->cx, pn->cy, pn->cx, pn->cy, (Node*)1, (Node*)3)); 01637 } 01638 01639 // --------------------------------------------------- 01640 // For moving of elements: Copies all selected elements into the 01641 // list 'p' and deletes them from the document. 01642 // BUG: does not (only) copy, as the name suggests. 01643 // cannot be used to make copies. 01644 // returns the number of "copied" _Markers_ only 01645 int Schematic::copySelectedElements(Q3PtrList<Element> *p) 01646 { 01647 int i, count = 0; 01648 Component *pc; 01649 Wire *pw; 01650 Diagram *pd; 01651 Element *pe; 01652 Node *pn; 01653 01654 01655 // test all components ********************************* 01656 // Insert components before wires in order to prevent short-cut removal. 01657 for(pc = Components->first(); pc != 0; ) 01658 if(pc->isSelected) 01659 { 01660 p->append(pc); 01661 count++; 01662 01663 // delete all port connections 01664 foreach(Port *pp, pc->Ports) 01665 { 01666 pp->Connection->Connections.removeRef((Element*)pc); 01667 pp->Connection->State = 4; 01668 } 01669 01670 Components->take(); // take component out of the document 01671 pc = Components->current(); 01672 } 01673 else pc = Components->next(); 01674 01675 // test all wires and wire labels *********************** 01676 for(pw = Wires->first(); pw != 0; ) 01677 { 01678 if(pw->Label) if(pw->Label->isSelected) 01679 p->append(pw->Label); 01680 01681 if(pw->isSelected) 01682 { 01683 p->append(pw); 01684 01685 pw->Port1->Connections.removeRef(pw); // remove connection 1 01686 pw->Port1->State = 4; 01687 pw->Port2->Connections.removeRef(pw); // remove connection 2 01688 pw->Port2->State = 4; 01689 Wires->take(); 01690 pw = Wires->current(); 01691 } 01692 else pw = Wires->next(); 01693 } 01694 01695 // .............................................. 01696 // Inserts wires, if a connection to a not moving element is found. 01697 // The order of the "for"-loops is important to guarantee a stable 01698 // operation: components, new wires, old wires 01699 pc = (Component*)p->first(); 01700 for(i=0; i<count; i++) 01701 { 01702 foreach(Port *pp, pc->Ports) 01703 newMovingWires(p, pp->Connection, count); 01704 01705 p->findRef(pc); // back to the real current pointer 01706 pc = (Component*)p->next(); 01707 } 01708 01709 for(pe = (Element*)pc; pe != 0; pe = p->next()) // new wires 01710 if(pe->isSelected) 01711 break; 01712 01713 for(pw = (Wire*)pe; pw != 0; pw = (Wire*)p->next()) 01714 if(pw->Type == isWire) // not working on labels 01715 { 01716 newMovingWires(p, pw->Port1, count); 01717 newMovingWires(p, pw->Port2, count); 01718 p->findRef(pw); // back to the real current pointer 01719 } 01720 01721 01722 // .............................................. 01723 // delete the unused nodes 01724 for(pn = Nodes->first(); pn!=0; ) 01725 { 01726 if(pn->State & 8) 01727 if(pn->Connections.count() == 2) 01728 if(oneTwoWires(pn)) // if possible, connect two wires to one 01729 { 01730 pn = Nodes->current(); 01731 continue; 01732 } 01733 01734 if(pn->Connections.count() == 0) 01735 { 01736 if(pn->Label) 01737 { 01738 pn->Label->Type = isMovingLabel; 01739 if(pn->State & 1) 01740 { 01741 if(!(pn->State & 2)) pn->Label->Type = isHMovingLabel; 01742 } 01743 else if(pn->State & 2) pn->Label->Type = isVMovingLabel; 01744 p->append(pn->Label); // do not forget the node labels 01745 } 01746 Nodes->remove(); 01747 pn = Nodes->current(); 01748 continue; 01749 } 01750 01751 pn->State = 0; 01752 pn = Nodes->next(); 01753 } 01754 01755 // test all node labels 01756 // do this last to avoid double copying 01757 for(pn = Nodes->first(); pn != 0; pn = Nodes->next()) 01758 if(pn->Label) if(pn->Label->isSelected) 01759 p->append(pn->Label); 01760 01761 01762 // test all paintings ********************************** 01763 for(Painting *ppa = Paintings->first(); ppa != 0; ) 01764 if(ppa->isSelected) 01765 { 01766 p->append(ppa); 01767 Paintings->take(); 01768 ppa = Paintings->current(); 01769 } 01770 else ppa = Paintings->next(); 01771 01772 count = 0; // count markers now 01773 // test all diagrams ********************************** 01774 for(pd = Diagrams->first(); pd != 0; ) 01775 if(pd->isSelected) 01776 { 01777 p->append(pd); 01778 Diagrams->take(); 01779 pd = Diagrams->current(); 01780 } 01781 else 01782 { 01783 foreach(Graph *pg, pd->Graphs) 01784 { 01785 QMutableListIterator<Marker *> im(pg->Markers); 01786 Marker *pm; 01787 while (im.hasNext()) 01788 { 01789 pm = im.next(); 01790 if(pm->isSelected) 01791 { 01792 count++; 01793 p->append(pm); 01794 } 01795 } 01796 } 01797 01798 pd = Diagrams->next(); 01799 } 01800 01801 return count; 01802 } 01803 01804 // --------------------------------------------------- 01805 bool Schematic::copyComps2WiresPaints(int& x1, int& y1, int& x2, int& y2, 01806 QList<Element *> *ElementCache) 01807 { 01808 x1=INT_MAX; 01809 y1=INT_MAX; 01810 x2=INT_MIN; 01811 y2=INT_MIN; 01812 copyLabels(x1, y1, x2, y2, ElementCache); // must be first of all ! 01813 copyComponents2(x1, y1, x2, y2, ElementCache); 01814 copyWires(x1, y1, x2, y2, ElementCache); 01815 copyPaintings(x1, y1, x2, y2, ElementCache); 01816 01817 if(y1 == INT_MAX) return false; // no element selected 01818 return true; 01819 } 01820 01821 // --------------------------------------------------- 01822 // Used in "aligning()", "distributeHorizontal()", "distributeVertical()". 01823 int Schematic::copyElements(int& x1, int& y1, int& x2, int& y2, 01824 QList<Element *> *ElementCache) 01825 { 01826 int bx1, by1, bx2, by2; 01827 Wires->setAutoDelete(false); 01828 Components->setAutoDelete(false); 01829 01830 x1=INT_MAX; 01831 y1=INT_MAX; 01832 x2=INT_MIN; 01833 y2=INT_MIN; 01834 // take components and wires out of list, check their boundings 01835 int number = copyComponents(x1, y1, x2, y2, ElementCache); 01836 number += copyWires(x1, y1, x2, y2, ElementCache); 01837 01838 Wires->setAutoDelete(true); 01839 Components->setAutoDelete(true); 01840 01841 // find upper most selected diagram 01842 for(Diagram *pd = Diagrams->last(); pd != 0; pd = Diagrams->prev()) 01843 if(pd->isSelected) 01844 { 01845 pd->Bounding(bx1, by1, bx2, by2); 01846 if(bx1 < x1) x1 = bx1; 01847 if(bx2 > x2) x2 = bx2; 01848 if(by1 < y1) y1 = by1; 01849 if(by2 > y2) y2 = by2; 01850 ElementCache->append(pd); 01851 number++; 01852 } 01853 // find upper most selected painting 01854 for(Painting *pp = Paintings->last(); pp != 0; pp = Paintings->prev()) 01855 if(pp->isSelected) 01856 { 01857 pp->Bounding(bx1, by1, bx2, by2); 01858 if(bx1 < x1) x1 = bx1; 01859 if(bx2 > x2) x2 = bx2; 01860 if(by1 < y1) y1 = by1; 01861 if(by2 > y2) y2 = by2; 01862 ElementCache->append(pp); 01863 number++; 01864 } 01865 01866 return number; 01867 } 01868 01869 // --------------------------------------------------- 01870 // Deletes all selected elements. 01871 bool Schematic::deleteElements() 01872 { 01873 bool sel = false; 01874 01875 Component *pc = Components->first(); 01876 while(pc != 0) // all selected component 01877 if(pc->isSelected) 01878 { 01879 deleteComp(pc); 01880 pc = Components->current(); 01881 sel = true; 01882 } 01883 else pc = Components->next(); 01884 01885 Wire *pw = Wires->first(); 01886 while(pw != 0) // all selected wires and their labels 01887 { 01888 if(pw->Label) 01889 if(pw->Label->isSelected) 01890 { 01891 delete pw->Label; 01892 pw->Label = 0; 01893 sel = true; 01894 } 01895 01896 if(pw->isSelected) 01897 { 01898 deleteWire(pw); 01899 pw = Wires->current(); 01900 sel = true; 01901 } 01902 else pw = Wires->next(); 01903 } 01904 01905 // all selected labels on nodes *************************** 01906 for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next()) 01907 if(pn->Label) 01908 if(pn->Label->isSelected) 01909 { 01910 delete pn->Label; 01911 pn->Label = 0; 01912 sel = true; 01913 } 01914 01915 Diagram *pd = Diagrams->first(); 01916 while(pd != 0) // test all diagrams 01917 if(pd->isSelected) 01918 { 01919 Diagrams->remove(); 01920 pd = Diagrams->current(); 01921 sel = true; 01922 } 01923 else 01924 { 01925 bool wasGraphDeleted = false; 01926 // all graphs of diagram 01927 01928 QMutableListIterator<Graph *> ig(pd->Graphs); 01929 Graph *pg; 01930 01931 while (ig.hasNext()) 01932 { 01933 pg = ig.next(); 01934 // all markers of diagram 01935 QMutableListIterator<Marker *> im(pg->Markers); 01936 Marker *pm; 01937 while (im.hasNext()) 01938 { 01939 pm = im.next(); 01940 if(pm->isSelected) 01941 { 01942 im.remove(); 01943 sel = true; 01944 } 01945 } 01946 01947 if(pg->isSelected) 01948 { 01949 ig.remove(); 01950 sel = wasGraphDeleted = true; 01951 } 01952 } 01953 if(wasGraphDeleted) 01954 pd->recalcGraphData(); // update diagram (resize etc.) 01955 01956 pd = Diagrams->next(); 01957 } //else 01958 01959 01960 Painting *pp = Paintings->first(); 01961 while(pp != 0) // test all paintings 01962 { 01963 if(pp->isSelected) 01964 if(pp->Name.at(0) != '.') // do not delete "PortSym", "ID_text" 01965 { 01966 sel = true; 01967 Paintings->remove(); 01968 pp = Paintings->current(); 01969 continue; 01970 } 01971 pp = Paintings->next(); 01972 } 01973 01974 if(sel) 01975 { 01976 sizeOfAll(UsedX1, UsedY1, UsedX2, UsedY2); // set new document size 01977 setChanged(sel, true); 01978 } 01979 return sel; 01980 } 01981 01982 // --------------------------------------------------- 01988 bool Schematic::aligning(int Mode) 01989 { 01990 int x1, y1, x2, y2; 01991 int bx1, by1, bx2, by2, *bx=0, *by=0, *ax=0, *ay=0; 01992 QList<Element *> ElementCache; 01993 int count = copyElements(x1, y1, x2, y2, &ElementCache); 01994 if(count < 1) return false; 01995 01996 01997 ax = ay = &x2; // = 0 01998 switch(Mode) 01999 { 02000 case 0: // align top 02001 bx = &x1; 02002 by = &by1; 02003 y2 = 1; 02004 break; 02005 case 1: // align bottom 02006 bx = &x1; 02007 y1 = y2; 02008 by = &by2; 02009 y2 = 1; 02010 break; 02011 case 2: // align left 02012 by = &y1; 02013 bx = &bx1; 02014 y2 = 1; 02015 break; 02016 case 3: // align right 02017 by = &y1; 02018 x1 = x2; 02019 bx = &bx2; 02020 y2 = 1; 02021 break; 02022 case 4: // center horizontally 02023 x1 = (x2+x1) / 2; 02024 by = &x2; // = 0 02025 ax = &bx1; 02026 bx = &bx2; 02027 y1 = 0; 02028 y2 = 2; 02029 break; 02030 case 5: // center vertically 02031 y1 = (y2+y1) / 2; 02032 bx = &x2; // = 0 02033 ay = &by1; 02034 by = &by2; 02035 x1 = 0; 02036 y2 = 2; 02037 break; 02038 } 02039 x2 = 0; 02040 02041 Wire *pw; 02042 Component *pc; 02043 Element *pe; 02044 // re-insert elements 02045 // Go backwards in order to insert node labels before its component. 02046 QListIterator<Element *> elementCacheIter(ElementCache); 02047 elementCacheIter.toBack(); 02048 while (elementCacheIter.hasPrevious()) { 02049 pe = elementCacheIter.previous(); 02050 switch(pe->Type) 02051 { 02052 case isComponent: 02053 case isAnalogComponent: 02054 case isDigitalComponent: 02055 pc = (Component*)pe; 02056 pc->Bounding(bx1, by1, bx2, by2); 02057 pc->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true); 02058 insertRawComponent(pc); 02059 break; 02060 02061 case isWire: 02062 pw = (Wire*)pe; 02063 bx1 = pw->x1; 02064 by1 = pw->y1; 02065 bx2 = pw->x2; 02066 by2 = pw->y2; 02067 pw->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true); 02068 // if(pw->Label) { } 02069 insertWire(pw); 02070 break; 02071 02072 case isDiagram: 02073 // Should the axis label be counted for ? I guess everyone 02074 // has a different opinion. 02075 // ((Diagram*)pe)->Bounding(bx1, by1, bx2, by2); 02076 02077 // Take size without axis label. 02078 bx1 = ((Diagram*)pe)->cx; 02079 by2 = ((Diagram*)pe)->cy; 02080 bx2 = bx1 + ((Diagram*)pe)->x2; 02081 by1 = by2 - ((Diagram*)pe)->y2; 02082 ((Diagram*)pe)->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true); 02083 break; 02084 02085 case isPainting: 02086 ((Painting*)pe)->Bounding(bx1, by1, bx2, by2); 02087 ((Painting*)pe)->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true); 02088 break; 02089 02090 case isNodeLabel: 02091 if(((Element*)(((WireLabel*)pe)->pOwner))->Type & isComponent) 02092 { 02093 pc = (Component*)(((WireLabel*)pe)->pOwner); 02094 pc->Bounding(bx1, by1, bx2, by2); 02095 } 02096 else 02097 { 02098 pw = (Wire*)(((WireLabel*)pe)->pOwner); 02099 bx1 = pw->x1; 02100 by1 = pw->y1; 02101 bx2 = pw->x2; 02102 by2 = pw->y2; 02103 } 02104 ((WireLabel*)pe)->cx += x1-((*bx)+(*ax))/y2; 02105 ((WireLabel*)pe)->cy += y1-((*by)+(*ay))/y2; 02106 insertNodeLabel((WireLabel*)pe); 02107 break; 02108 02109 default: 02110 ; 02111 } 02112 } 02113 02114 ElementCache.clear(); 02115 if(count < 2) return false; 02116 02117 setChanged(true, true); 02118 return true; 02119 } 02120 02125 bool Schematic::distributeHorizontal() 02126 { 02127 int x1, y1, x2, y2; 02128 int bx1, by1, bx2, by2; 02129 QList<Element *> ElementCache; 02130 int count = copyElements(x1, y1, x2, y2, &ElementCache); 02131 if(count < 1) return false; 02132 02133 Element *pe; 02134 WireLabel *pl; 02135 // Node labels are not counted for, so put them to the end. 02136 /* for(pe = ElementCache.last(); pe != 0; pe = ElementCache.prev()) 02137 if(pe->Type == isNodeLabel) { 02138 ElementCache.append(pe); 02139 ElementCache.removeRef(pe); 02140 }*/ 02141 02142 // using bubble sort to get elements x ordered 02143 QListIterator<Element *> elementCacheIter(ElementCache); 02144 if(count > 1) 02145 for(int i = count-1; i>0; i--) 02146 { 02147 pe = ElementCache.first(); 02148 for(int j=0; j<i; j++) 02149 { 02150 pe->getCenter(bx1, by1); 02151 pe=elementCacheIter.peekNext(); 02152 pe->getCenter(bx2, by2); 02153 if(bx1 > bx2) // change two elements ? 02154 { 02155 ElementCache.replace(j+1, elementCacheIter.peekPrevious()); 02156 ElementCache.replace(j, pe); 02157 pe = elementCacheIter.next(); 02158 } 02159 } 02160 } 02161 02162 ElementCache.last()->getCenter(x2, y2); 02163 ElementCache.first()->getCenter(x1, y1); 02164 Wire *pw; 02165 int x = x2; 02166 int dx=0; 02167 if(count > 1) dx = (x2-x1)/(count-1); 02168 // re-insert elements and put them at right position 02169 // Go backwards in order to insert node labels before its component. 02170 elementCacheIter.toBack(); 02171 while (elementCacheIter.hasPrevious()) 02172 { 02173 pe = elementCacheIter.previous(); 02174 switch(pe->Type) 02175 { 02176 case isComponent: 02177 case isAnalogComponent: 02178 case isDigitalComponent: 02179 pe->cx = x; 02180 insertRawComponent((Component*)pe); 02181 break; 02182 02183 case isWire: 02184 pw = (Wire*)pe; 02185 if(pw->isHorizontal()) 02186 { 02187 x1 = pw->x2 - pw->x1; 02188 pw->x1 = x - (x1 >> 1); 02189 pw->x2 = pw->x1 + x1; 02190 } 02191 else pw->x1 = pw->x2 = x; 02192 // if(pw->Label) { } 02193 insertWire(pw); 02194 break; 02195 02196 case isDiagram: 02197 pe->cx = x - (pe->x2 >> 1); 02198 break; 02199 02200 case isPainting: 02201 pe->getCenter(bx1, by1); 02202 pe->setCenter(x, by1, false); 02203 break; 02204 02205 case isNodeLabel: 02206 pl = (WireLabel*)pe; 02207 if(((Element*)(pl->pOwner))->Type & isComponent) 02208 pe->cx += x - ((Component*)(pl->pOwner))->cx; 02209 else 02210 { 02211 pw = (Wire*)(pl->pOwner); 02212 if(pw->isHorizontal()) 02213 { 02214 x1 = pw->x2 - pw->x1; 02215 pe->cx += x - (x1 >> 1) - pw->x1; 02216 } 02217 else pe->cx += x - pw->x1; 02218 } 02219 insertNodeLabel(pl); 02220 x += dx; 02221 break; 02222 02223 default: 02224 ; 02225 } 02226 x -= dx; 02227 } 02228 02229 ElementCache.clear(); 02230 if(count < 2) return false; 02231 02232 setChanged(true, true); 02233 return true; 02234 } 02235 02240 bool Schematic::distributeVertical() 02241 { 02242 int x1, y1, x2, y2; 02243 int bx1, by1, bx2, by2; 02244 QList<Element *> ElementCache; 02245 int count = copyElements(x1, y1, x2, y2, &ElementCache); 02246 if(count < 1) return false; 02247 02248 // using bubble sort to get elements y ordered 02249 QListIterator<Element *> elementCacheIter(ElementCache); 02250 Element *pe; 02251 if(count > 1) 02252 for(int i = count-1; i>0; i--) 02253 { 02254 pe = ElementCache.first(); 02255 for(int j=0; j<i; j++) 02256 { 02257 pe->getCenter(bx1, by1); 02258 pe = elementCacheIter.peekNext(); 02259 pe->getCenter(bx2, by2); 02260 if(by1 > by2) // change two elements ? 02261 { 02262 ElementCache.replace(j+1, elementCacheIter.peekPrevious()); 02263 ElementCache.replace(j, pe); 02264 pe = elementCacheIter.next(); 02265 } 02266 } 02267 } 02268 02269 ElementCache.last()->getCenter(x2, y2); 02270 ElementCache.first()->getCenter(x1, y1); 02271 Wire *pw; 02272 int y = y2; 02273 int dy=0; 02274 if(count > 1) dy = (y2-y1)/(count-1); 02275 // re-insert elements and put them at right position 02276 // Go backwards in order to insert node labels before its component. 02277 elementCacheIter.toBack(); 02278 while (elementCacheIter.hasPrevious()) 02279 { 02280 pe = elementCacheIter.previous(); 02281 switch(pe->Type) 02282 { 02283 case isComponent: 02284 case isAnalogComponent: 02285 case isDigitalComponent: 02286 pe->cy = y; 02287 insertRawComponent((Component*)pe); 02288 break; 02289 02290 case isWire: 02291 pw = (Wire*)pe; 02292 if(pw->isHorizontal()) pw->y1 = pw->y2 = y; 02293 else 02294 { 02295 y1 = pw->y2 - pw->y1; 02296 pw->y1 = y - (y1 >> 1); 02297 pw->y2 = pe->y1 + y1; 02298 } 02299 // if(pw->Label) { } 02300 insertWire(pw); 02301 break; 02302 02303 case isDiagram: 02304 pe->cy = y + (pe->y2 >> 1); 02305 break; 02306 02307 case isPainting: 02308 pe->getCenter(bx1, by1); 02309 pe->setCenter(bx1, y, false); 02310 break; 02311 02312 case isNodeLabel: 02313 if(((Element*)(((WireLabel*)pe)->pOwner))->Type & isComponent) 02314 pe->cy += y - ((Component*)(((WireLabel*)pe)->pOwner))->cy; 02315 else 02316 { 02317 pw = (Wire*)(((WireLabel*)pe)->pOwner); 02318 if(!pw->isHorizontal()) 02319 { 02320 y1 = pw->y2 - pw->y1; 02321 pe->cy += y - (y1 >> 1) - pw->y1; 02322 } 02323 else pe->cy += y - pw->y1; 02324 } 02325 insertNodeLabel((WireLabel*)pe); 02326 y += dy; 02327 break; 02328 02329 default: 02330 ; 02331 } 02332 y -= dy; 02333 } 02334 02335 ElementCache.clear(); 02336 if(count < 2) return false; 02337 02338 setChanged(true, true); 02339 return true; 02340 } 02341 02342 02343 /* ******************************************************************* 02344 ***** ***** 02345 ***** Actions with components ***** 02346 ***** ***** 02347 ******************************************************************* */ 02348 02349 // Finds the correct number for power sources, subcircuit ports and 02350 // digital sources and sets them accordingly. 02351 void Schematic::setComponentNumber(Component *c) 02352 { 02353 Property *pp = c->Props.getFirst(); 02354 if(!pp) return; 02355 if(pp->Name != "Num") return; 02356 02357 int n=1; 02358 QString s = pp->Value; 02359 QString cSign = c->Model; 02360 Component *pc; 02361 // First look, if the port number already exists. 02362 for(pc = Components->first(); pc != 0; pc = Components->next()) 02363 if(pc->Model == cSign) 02364 if(pc->Props.getFirst()->Value == s) break; 02365 if(!pc) return; // was port number not yet in use ? 02366 02367 // Find the first free number. 02368 do 02369 { 02370 s = QString::number(n); 02371 // look for existing ports and their numbers 02372 for(pc = Components->first(); pc != 0; pc = Components->next()) 02373 if(pc->Model == cSign) 02374 if(pc->Props.getFirst()->Value == s) break; 02375 02376 n++; 02377 } 02378 while(pc); // found not used component number 02379 pp->Value = s; // set new number 02380 } 02381 02382 // --------------------------------------------------- 02383 void Schematic::insertComponentNodes(Component *c, bool noOptimize) 02384 { 02385 // simulation components do not have ports 02386 if (c->Ports.empty()) return; 02387 02388 // connect every node of the component to corresponding schematic node 02389 foreach(Port *pp, c->Ports) 02390 pp->Connection = insertNode(pp->x+c->cx, pp->y+c->cy, c); 02391 02392 if(noOptimize) return; 02393 02394 Node *pn; 02395 Element *pe, *pe1; 02396 Q3PtrList<Element> *pL; 02397 // if component over wire then delete this wire 02398 QListIterator<Port *> iport(c->Ports); 02399 // omit the first element 02400 Port *pp = iport.next(); 02401 while (iport.hasNext()) 02402 { 02403 pp = iport.next(); 02404 pn = pp->Connection; 02405 for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next()) 02406 if(pe->Type == isWire) 02407 { 02408 if(((Wire*)pe)->Port1 == pn) pL = &(((Wire*)pe)->Port2->Connections); 02409 else pL = &(((Wire*)pe)->Port1->Connections); 02410 02411 for(pe1 = pL->first(); pe1!=0; pe1 = pL->next()) 02412 if(pe1 == c) 02413 { 02414 deleteWire((Wire*)pe); 02415 break; 02416 } 02417 } 02418 } 02419 } 02420 02421 // --------------------------------------------------- 02422 // Used for example in moving components. 02423 void Schematic::insertRawComponent(Component *c, bool noOptimize) 02424 { 02425 // connect every node of component to corresponding schematic node 02426 insertComponentNodes(c, noOptimize); 02427 Components->append(c); 02428 02429 // a ground symbol erases an existing label on the wire line 02430 if(c->Model == "GND") 02431 { 02432 c->Model = "x"; // prevent that this ground is found as label 02433 Element *pe = getWireLabel(c->Ports.first()->Connection); 02434 if(pe) if((pe->Type & isComponent) == 0) 02435 { 02436 delete ((Conductor*)pe)->Label; 02437 ((Conductor*)pe)->Label = 0; 02438 } 02439 c->Model = "GND"; // rebuild component model 02440 } 02441 } 02442 02443 // --------------------------------------------------- 02444 void Schematic::recreateComponent(Component *Comp) 02445 { 02446 02447 WireLabel **plMem=0, **pl; 02448 int PortCount = Comp->Ports.count(); 02449 02450 if(PortCount > 0) 02451 { 02452 // Save the labels whose node is not connected to somewhere else. 02453 // Otherwise the label would be deleted. 02454 pl = plMem = (WireLabel**)malloc(PortCount * sizeof(WireLabel*)); 02455 foreach(Port *pp, Comp->Ports) 02456 if(pp->Connection->Connections.count() < 2) 02457 { 02458 *(pl++) = pp->Connection->Label; 02459 pp->Connection->Label = 0; 02460 } 02461 else *(pl++) = 0; 02462 } 02463 02464 02465 int x = Comp->tx, y = Comp->ty; 02466 int x1 = Comp->x1, x2 = Comp->x2, y1 = Comp->y1, y2 = Comp->y2; 02467 QString tmp = Comp->Name; // is sometimes changed by "recreate" 02468 Comp->recreate(this); // to apply changes to the schematic symbol 02469 Comp->Name = tmp; 02470 if(x < x1) 02471 x += Comp->x1 - x1; 02472 else if(x > x2) 02473 x += Comp->x2 - x2; 02474 if(y < y1) 02475 y += Comp->y1 - y1; 02476 else if(y > y2) 02477 y += Comp->y2 - y2; 02478 Comp->tx = x; 02479 Comp->ty = y; 02480 02481 02482 if(PortCount > 0) 02483 { 02484 // restore node labels 02485 pl = plMem; 02486 foreach(Port *pp, Comp->Ports) 02487 { 02488 if(*pl != 0) 02489 { 02490 (*pl)->cx = pp->Connection->cx; 02491 (*pl)->cy = pp->Connection->cy; 02492 placeNodeLabel(*pl); 02493 } 02494 pl++; 02495 if((--PortCount) < 1) break; 02496 } 02497 for( ; PortCount > 0; PortCount--) 02498 { 02499 delete (*pl); // delete not needed labels 02500 pl++; 02501 } 02502 free(plMem); 02503 } 02504 } 02505 02506 // --------------------------------------------------- 02507 void Schematic::insertComponent(Component *c) 02508 { 02509 // connect every node of component to corresponding schematic node 02510 insertComponentNodes(c, false); 02511 02512 bool ok; 02513 QString s; 02514 int max=1, len = c->Name.length(), z; 02515 if(c->Name.isEmpty()) 02516 { 02517 // a ground symbol erases an existing label on the wire line 02518 if(c->Model == "GND") 02519 { 02520 c->Model = "x"; // prevent that this ground is found as label 02521 Element *pe = getWireLabel(c->Ports.first()->Connection); 02522 if(pe) if((pe->Type & isComponent) == 0) 02523 { 02524 delete ((Conductor*)pe)->Label; 02525 ((Conductor*)pe)->Label = 0; 02526 } 02527 c->Model = "GND"; // rebuild component model 02528 } 02529 } 02530 else 02531 { 02532 // determines the name by looking for names with the same 02533 // prefix and increment the number 02534 for(Component *pc = Components->first(); pc != 0; pc = Components->next()) 02535 if(pc->Name.left(len) == c->Name) 02536 { 02537 s = pc->Name.right(pc->Name.length()-len); 02538 z = s.toInt(&ok); 02539 if(ok) if(z >= max) max = z + 1; 02540 } 02541 c->Name += QString::number(max); // create name with new number 02542 } 02543 02544 setComponentNumber(c); // important for power sources and subcircuit ports 02545 Components->append(c); 02546 } 02547 02548 // --------------------------------------------------- 02549 void Schematic::activateCompsWithinRect(int x1, int y1, int x2, int y2) 02550 { 02551 bool changed = false; 02552 int cx1, cy1, cx2, cy2, a; 02553 // exchange rectangle coordinates to obtain x1 < x2 and y1 < y2 02554 cx1 = (x1 < x2) ? x1 : x2; 02555 cx2 = (x1 > x2) ? x1 : x2; 02556 cy1 = (y1 < y2) ? y1 : y2; 02557 cy2 = (y1 > y2) ? y1 : y2; 02558 x1 = cx1; 02559 x2 = cx2; 02560 y1 = cy1; 02561 y2 = cy2; 02562 02563 02564 for(Component *pc = Components->first(); pc != 0; pc = Components->next()) 02565 { 02566 pc->Bounding(cx1, cy1, cx2, cy2); 02567 if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2) 02568 { 02569 a = pc->isActive - 1; 02570 02571 if(pc->Ports.count() > 1) 02572 { 02573 if(a < 0) a = 2; 02574 pc->isActive = a; // change "active status" 02575 } 02576 else 02577 { 02578 a &= 1; 02579 pc->isActive = a; // change "active status" 02580 if(a == COMP_IS_ACTIVE) // only for active (not shorten) 02581 if(pc->Model == "GND") // if existing, delete label on wire line 02582 oneLabel(pc->Ports.first()->Connection); 02583 } 02584 changed = true; 02585 } 02586 } 02587 02588 if(changed) setChanged(true, true); 02589 } 02590 02591 // --------------------------------------------------- 02592 bool Schematic::activateSpecifiedComponent(int x, int y) 02593 { 02594 int x1, y1, x2, y2, a; 02595 for(Component *pc = Components->first(); pc != 0; pc = Components->next()) 02596 { 02597 pc->Bounding(x1, y1, x2, y2); 02598 if(x >= x1) if(x <= x2) if(y >= y1) if(y <= y2) 02599 { 02600 a = pc->isActive - 1; 02601 02602 if(pc->Ports.count() > 1) 02603 { 02604 if(a < 0) a = 2; 02605 pc->isActive = a; // change "active status" 02606 } 02607 else 02608 { 02609 a &= 1; 02610 pc->isActive = a; // change "active status" 02611 if(a == COMP_IS_ACTIVE) // only for active (not shorten) 02612 if(pc->Model == "GND") // if existing, delete label on wire line 02613 oneLabel(pc->Ports.first()->Connection); 02614 } 02615 setChanged(true, true); 02616 return true; 02617 } 02618 } 02619 return false; 02620 } 02621 02622 // --------------------------------------------------- 02623 bool Schematic::activateSelectedComponents() 02624 { 02625 int a; 02626 bool sel = false; 02627 for(Component *pc = Components->first(); pc != 0; pc = Components->next()) 02628 if(pc->isSelected) 02629 { 02630 a = pc->isActive - 1; 02631 02632 if(pc->Ports.count() > 1) 02633 { 02634 if(a < 0) a = 2; 02635 pc->isActive = a; // change "active status" 02636 } 02637 else 02638 { 02639 a &= 1; 02640 pc->isActive = a; // change "active status" 02641 if(a == COMP_IS_ACTIVE) // only for active (not shorten) 02642 if(pc->Model == "GND") // if existing, delete label on wire line 02643 oneLabel(pc->Ports.first()->Connection); 02644 } 02645 sel = true; 02646 } 02647 02648 if(sel) setChanged(true, true); 02649 return sel; 02650 } 02651 02652 // --------------------------------------------------- 02653 // Sets the component ports anew. Used after rotate, mirror etc. 02654 void Schematic::setCompPorts(Component *pc) 02655 { 02656 WireLabel *pl; 02657 Q3PtrList<WireLabel> LabelCache; 02658 02659 foreach(Port *pp, pc->Ports) 02660 { 02661 pp->Connection->Connections.removeRef((Element*)pc);// delete connections 02662 switch(pp->Connection->Connections.count()) 02663 { 02664 case 0: 02665 pl = pp->Connection->Label; 02666 if(pl) 02667 { 02668 LabelCache.append(pl); 02669 pl->cx = pp->x + pc->cx; 02670 pl->cy = pp->y + pc->cy; 02671 } 02672 Nodes->removeRef(pp->Connection); 02673 break; 02674 case 2: 02675 oneTwoWires(pp->Connection); // try to connect two wires to one 02676 default: 02677 ; 02678 } 02679 } 02680 02681 // Re-connect component node to schematic node. This must be done completely 02682 // after the first loop in order to avoid problems with node labels. 02683 foreach(Port *pp, pc->Ports) 02684 pp->Connection = insertNode(pp->x+pc->cx, pp->y+pc->cy, pc); 02685 02686 for(pl = LabelCache.first(); pl != 0; pl = LabelCache.next()) 02687 insertNodeLabel(pl); 02688 } 02689 02690 // --------------------------------------------------- 02691 // Returns a pointer of the component on whose text x/y points. 02692 Component* Schematic::selectCompText(int x_, int y_, int& w, int& h) 02693 { 02694 int a, b, dx, dy; 02695 for(Component *pc = Components->first(); pc != 0; pc = Components->next()) 02696 { 02697 a = pc->cx + pc->tx; 02698 if(x_ < a) continue; 02699 b = pc->cy + pc->ty; 02700 if(y_ < b) continue; 02701 02702 pc->textSize(dx, dy); 02703 if(x_ > a+dx) continue; 02704 if(y_ > b+dy) continue; 02705 02706 w = dx; 02707 h = dy; 02708 return pc; 02709 } 02710 02711 return 0; 02712 } 02713 02714 // --------------------------------------------------- 02715 Component* Schematic::searchSelSubcircuit() 02716 { 02717 Component *sub=0; 02718 // test all components 02719 for(Component *pc = Components->first(); pc != 0; pc = Components->next()) 02720 { 02721 if(!pc->isSelected) continue; 02722 if(pc->Model != "Sub") 02723 if(pc->Model != "VHDL") 02724 if(pc->Model != "Verilog") continue; 02725 02726 if(sub != 0) return 0; // more than one subcircuit selected 02727 sub = pc; 02728 } 02729 return sub; 02730 } 02731 02732 // --------------------------------------------------- 02733 Component* Schematic::selectedComponent(int x, int y) 02734 { 02735 // test all components 02736 for(Component *pc = Components->first(); pc != 0; pc = Components->next()) 02737 if(pc->getSelected(x, y)) 02738 return pc; 02739 02740 return 0; 02741 } 02742 02743 // --------------------------------------------------- 02744 // Deletes the component 'c'. 02745 void Schematic::deleteComp(Component *c) 02746 { 02747 // delete all port connections 02748 foreach(Port *pn, c->Ports) 02749 switch(pn->Connection->Connections.count()) 02750 { 02751 case 1 : 02752 if(pn->Connection->Label) delete pn->Connection->Label; 02753 Nodes->removeRef(pn->Connection); // delete open nodes 02754 pn->Connection = 0; // (auto-delete) 02755 break; 02756 case 3 : 02757 pn->Connection->Connections.removeRef(c);// delete connection 02758 oneTwoWires(pn->Connection); // two wires -> one wire 02759 break; 02760 default : 02761 pn->Connection->Connections.removeRef(c);// remove connection 02762 break; 02763 } 02764 02765 Components->removeRef(c); // delete component 02766 } 02767 02768 // --------------------------------------------------- 02769 int Schematic::copyComponents(int& x1, int& y1, int& x2, int& y2, 02770 QList<Element *> *ElementCache) 02771 { 02772 Component *pc; 02773 int bx1, by1, bx2, by2, count=0; 02774 // find bounds of all selected components 02775 for(pc = Components->first(); pc != 0; ) 02776 { 02777 if(pc->isSelected) 02778 { 02779 pc->Bounding(bx1, by1, bx2, by2); // is needed because of "distribute 02780 if(bx1 < x1) x1 = bx1; // uniformly" 02781 if(bx2 > x2) x2 = bx2; 02782 if(by1 < y1) y1 = by1; 02783 if(by2 > y2) y2 = by2; 02784 02785 count++; 02786 ElementCache->append(pc); 02787 02788 // rescue non-selected node labels 02789 foreach(Port *pp, pc->Ports) 02790 if(pp->Connection->Label) 02791 if(pp->Connection->Connections.count() < 2) 02792 { 02793 ElementCache->append(pp->Connection->Label); 02794 02795 // Don't set pp->Connection->Label->pOwner=0, 02796 // so text position stays unchanged, but 02797 // remember component for align/distribute. 02798 pp->Connection->Label->pOwner = (Node*)pc; 02799 02800 pp->Connection->Label = 0; 02801 } 02802 02803 deleteComp(pc); 02804 pc = Components->current(); 02805 continue; 02806 } 02807 pc = Components->next(); 02808 } 02809 return count; 02810 } 02811 02812 // --------------------------------------------------- 02813 void Schematic::copyComponents2(int& x1, int& y1, int& x2, int& y2, 02814 QList<Element *> *ElementCache) 02815 { 02816 Component *pc; 02817 // find bounds of all selected components 02818 for(pc = Components->first(); pc != 0; ) 02819 { 02820 if(pc->isSelected) 02821 { 02822 // is better for unsymmetrical components 02823 if(pc->cx < x1) x1 = pc->cx; 02824 if(pc->cx > x2) x2 = pc->cx; 02825 if(pc->cy < y1) y1 = pc->cy; 02826 if(pc->cy > y2) y2 = pc->cy; 02827 02828 ElementCache->append(pc); 02829 02830 // rescue non-selected node labels 02831 foreach(Port *pp, pc->Ports) 02832 if(pp->Connection->Label) 02833 if(pp->Connection->Connections.count() < 2) 02834 { 02835 ElementCache->append(pp->Connection->Label); 02836 pp->Connection->Label = 0; 02837 // Don't set pp->Connection->Label->pOwner=0, 02838 // so text position stays unchanged. 02839 } 02840 02841 deleteComp(pc); 02842 pc = Components->current(); 02843 continue; 02844 } 02845 pc = Components->next(); 02846 } 02847 } 02848 02849 02850 /* ******************************************************************* 02851 ***** ***** 02852 ***** Actions with labels ***** 02853 ***** ***** 02854 ******************************************************************* */ 02855 02856 // Test, if wire connects wire line with more than one label and delete 02857 // all further labels. Also delete all labels if wire line is grounded. 02858 void Schematic::oneLabel(Node *n1) 02859 { 02860 Wire *pw; 02861 Node *pn, *pNode; 02862 Element *pe; 02863 WireLabel *pl = 0; 02864 bool named=false; // wire line already named ? 02865 Q3PtrList<Node> Cons; 02866 02867 for(pn = Nodes->first(); pn!=0; pn = Nodes->next()) 02868 pn->y1 = 0; // mark all nodes as not checked 02869 02870 Cons.append(n1); 02871 n1->y1 = 1; // mark Node as already checked 02872 for(pn = Cons.first(); pn!=0; pn = Cons.next()) 02873 { 02874 if(pn->Label) 02875 { 02876 if(named) 02877 { 02878 delete pn->Label; 02879 pn->Label = 0; // erase double names 02880 } 02881 else 02882 { 02883 named = true; 02884 pl = pn->Label; 02885 } 02886 } 02887 02888 for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next()) 02889 { 02890 if(pe->Type != isWire) 02891 { 02892 if(((Component*)pe)->isActive == COMP_IS_ACTIVE) 02893 if(((Component*)pe)->Model == "GND") 02894 { 02895 named = true; 02896 if(pl) 02897 { 02898 pl->pOwner->Label = 0; 02899 delete pl; 02900 } 02901 pl = 0; 02902 } 02903 continue; 02904 } 02905 pw = (Wire*)pe; 02906 02907 if(pn != pw->Port1) pNode = pw->Port1; 02908 else pNode = pw->Port2; 02909 02910 if(pNode->y1) continue; 02911 pNode->y1 = 1; // mark Node as already checked 02912 Cons.append(pNode); 02913 Cons.findRef(pn); 02914 02915 if(pw->Label) 02916 { 02917 if(named) 02918 { 02919 delete pw->Label; 02920 pw->Label = 0; // erase double names 02921 } 02922 else 02923 { 02924 named = true; 02925 pl = pw->Label; 02926 } 02927 } 02928 } 02929 } 02930 } 02931 02932 // --------------------------------------------------- 02933 int Schematic::placeNodeLabel(WireLabel *pl) 02934 { 02935 Node *pn; 02936 int x = pl->cx; 02937 int y = pl->cy; 02938 02939 // check if new node lies upon an existing node 02940 for(pn = Nodes->first(); pn != 0; pn = Nodes->next()) 02941 if(pn->cx == x) if(pn->cy == y) break; 02942 02943 if(!pn) return -1; 02944 02945 Element *pe = getWireLabel(pn); 02946 if(pe) // name found ? 02947 { 02948 if(pe->Type & isComponent) 02949 { 02950 delete pl; 02951 return -2; // ground potential 02952 } 02953 02954 delete ((Conductor*)pe)->Label; 02955 ((Conductor*)pe)->Label = 0; 02956 } 02957 02958 pn->Label = pl; // insert node label 02959 pl->Type = isNodeLabel; 02960 pl->pOwner = pn; 02961 return 0; 02962 } 02963 02964 // --------------------------------------------------- 02965 // Test, if wire line is already labeled and returns a pointer to the 02966 // labeled element. 02967 Element* Schematic::getWireLabel(Node *pn_) 02968 { 02969 Wire *pw; 02970 Node *pn, *pNode; 02971 Element *pe; 02972 Q3PtrList<Node> Cons; 02973 02974 for(pn = Nodes->first(); pn!=0; pn = Nodes->next()) 02975 pn->y1 = 0; // mark all nodes as not checked 02976 02977 Cons.append(pn_); 02978 pn_->y1 = 1; // mark Node as already checked 02979 for(pn = Cons.first(); pn!=0; pn = Cons.next()) 02980 if(pn->Label) return pn; 02981 else 02982 for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next()) 02983 { 02984 if(pe->Type != isWire) 02985 { 02986 if(((Component*)pe)->isActive == COMP_IS_ACTIVE) 02987 if(((Component*)pe)->Model == "GND") return pe; 02988 continue; 02989 } 02990 02991 pw = (Wire*)pe; 02992 if(pw->Label) return pw; 02993 02994 if(pn != pw->Port1) pNode = pw->Port1; 02995 else pNode = pw->Port2; 02996 02997 if(pNode->y1) continue; 02998 pNode->y1 = 1; // mark Node as already checked 02999 Cons.append(pNode); 03000 Cons.findRef(pn); 03001 } 03002 return 0; // no wire label found 03003 } 03004 03005 // --------------------------------------------------- 03006 // Inserts a node label. 03007 void Schematic::insertNodeLabel(WireLabel *pl) 03008 { 03009 if(placeNodeLabel(pl) != -1) 03010 return; 03011 03012 // Go on, if label don't lie on existing node. 03013 03014 Wire *pw = selectedWire(pl->cx, pl->cy); 03015 if(pw) // lies label on existing wire ? 03016 { 03017 if(getWireLabel(pw->Port1) == 0) // wire not yet labeled ? 03018 pw->setName(pl->Name, pl->initValue, 0, pl->cx, pl->cy); 03019 03020 delete pl; 03021 return; 03022 } 03023 03024 03025 Node *pn = new Node(pl->cx, pl->cy); 03026 Nodes->append(pn); 03027 03028 pn->Label = pl; 03029 pl->Type = isNodeLabel; 03030 pl->pOwner = pn; 03031 } 03032 03033 // --------------------------------------------------- 03034 void Schematic::copyLabels(int& x1, int& y1, int& x2, int& y2, 03035 QList<Element *> *ElementCache) 03036 { 03037 WireLabel *pl; 03038 // find bounds of all selected wires 03039 for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next()) 03040 { 03041 pl = pw->Label; 03042 if(pl) if(pl->isSelected) 03043 { 03044 if(pl->x1 < x1) x1 = pl->x1; 03045 if(pl->y1-pl->y2 < y1) y1 = pl->y1-pl->y2; 03046 if(pl->x1+pl->x2 > x2) x2 = pl->x1+pl->x2; 03047 if(pl->y1 > y2) y2 = pl->y1; 03048 ElementCache->append(pl); 03049 } 03050 } 03051 03052 for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next()) 03053 { 03054 pl = pn->Label; 03055 if(pl) if(pl->isSelected) 03056 { 03057 if(pl->x1 < x1) x1 = pl->x1; 03058 if(pl->y1-pl->y2 < y1) y1 = pl->y1-pl->y2; 03059 if(pl->x1+pl->x2 > x2) x2 = pl->x1+pl->x2; 03060 if(pl->y1 > y2) y2 = pl->y1; 03061 ElementCache->append(pl); 03062 pl->pOwner->Label = 0; // erase connection 03063 pl->pOwner = 0; 03064 } 03065 } 03066 } 03067 03068 03069 /* ******************************************************************* 03070 ***** ***** 03071 ***** Actions with paintings ***** 03072 ***** ***** 03073 ******************************************************************* */ 03074 03075 Painting* Schematic::selectedPainting(float fX, float fY) 03076 { 03077 float Corr = 5.0 / Scale; // size of line select 03078 03079 for(Painting *pp = Paintings->first(); pp != 0; pp = Paintings->next()) 03080 if(pp->getSelected(fX, fY, Corr)) 03081 return pp; 03082 03083 return 0; 03084 } 03085 03086 // --------------------------------------------------- 03087 void Schematic::copyPaintings(int& x1, int& y1, int& x2, int& y2, 03088 QList<Element *> *ElementCache) 03089 { 03090 Painting *pp; 03091 int bx1, by1, bx2, by2; 03092 // find boundings of all selected paintings 03093 for(pp = Paintings->first(); pp != 0; ) 03094 if(pp->isSelected) 03095 { 03096 pp->Bounding(bx1, by1, bx2, by2); 03097 if(bx1 < x1) x1 = bx1; 03098 if(bx2 > x2) x2 = bx2; 03099 if(by1 < y1) y1 = by1; 03100 if(by2 > y2) y2 = by2; 03101 03102 ElementCache->append(pp); 03103 Paintings->take(); 03104 pp = Paintings->current(); 03105 } 03106 else pp = Paintings->next(); 03107 } 03108 03109 // vim:ts=8:sw=2:noet