My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
schematic_element.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  schematic_element.cpp
3  -----------------------
4  begin : Sat Mar 3 2006
5  copyright : (C) 2006 by Michael Margraf
6  email : michael.margraf@alumni.tu-berlin.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include <stdlib.h>
19 #include <limits.h>
20 
21 #include "schematic.h"
22 #include "node.h"
23 #include "wire.h"
24 #include "diagrams/diagram.h"
25 #include "paintings/painting.h"
26 #include "components/component.h"
27 
28 
29 
30 /* *******************************************************************
31  ***** *****
32  ***** Actions handling the nodes *****
33  ***** *****
34  ******************************************************************* */
35 
36 // Inserts a port into the schematic and connects it to another node if
37 // the coordinates are identical. The node is returned.
39 {
40  Node *pn;
41  // check if new node lies upon existing node
42  for(pn = Nodes->first(); pn != 0; pn = Nodes->next()) // check every node
43  if(pn->cx == x) if(pn->cy == y) {
44  pn->Connections.append(e);
45  break;
46  }
47 
48  if(pn == 0) { // create new node, if no existing one lies at this position
49  pn = new Node(x, y);
50  Nodes->append(pn);
51  pn->Connections.append(e); // connect schematic node to component node
52  }
53  else return pn; // return, if node is not new
54 
55  // check if the new node lies upon an existing wire
56  for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next()) {
57  if(pw->x1 == x) {
58  if(pw->y1 > y) continue;
59  if(pw->y2 < y) continue;
60  }
61  else if(pw->y1 == y) {
62  if(pw->x1 > x) continue;
63  if(pw->x2 < x) continue;
64  }
65  else continue;
66 
67  // split the wire into two wires
68  splitWire(pw, pn);
69  return pn;
70  }
71 
72  return pn;
73 }
74 
75 // ---------------------------------------------------
77 {
78  for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next()) // test nodes
79  if(pn->getSelected(x, y))
80  return pn;
81 
82  return 0;
83 }
84 
85 
86 /* *******************************************************************
87  ***** *****
88  ***** Actions handling the wires *****
89  ***** *****
90  ******************************************************************* */
91 
92 // Inserts a port into the schematic and connects it to another node if the
93 // coordinates are identical. If 0 is returned, no new wire is inserted.
94 // If 2 is returned, the wire line ended.
96 {
97  Node *pn;
98  // check if new node lies upon an existing node
99  for(pn = Nodes->first(); pn != 0; pn = Nodes->next()) // check every node
100  if(pn->cx == w->x1) if(pn->cy == w->y1) break;
101 
102  if(pn != 0) {
103  pn->Connections.append(w);
104  w->Port1 = pn;
105  return 2; // node is not new
106  }
107 
108 
109 
110  // check if the new node lies upon an existing wire
111  for(Wire *ptr2 = Wires->first(); ptr2 != 0; ptr2 = Wires->next()) {
112  if(ptr2->x1 == w->x1) {
113  if(ptr2->y1 > w->y1) continue;
114  if(ptr2->y2 < w->y1) continue;
115 
116  if(ptr2->isHorizontal() == w->isHorizontal()) { // ptr2-wire is vertical
117  if(ptr2->y2 >= w->y2) {
118  delete w; // new wire lies within an existing wire
119  return 0; }
120  else {
121  // one part of the wire lies within an existing wire
122  // the other part not
123  if(ptr2->Port2->Connections.count() == 1) {
124  w->y1 = ptr2->y1;
125  w->Port1 = ptr2->Port1;
126  if(ptr2->Label) {
127  w->Label = ptr2->Label;
128  w->Label->pOwner = w;
129  }
130  ptr2->Port1->Connections.removeRef(ptr2); // two -> one wire
131  ptr2->Port1->Connections.append(w);
132  Nodes->removeRef(ptr2->Port2);
133  Wires->removeRef(ptr2);
134  return 2;
135  }
136  else {
137  w->y1 = ptr2->y2;
138  w->Port1 = ptr2->Port2;
139  ptr2->Port2->Connections.append(w); // shorten new wire
140  return 2;
141  }
142  }
143  }
144  }
145  else if(ptr2->y1 == w->y1) {
146  if(ptr2->x1 > w->x1) continue;
147  if(ptr2->x2 < w->x1) continue;
148 
149  if(ptr2->isHorizontal() == w->isHorizontal()) { // ptr2-wire is horizontal
150  if(ptr2->x2 >= w->x2) {
151  delete w; // new wire lies within an existing wire
152  return 0;
153  }
154  else {
155  // one part of the wire lies within an existing wire
156  // the other part not
157  if(ptr2->Port2->Connections.count() == 1) {
158  w->x1 = ptr2->x1;
159  w->Port1 = ptr2->Port1;
160  if(ptr2->Label) {
161  w->Label = ptr2->Label;
162  w->Label->pOwner = w;
163  }
164  ptr2->Port1->Connections.removeRef(ptr2); // two -> one wire
165  ptr2->Port1->Connections.append(w);
166  Nodes->removeRef(ptr2->Port2);
167  Wires->removeRef(ptr2);
168  return 2;
169  }
170  else {
171  w->x1 = ptr2->x2;
172  w->Port1 = ptr2->Port2;
173  ptr2->Port2->Connections.append(w); // shorten new wire
174  return 2;
175  }
176  }
177  }
178  }
179  else continue;
180 
181  pn = new Node(w->x1, w->y1); // create new node
182  Nodes->append(pn);
183  pn->Connections.append(w); // connect schematic node to the new wire
184  w->Port1 = pn;
185 
186  // split the wire into two wires
187  splitWire(ptr2, pn);
188  return 2;
189  }
190 
191  pn = new Node(w->x1, w->y1); // create new node
192  Nodes->append(pn);
193  pn->Connections.append(w); // connect schematic node to the new wire
194  w->Port1 = pn;
195  return 1;
196 }
197 
198 // ---------------------------------------------------
199 // if possible, connect two horizontal wires to one
201 {
202  Wire *pw;
203  Node *n = w->Port1;
204 
205  pw = (Wire*)n->Connections.last(); // last connection is the new wire itself
206  for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev()) {
207  if(pw->Type != isWire) continue;
208  if(!pw->isHorizontal()) continue;
209  if(pw->x1 < w->x1) {
210  if(n->Connections.count() != 2) continue;
211  if(pw->Label) {
212  w->Label = pw->Label;
213  w->Label->pOwner = w;
214  }
215  else if(n->Label) {
216  w->Label = n->Label;
217  w->Label->pOwner = w;
218  w->Label->Type = isHWireLabel;
219  }
220  w->x1 = pw->x1;
221  w->Port1 = pw->Port1; // new wire lengthens an existing one
222  Nodes->removeRef(n);
223  w->Port1->Connections.removeRef(pw);
224  w->Port1->Connections.append(w);
225  Wires->removeRef(pw);
226  return true;
227  }
228  if(pw->x2 >= w->x2) { // new wire lies within an existing one ?
229  w->Port1->Connections.removeRef(w); // second node not yet made
230  delete w;
231  return false;
232  }
233  if(pw->Port2->Connections.count() < 2) {
234  // existing wire lies within the new one
235  if(pw->Label) {
236  w->Label = pw->Label;
237  w->Label->pOwner = w;
238  }
239  pw->Port1->Connections.removeRef(pw);
240  Nodes->removeRef(pw->Port2);
241  Wires->removeRef(pw);
242  return true;
243  }
244  w->x1 = pw->x2; // shorten new wire according to an existing one
245  w->Port1->Connections.removeRef(w);
246  w->Port1 = pw->Port2;
247  w->Port1->Connections.append(w);
248  return true;
249  }
250 
251  return true;
252 }
253 
254 // ---------------------------------------------------
255 // if possible, connect two vertical wires to one
257 {
258  Wire *pw;
259  Node *n = w->Port1;
260 
261  pw = (Wire*)n->Connections.last(); // last connection is the new wire itself
262  for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev()) {
263  if(pw->Type != isWire) continue;
264  if(pw->isHorizontal()) continue;
265  if(pw->y1 < w->y1) {
266  if(n->Connections.count() != 2) continue;
267  if(pw->Label) {
268  w->Label = pw->Label;
269  w->Label->pOwner = w;
270  }
271  else if(n->Label) {
272  w->Label = n->Label;
273  w->Label->pOwner = w;
274  w->Label->Type = isVWireLabel;
275  }
276  w->y1 = pw->y1;
277  w->Port1 = pw->Port1; // new wire lengthens an existing one
278  Nodes->removeRef(n);
279  w->Port1->Connections.removeRef(pw);
280  w->Port1->Connections.append(w);
281  Wires->removeRef(pw);
282  return true;
283  }
284  if(pw->y2 >= w->y2) { // new wire lies complete within an existing one ?
285  w->Port1->Connections.removeRef(w); // second node not yet made
286  delete w;
287  return false;
288  }
289  if(pw->Port2->Connections.count() < 2) {
290  // existing wire lies within the new one
291  if(pw->Label) {
292  w->Label = pw->Label;
293  w->Label->pOwner = w;
294  }
295  pw->Port1->Connections.removeRef(pw);
296  Nodes->removeRef(pw->Port2);
297  Wires->removeRef(pw);
298  return true;
299  }
300  w->y1 = pw->y2; // shorten new wire according to an existing one
301  w->Port1->Connections.removeRef(w);
302  w->Port1 = pw->Port2;
303  w->Port1->Connections.append(w);
304  return true;
305  }
306 
307  return true;
308 }
309 
310 // ---------------------------------------------------
311 // Inserts a port into the schematic and connects it to another node if the
312 // coordinates are identical. If 0 is returned, no new wire is inserted.
313 // If 2 is returned, the wire line ended.
315 {
316  Node *pn;
317  // check if new node lies upon an existing node
318  for(pn = Nodes->first(); pn != 0; pn = Nodes->next()) // check every node
319  if(pn->cx == w->x2) if(pn->cy == w->y2) break;
320 
321  if(pn != 0) {
322  pn->Connections.append(w);
323  w->Port2 = pn;
324  return 2; // node is not new
325  }
326 
327 
328 
329  // check if the new node lies upon an existing wire
330  for(Wire *ptr2 = Wires->first(); ptr2 != 0; ptr2 = Wires->next()) {
331  if(ptr2->x1 == w->x2) {
332  if(ptr2->y1 > w->y2) continue;
333  if(ptr2->y2 < w->y2) continue;
334 
335  // (if new wire lies within an existing wire, was already check before)
336  if(ptr2->isHorizontal() == w->isHorizontal()) { // ptr2-wire is vertical
337  // one part of the wire lies within an existing wire
338  // the other part not
339  if(ptr2->Port1->Connections.count() == 1) {
340  if(ptr2->Label) {
341  w->Label = ptr2->Label;
342  w->Label->pOwner = w;
343  }
344  w->y2 = ptr2->y2;
345  w->Port2 = ptr2->Port2;
346  ptr2->Port2->Connections.removeRef(ptr2); // two -> one wire
347  ptr2->Port2->Connections.append(w);
348  Nodes->removeRef(ptr2->Port1);
349  Wires->removeRef(ptr2);
350  return 2;
351  }
352  else {
353  w->y2 = ptr2->y1;
354  w->Port2 = ptr2->Port1;
355  ptr2->Port1->Connections.append(w); // shorten new wire
356  return 2;
357  }
358  }
359  }
360  else if(ptr2->y1 == w->y2) {
361  if(ptr2->x1 > w->x2) continue;
362  if(ptr2->x2 < w->x2) continue;
363 
364  // (if new wire lies within an existing wire, was already check before)
365  if(ptr2->isHorizontal() == w->isHorizontal()) { // ptr2-wire is horizontal
366  // one part of the wire lies within an existing wire
367  // the other part not
368  if(ptr2->Port1->Connections.count() == 1) {
369  if(ptr2->Label) {
370  w->Label = ptr2->Label;
371  w->Label->pOwner = w;
372  }
373  w->x2 = ptr2->x2;
374  w->Port2 = ptr2->Port2;
375  ptr2->Port2->Connections.removeRef(ptr2); // two -> one wire
376  ptr2->Port2->Connections.append(w);
377  Nodes->removeRef(ptr2->Port1);
378  Wires->removeRef(ptr2);
379  return 2;
380  }
381  else {
382  w->x2 = ptr2->x1;
383  w->Port2 = ptr2->Port1;
384  ptr2->Port1->Connections.append(w); // shorten new wire
385  return 2;
386  }
387  }
388  }
389  else continue;
390 
391  pn = new Node(w->x2, w->y2); // create new node
392  Nodes->append(pn);
393  pn->Connections.append(w); // connect schematic node to the new wire
394  w->Port2 = pn;
395 
396  // split the wire into two wires
397  splitWire(ptr2, pn);
398  return 2;
399  }
400 
401  pn = new Node(w->x2, w->y2); // create new node
402  Nodes->append(pn);
403  pn->Connections.append(w); // connect schematic node to the new wire
404  w->Port2 = pn;
405  return 1;
406 }
407 
408 // ---------------------------------------------------
409 // if possible, connect two horizontal wires to one
411 {
412  Wire *pw;
413  Node *n = w->Port2;
414 
415  pw = (Wire*)n->Connections.last(); // last connection is the new wire itself
416  for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev()) {
417  if(pw->Type != isWire) continue;
418  if(!pw->isHorizontal()) continue;
419  if(pw->x2 > w->x2) {
420  if(n->Connections.count() != 2) continue;
421  if(pw->Label) {
422  w->Label = pw->Label;
423  w->Label->pOwner = w;
424  }
425  w->x2 = pw->x2;
426  w->Port2 = pw->Port2; // new wire lengthens an existing one
427  Nodes->removeRef(n);
428  w->Port2->Connections.removeRef(pw);
429  w->Port2->Connections.append(w);
430  Wires->removeRef(pw);
431  return true;
432  }
433  // (if new wire lies complete within an existing one, was already
434  // checked before)
435 
436  if(pw->Port1->Connections.count() < 2) {
437  // existing wire lies within the new one
438  if(pw->Label) {
439  w->Label = pw->Label;
440  w->Label->pOwner = w;
441  }
442  pw->Port2->Connections.removeRef(pw);
443  Nodes->removeRef(pw->Port1);
444  Wires->removeRef(pw);
445  return true;
446  }
447  w->x2 = pw->x1; // shorten new wire according to an existing one
448  w->Port2->Connections.removeRef(w);
449  w->Port2 = pw->Port1;
450  w->Port2->Connections.append(w);
451  return true;
452  }
453 
454  return true;
455 }
456 
457 // ---------------------------------------------------
458 // if possible, connect two vertical wires to one
460 {
461  Wire *pw;
462  Node *n = w->Port2;
463 
464  pw = (Wire*)n->Connections.last(); // last connection is the new wire itself
465  for(pw = (Wire*)n->Connections.prev(); pw!=0; pw = (Wire*)n->Connections.prev()) {
466  if(pw->Type != isWire) continue;
467  if(pw->isHorizontal()) continue;
468  if(pw->y2 > w->y2) {
469  if(n->Connections.count() != 2) continue;
470  if(pw->Label) {
471  w->Label = pw->Label;
472  w->Label->pOwner = w;
473  }
474  w->y2 = pw->y2;
475  w->Port2 = pw->Port2; // new wire lengthens an existing one
476  Nodes->removeRef(n);
477  w->Port2->Connections.removeRef(pw);
478  w->Port2->Connections.append(w);
479  Wires->removeRef(pw);
480  return true;
481  }
482  // (if new wire lies complete within an existing one, was already
483  // checked before)
484 
485  if(pw->Port1->Connections.count() < 2) {
486  // existing wire lies within the new one
487  if(pw->Label) {
488  w->Label = pw->Label;
489  w->Label->pOwner = w;
490  }
491  pw->Port2->Connections.removeRef(pw);
492  Nodes->removeRef(pw->Port1);
493  Wires->removeRef(pw);
494  return true;
495  }
496  w->y2 = pw->y1; // shorten new wire according to an existing one
497  w->Port2->Connections.removeRef(w);
498  w->Port2 = pw->Port1;
499  w->Port2->Connections.append(w);
500  return true;
501  }
502 
503  return true;
504 }
505 
506 // ---------------------------------------------------
507 // Inserts a vertical or horizontal wire into the schematic and connects
508 // the ports that hit together. Returns whether the beginning and ending
509 // (the ports of the wire) are connected or not.
511 {
512  int tmp, con = 0;
513  bool ok;
514 
515  // change coordinates if necessary (port 1 coordinates must be less
516  // port 2 coordinates)
517  if(w->x1 > w->x2) { tmp = w->x1; w->x1 = w->x2; w->x2 = tmp; }
518  else
519  if(w->y1 > w->y2) { tmp = w->y1; w->y1 = w->y2; w->y2 = tmp; }
520  else con = 0x100;
521 
522 
523 
524  tmp = insertWireNode1(w);
525  if(tmp == 0) return 3; // no new wire and no open connection
526  if(tmp > 1) con |= 2; // insert node and remember if it remains open
527 
528  if(w->isHorizontal()) ok = connectHWires1(w);
529  else ok = connectVWires1(w);
530  if(!ok) return 3;
531 
532 
533 
534 
535  tmp = insertWireNode2(w);
536  if(tmp == 0) return 3; // no new wire and no open connection
537  if(tmp > 1) con |= 1; // insert node and remember if it remains open
538 
539  if(w->isHorizontal()) ok = connectHWires2(w);
540  else ok = connectVWires2(w);
541  if(!ok) return 3;
542 
543 
544 
545  // change node 1 and 2
546  if(con > 255) con = ((con >> 1) & 1) | ((con << 1) & 2);
547 
548  Wires->append(w); // add wire to the schematic
549 
550 
551 
552 
553  int n1, n2;
554  Wire *pw, *nw;
555  Node *pn, *pn2;
556  Element *pe;
557  // ................................................................
558  // Check if the new line covers existing nodes.
559  // In order to also check new appearing wires -> use "for"-loop
560  for(pw = Wires->current(); pw != 0; pw = Wires->next())
561  for(pn = Nodes->first(); pn != 0; ) { // check every node
562  if(pn->cx == pw->x1) {
563  if(pn->cy <= pw->y1) { pn = Nodes->next(); continue; }
564  if(pn->cy >= pw->y2) { pn = Nodes->next(); continue; }
565  }
566  else if(pn->cy == pw->y1) {
567  if(pn->cx <= pw->x1) { pn = Nodes->next(); continue; }
568  if(pn->cx >= pw->x2) { pn = Nodes->next(); continue; }
569  }
570  else { pn = Nodes->next(); continue; }
571 
572  n1 = 2; n2 = 3;
573  pn2 = pn;
574  // check all connections of the current node
575  for(pe=pn->Connections.first(); pe!=0; pe=pn->Connections.next()) {
576  if(pe->Type != isWire) continue;
577  nw = (Wire*)pe;
578  // wire lies within the new ?
579  if(pw->isHorizontal() != nw->isHorizontal()) continue;
580 
581  pn = nw->Port1;
582  pn2 = nw->Port2;
583  n1 = pn->Connections.count();
584  n2 = pn2->Connections.count();
585  if(n1 == 1) {
586  Nodes->removeRef(pn); // delete node 1 if open
587  pn2->Connections.removeRef(nw); // remove connection
588  pn = pn2;
589  }
590 
591  if(n2 == 1) {
592  pn->Connections.removeRef(nw); // remove connection
593  Nodes->removeRef(pn2); // delete node 2 if open
594  pn2 = pn;
595  }
596 
597  if(pn == pn2) {
598  if(nw->Label) {
599  pw->Label = nw->Label;
600  pw->Label->pOwner = pw;
601  }
602  Wires->removeRef(nw); // delete wire
603  Wires->findRef(pw); // set back to current wire
604  }
605  break;
606  }
607  if(n1 == 1) if(n2 == 1) continue;
608 
609  // split wire into two wires
610  if((pw->x1 != pn->cx) || (pw->y1 != pn->cy)) {
611  nw = new Wire(pw->x1, pw->y1, pn->cx, pn->cy, pw->Port1, pn);
612  pn->Connections.append(nw);
613  Wires->append(nw);
614  Wires->findRef(pw);
615  pw->Port1->Connections.append(nw);
616  }
617  pw->Port1->Connections.removeRef(pw);
618  pw->x1 = pn2->cx;
619  pw->y1 = pn2->cy;
620  pw->Port1 = pn2;
621  pn2->Connections.append(pw);
622 
623  pn = Nodes->next();
624  }
625 
626  if (Wires->containsRef (w)) // if two wire lines with different labels ...
627  oneLabel(w->Port1); // ... are connected, delete one label
628  return con | 0x0200; // sent also end flag
629 }
630 
631 // ---------------------------------------------------
632 // Follows a wire line and selects it.
633 void Schematic::selectWireLine(Element *pe, Node *pn, bool ctrl)
634 {
635  Node *pn_1st = pn;
636  while(pn->Connections.count() == 2) {
637  if(pn->Connections.first() == pe) pe = pn->Connections.last();
638  else pe = pn->Connections.first();
639 
640  if(pe->Type != isWire) break;
641  if(ctrl) pe->isSelected ^= ctrl;
642  else pe->isSelected = true;
643 
644  if(((Wire*)pe)->Port1 == pn) pn = ((Wire*)pe)->Port2;
645  else pn = ((Wire*)pe)->Port1;
646  if(pn == pn_1st) break; // avoid endless loop in wire loops
647  }
648 }
649 
650 // ---------------------------------------------------
652 {
653  for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next())
654  if(pw->getSelected(x, y))
655  return pw;
656 
657  return 0;
658 }
659 
660 // ---------------------------------------------------
661 // Splits the wire "*pw" into two pieces by the node "*pn".
663 {
664  Wire *newWire = new Wire(pn->cx, pn->cy, pw->x2, pw->y2, pn, pw->Port2);
665  newWire->isSelected = pw->isSelected;
666 
667  pw->x2 = pn->cx;
668  pw->y2 = pn->cy;
669  pw->Port2 = pn;
670 
671  newWire->Port2->Connections.prepend(newWire);
672  pn->Connections.prepend(pw);
673  pn->Connections.prepend(newWire);
674  newWire->Port2->Connections.removeRef(pw);
675  Wires->append(newWire);
676 
677  if(pw->Label)
678  if((pw->Label->cx > pn->cx) || (pw->Label->cy > pn->cy)) {
679  newWire->Label = pw->Label; // label goes to the new wire
680  pw->Label = 0;
681  newWire->Label->pOwner = newWire;
682  }
683 
684  return newWire;
685 }
686 
687 // ---------------------------------------------------
688 // If possible, make one wire out of two wires.
690 {
691  Wire *e3;
692  Wire *e1 = (Wire*)n->Connections.getFirst(); // two wires -> one wire
693  Wire *e2 = (Wire*)n->Connections.getLast();
694 
695  if(e1->Type == isWire) if(e2->Type == isWire)
696  if(e1->isHorizontal() == e2->isHorizontal()) {
697  if(e1->x1 == e2->x2) if(e1->y1 == e2->y2) {
698  e3 = e1; e1 = e2; e2 = e3; // e1 must have lesser coordinates
699  }
700  if(e2->Label) { // take over the node name label ?
701  e1->Label = e2->Label;
702  e1->Label->pOwner = e1;
703  }
704  else if(n->Label) {
705  e1->Label = n->Label;
706  e1->Label->pOwner = e1;
707  if(e1->isHorizontal())
708  e1->Label->Type = isHWireLabel;
709  else
710  e1->Label->Type = isVWireLabel;
711  }
712 
713  e1->x2 = e2->x2;
714  e1->y2 = e2->y2;
715  e1->Port2 = e2->Port2;
716  Nodes->removeRef(n); // delete node (is auto delete)
717  e1->Port2->Connections.removeRef(e2);
718  e1->Port2->Connections.append(e1);
719  Wires->removeRef(e2);
720  return true;
721  }
722  return false;
723 }
724 
725 // ---------------------------------------------------
726 // Deletes the wire 'w'.
728 {
729  if(w->Port1->Connections.count() == 1) {
730  if(w->Port1->Label) delete w->Port1->Label;
731  Nodes->removeRef(w->Port1); // delete node 1 if open
732  }
733  else {
734  w->Port1->Connections.removeRef(w); // remove connection
735  if(w->Port1->Connections.count() == 2)
736  oneTwoWires(w->Port1); // two wires -> one wire
737  }
738 
739  if(w->Port2->Connections.count() == 1) {
740  if(w->Port2->Label) delete w->Port2->Label;
741  Nodes->removeRef(w->Port2); // delete node 2 if open
742  }
743  else {
744  w->Port2->Connections.removeRef(w); // remove connection
745  if(w->Port2->Connections.count() == 2)
746  oneTwoWires(w->Port2); // two wires -> one wire
747  }
748 
749  if(w->Label) {
750  delete w->Label;
751  w->Label = 0;
752  }
753  Wires->removeRef(w);
754 }
755 
756 // ---------------------------------------------------
757 int Schematic::copyWires(int& x1, int& y1, int& x2, int& y2,
758  QPtrList<Element> *ElementCache)
759 {
760  int count=0;
761  Node *pn;
762  Wire *pw;
763  WireLabel *pl;
764  for(pw = Wires->first(); pw != 0; ) // find bounds of all selected wires
765  if(pw->isSelected) {
766  if(pw->x1 < x1) x1 = pw->x1;
767  if(pw->x2 > x2) x2 = pw->x2;
768  if(pw->y1 < y1) y1 = pw->y1;
769  if(pw->y2 > y2) y2 = pw->y2;
770 
771  count++;
772  ElementCache->append(pw);
773 
774  // rescue non-selected node labels
775  pn = pw->Port1;
776  if(pn->Label)
777  if(pn->Connections.count() < 2) {
778  ElementCache->append(pn->Label);
779 
780  // Don't set pn->Label->pOwner=0 , so text position stays unchanged.
781  // But remember its wire.
782  pn->Label->pOwner = (Node*)pw;
783  pn->Label = 0;
784  }
785  pn = pw->Port2;
786  if(pn->Label)
787  if(pn->Connections.count() < 2) {
788  ElementCache->append(pn->Label);
789 
790  // Don't set pn->Label->pOwner=0 , so text position stays unchanged.
791  // But remember its wire.
792  pn->Label->pOwner = (Node*)pw;
793  pn->Label = 0;
794  }
795 
796  pl = pw->Label;
797  pw->Label = 0;
798  deleteWire(pw);
799  pw->Label = pl; // restore wire label
800  pw = Wires->current();
801  }
802  else pw = Wires->next();
803 
804  return count;
805 }
806 
807 
808 /* *******************************************************************
809  ***** *****
810  ***** Actions with markers *****
811  ***** *****
812  ******************************************************************* */
813 
815 {
816  int n;
817  // test all diagrams
818  for(Diagram *pd = Diagrams->last(); pd != 0; pd = Diagrams->prev())
819  if(pd->getSelected(x, y)) {
820 
821  // test all graphs of the diagram
822  for(Graph *pg = pd->Graphs.first(); pg != 0; pg = pd->Graphs.next()) {
823  n = pg->getSelected(x-pd->cx, pd->cy-y);
824  if(n >= 0) {
825  Marker *pm = new Marker(pd, pg, n, x-pd->cx, y-pd->cy);
826  pg->Markers.append(pm);
827  setChanged(true, true);
828  return pm;
829  }
830  }
831  }
832 
833  return 0;
834 }
835 
836 // ---------------------------------------------------
837 // Moves the marker pointer left/right on the graph.
838 void Schematic::markerLeftRight(bool left, QPtrList<Element> *Elements)
839 {
840  Marker *pm;
841  bool acted = false;
842  for(pm = (Marker*)Elements->first(); pm!=0; pm = (Marker*)Elements->next()) {
843  pm->pGraph->Markers.append(pm);
844  if(pm->moveLeftRight(left))
845  acted = true;
846  }
847 
848  if(acted) setChanged(true, true, 'm');
849 }
850 
851 // ---------------------------------------------------
852 // Moves the marker pointer up/down on the more-dimensional graph.
853 void Schematic::markerUpDown(bool up, QPtrList<Element> *Elements)
854 {
855  Marker *pm;
856  bool acted = false;
857  for(pm = (Marker*)Elements->first(); pm!=0; pm = (Marker*)Elements->next()) {
858  pm->pGraph->Markers.append(pm);
859  if(pm->moveUpDown(up))
860  acted = true;
861  }
862 
863  if(acted) setChanged(true, true, 'm');
864 }
865 
866 
867 /* *******************************************************************
868  ***** *****
869  ***** Actions with all elements *****
870  ***** *****
871  ******************************************************************* */
872 
873 // Selects the element that contains the coordinates x/y.
874 // Returns the pointer to the element.
875 // If 'flag' is true, the element can be deselected.
876 Element* Schematic::selectElement(float fX, float fY, bool flag, int *index)
877 {
878  int n, x = int(fX), y = int(fY);
879  Element *pe_1st=0, *pe_sel=0;
880  float Corr = textCorr(); // for selecting text
881 
882  WireLabel *pl;
883  // test all nodes and their labels
884  for(Node *pn = Nodes->last(); pn != 0; pn = Nodes->prev()) {
885  if(!flag)
886  if(index) // only true if called from MouseActions::MPressSelect()
887  if(pn->getSelected(x, y))
888  return pn;
889 
890  pl = pn->Label;
891  if(pl) if(pl->getSelected(x, y)) {
892  if(flag) { pl->isSelected ^= flag; return pl; }
893  if(pe_sel) {
894  pe_sel->isSelected = false;
895  return pl;
896  }
897  if(pe_1st == 0) pe_1st = pl; // give access to elements lying beneath
898  if(pl->isSelected) pe_sel = pl;
899  }
900  }
901 
902  // test all wires and wire labels
903  for(Wire *pw = Wires->last(); pw != 0; pw = Wires->prev()) {
904  if(pw->getSelected(x, y)) {
905  if(flag) { pw->isSelected ^= flag; return pw; }
906  if(pe_sel) {
907  pe_sel->isSelected = false;
908  return pw;
909  }
910  if(pe_1st == 0) pe_1st = pw; // give access to elements lying beneath
911  if(pw->isSelected) pe_sel = pw;
912  }
913  pl = pw->Label;
914  if(pl) if(pl->getSelected(x, y)) {
915  if(flag) { pl->isSelected ^= flag; return pl; }
916  if(pe_sel) {
917  pe_sel->isSelected = false;
918  return pl;
919  }
920  if(pe_1st == 0) pe_1st = pl; // give access to elements lying beneath
921  if(pl->isSelected) pe_sel = pl;
922  }
923  }
924 
925  // test all components
926  for(Component *pc = Components->last(); pc != 0; pc = Components->prev())
927  if(pc->getSelected(x, y)) {
928  if(flag) { pc->isSelected ^= flag; return pc; }
929  if(pe_sel) {
930  pe_sel->isSelected = false;
931  return pc;
932  }
933  if(pe_1st == 0) pe_1st = pc; // give access to elements lying beneath
934  if(pc->isSelected) pe_sel = pc;
935  }
936  else {
937  n = pc->getTextSelected(x, y, Corr);
938  if(n >= 0) { // was property text clicked ?
939  pc->Type = isComponentText;
940  if(index) *index = n;
941  return pc;
942  }
943  }
944 
945  Graph *pg;
946  Corr = 5.0 / Scale; // size of line select and area for resizing
947  // test all diagrams
948  for(Diagram *pd = Diagrams->last(); pd != 0; pd = Diagrams->prev()) {
949 
950  for(pg = pd->Graphs.first(); pg != 0; pg = pd->Graphs.next())
951  // test markers of graphs
952  for(Marker *pm = pg->Markers.first(); pm != 0; pm = pg->Markers.next())
953  if(pm->getSelected(x-pd->cx, y-pd->cy)) {
954  if(flag) { pm->isSelected ^= flag; return pm; }
955  if(pe_sel) {
956  pe_sel->isSelected = false;
957  return pm;
958  }
959  if(pe_1st == 0) pe_1st = pm; // give access to elements beneath
960  if(pm->isSelected) pe_sel = pm;
961  }
962 
963  // resize area clicked ?
964  if(pd->isSelected)
965  if(pd->resizeTouched(fX, fY, Corr))
966  if(pe_1st == 0) {
967  pd->Type = isDiagramResize;
968  return pd;
969  }
970 
971  if(pd->getSelected(x, y)) {
972  if(pd->Name[0] == 'T') { // tabular, timing diagram or truth table ?
973  if(pd->Name[1] == 'i') {
974  if(y > pd->cy) {
975  if(x < pd->cx+pd->xAxis.numGraphs) continue;
976  pd->Type = isDiagramHScroll;
977  return pd;
978  }
979  }
980  else {
981  if(x < pd->cx) { // clicked on scroll bar ?
982  pd->Type = isDiagramVScroll;
983  return pd;
984  }
985  }
986  }
987 
988  // test graphs of diagram
989  for(pg = pd->Graphs.first(); pg != 0; pg = pd->Graphs.next())
990  if(pg->getSelected(x-pd->cx, pd->cy-y) >= 0) {
991  if(flag) { pg->isSelected ^= flag; return pg; }
992  if(pe_sel) {
993  pe_sel->isSelected = false;
994  return pg;
995  }
996  if(pe_1st == 0) pe_1st = pg; // access to elements lying beneath
997  if(pg->isSelected) pe_sel = pg;
998  }
999 
1000 
1001  if(flag) { pd->isSelected ^= flag; return pd; }
1002  if(pe_sel) {
1003  pe_sel->isSelected = false;
1004  return pd;
1005  }
1006  if(pe_1st == 0) pe_1st = pd; // give access to elements lying beneath
1007  if(pd->isSelected) pe_sel = pd;
1008  }
1009  }
1010 
1011  // test all paintings
1012  for(Painting *pp = Paintings->last(); pp != 0; pp = Paintings->prev()) {
1013  if(pp->isSelected)
1014  if(pp->resizeTouched(fX, fY, Corr))
1015  if(pe_1st == 0) {
1016  pp->Type = isPaintingResize;
1017  return pp;
1018  }
1019 
1020  if(pp->getSelected(fX, fY, Corr)) {
1021  if(flag) { pp->isSelected ^= flag; return pp; }
1022  if(pe_sel) {
1023  pe_sel->isSelected = false;
1024  return pp;
1025  }
1026  if(pe_1st == 0) pe_1st = pp; // give access to elements lying beneath
1027  if(pp->isSelected) pe_sel = pp;
1028  }
1029  }
1030 
1031  return pe_1st;
1032 }
1033 
1034 // ---------------------------------------------------
1035 // Deselects all elements except 'e'.
1037 {
1038  // test all components
1039  for(Component *pc = Components->first(); pc != 0; pc = Components->next())
1040  if(e != pc) pc->isSelected = false;
1041 
1042  // test all wires
1043  for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next()) {
1044  if(e != pw) pw->isSelected = false;
1045  if(pw->Label) if(pw->Label != e) pw->Label->isSelected = false;
1046  }
1047 
1048  // test all node labels
1049  for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next())
1050  if(pn->Label) if(pn->Label != e) pn->Label->isSelected = false;
1051 
1052  // test all diagrams
1053  for(Diagram *pd = Diagrams->first(); pd != 0; pd = Diagrams->next()) {
1054  if(e != pd) pd->isSelected = false;
1055 
1056  // test graphs of diagram
1057  for(Graph *pg = pd->Graphs.first(); pg != 0; pg = pd->Graphs.next()) {
1058  if(e != pg) pg->isSelected = false;
1059 
1060  // test markers of graph
1061  for(Marker *pm = pg->Markers.first(); pm != 0; pm = pg->Markers.next())
1062  if(e != pm) pm->isSelected = false;
1063  }
1064 
1065  }
1066 
1067  // test all paintings
1068  for(Painting *pp = Paintings->first(); pp != 0; pp = Paintings->next())
1069  if(e != pp) pp->isSelected = false;
1070 }
1071 
1072 // ---------------------------------------------------
1073 // Selects elements that lie within the rectangle x1/y1, x2/y2.
1074 int Schematic::selectElements(int x1, int y1, int x2, int y2, bool flag)
1075 {
1076  int z=0; // counts selected elements
1077  int cx1, cy1, cx2, cy2;
1078 
1079  // exchange rectangle coordinates to obtain x1 < x2 and y1 < y2
1080  cx1 = (x1 < x2) ? x1 : x2; cx2 = (x1 > x2) ? x1 : x2;
1081  cy1 = (y1 < y2) ? y1 : y2; cy2 = (y1 > y2) ? y1 : y2;
1082  x1 = cx1; x2 = cx2;
1083  y1 = cy1; y2 = cy2;
1084 
1085  // test all components
1086  for(Component *pc = Components->first(); pc != 0; pc = Components->next()) {
1087  pc->Bounding(cx1, cy1, cx2, cy2);
1088  if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2) {
1089  pc->isSelected = true; z++;
1090  continue;
1091  }
1092  if(pc->isSelected &= flag) z++;
1093  }
1094 
1095 
1096  Wire *pw;
1097  for(pw = Wires->first(); pw != 0; pw = Wires->next()) { // test all wires
1098  if(pw->x1 >= x1) if(pw->x2 <= x2) if(pw->y1 >= y1) if(pw->y2 <= y2) {
1099  pw->isSelected = true; z++;
1100  continue;
1101  }
1102  if(pw->isSelected &= flag) z++;
1103  }
1104 
1105 
1106  // test all wire labels *********************************
1107  WireLabel *pl=0;
1108  for(pw = Wires->first(); pw != 0; pw = Wires->next()) {
1109  if(pw->Label) {
1110  pl = pw->Label;
1111  if(pl->x1 >= x1) if((pl->x1+pl->x2) <= x2)
1112  if(pl->y1 >= y1) if((pl->y1+pl->y2) <= y2) {
1113  pl->isSelected = true; z++;
1114  continue;
1115  }
1116  if(pl->isSelected &= flag) z++;
1117  }
1118  }
1119 
1120 
1121  // test all node labels *************************************
1122  for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next()) {
1123  pl = pn->Label;
1124  if(pl) {
1125  if(pl->x1 >= x1) if((pl->x1+pl->x2) <= x2)
1126  if((pl->y1-pl->y2) >= y1) if(pl->y1 <= y2) {
1127  pl->isSelected = true; z++;
1128  continue;
1129  }
1130  if(pl->isSelected &= flag) z++;
1131  }
1132  }
1133 
1134 
1135  // test all diagrams *******************************************
1136  for(Diagram *pd = Diagrams->first(); pd != 0; pd = Diagrams->next()) {
1137  // test graphs of diagram
1138  for(Graph *pg = pd->Graphs.first(); pg != 0; pg = pd->Graphs.next()) {
1139  if(pg->isSelected &= flag) z++;
1140 
1141  // test markers of graph
1142  for(Marker *pm = pg->Markers.first(); pm!=0; pm = pg->Markers.next()) {
1143  pm->Bounding(cx1, cy1, cx2, cy2);
1144  if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2) {
1145  pm->isSelected = true; z++;
1146  continue;
1147  }
1148  if(pm->isSelected &= flag) z++;
1149  }
1150  }
1151 
1152  // test diagram itself
1153  pd->Bounding(cx1, cy1, cx2, cy2);
1154  if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2) {
1155  pd->isSelected = true; z++;
1156  continue;
1157  }
1158  if(pd->isSelected &= flag) z++;
1159  }
1160 
1161  // test all paintings *******************************************
1162  for(Painting *pp = Paintings->first(); pp != 0; pp = Paintings->next()) {
1163  pp->Bounding(cx1, cy1, cx2, cy2);
1164  if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2) {
1165  pp->isSelected = true; z++;
1166  continue;
1167  }
1168  if(pp->isSelected &= flag) z++;
1169  }
1170 
1171  return z;
1172 }
1173 
1174 // ---------------------------------------------------
1175 // Selects all markers.
1177 {
1178  for(Diagram *pd = Diagrams->first(); pd != 0; pd = Diagrams->next())
1179  for(Graph *pg = pd->Graphs.first(); pg != 0; pg = pd->Graphs.next())
1180  for(Marker *pm = pg->Markers.first(); pm!=0; pm = pg->Markers.next())
1181  pm->isSelected = true;
1182 }
1183 
1184 // ---------------------------------------------------
1185 // For moving elements: If the moving element is connected to a not
1186 // moving element, insert two wires. If the connected element is already
1187 // a wire, use this wire. Otherwise create new wire.
1188 void Schematic::newMovingWires(QPtrList<Element> *p, Node *pn, int pos)
1189 {
1190  Element *pe;
1191 
1192  if(pn->State & 8) // Were new wires already inserted ?
1193  return;
1194  pn->State |= 8;
1195 
1196  for (;;) {
1197  if(pn->State & 16) // node was already worked on
1198  break;
1199 
1200  pe = pn->Connections.getFirst();
1201  if(pe == 0) return;
1202 
1203  if(pn->Connections.count() > 1)
1204  break;
1205  if(pe->Type != isWire) // is it connected to exactly one wire ?
1206  break;
1207 
1208  // .................................................
1209  long mask = 1, invMask = 3;
1210  Wire *pw2=0, *pw = (Wire*)pe;
1211 
1212  Node *pn2 = pw->Port1;
1213  if(pn2 == pn) pn2 = pw->Port2;
1214 
1215  if(pn2->Connections.count() == 2) // two existing wires connected ?
1216  if((pn2->State & (8+4)) == 0) {
1217  Element *pe2 = pn2->Connections.getFirst();
1218  if(pe2 == pe) pe2 = pn2->Connections.getLast();
1219  // connected wire connected to exactly one wire ?
1220  if(pe2->Type == isWire)
1221  pw2 = (Wire*)pe2;
1222  }
1223 
1224  // .................................................
1225  // reuse one wire
1226  p->insert(pos, pw);
1227  pw->Port1->Connections.removeRef(pw); // remove connection 1
1228  pw->Port1->State |= 16+4;
1229  pw->Port2->Connections.removeRef(pw); // remove connection 2
1230  pw->Port2->State |= 16+4;
1231  Wires->take(Wires->findRef(pw));
1232 
1233  if(pw->isHorizontal()) mask = 2;
1234 
1235  if(pw2 == 0) { // place new wire between component and old wire
1236  pn = pn2;
1237  mask ^= 3;
1238  invMask = 0;
1239  }
1240 
1241  if(pw->Port1 != pn) {
1242  pw->Port1->State |= mask;
1243  pw->Port1 = (Node*)mask;
1244  pw->Port2->State |= invMask;
1245  pw->Port2 = (Node*)invMask; // move port 2 completely
1246  }
1247  else {
1248  pw->Port1->State |= invMask;
1249  pw->Port1 = (Node*)invMask;
1250  pw->Port2->State |= mask;
1251  pw->Port2 = (Node*)mask;
1252  }
1253 
1254  invMask ^= 3;
1255  // .................................................
1256  // create new wire ?
1257  if(pw2 == 0) {
1258  if(pw->Port1 != (Node*)mask)
1259  p->insert(pos,
1260  new Wire(pw->x2, pw->y2, pw->x2, pw->y2, (Node*)mask, (Node*)invMask));
1261  else
1262  p->insert(pos,
1263  new Wire(pw->x1, pw->y1, pw->x1, pw->y1, (Node*)mask, (Node*)invMask));
1264  return;
1265  }
1266 
1267 
1268  // .................................................
1269  // reuse a second wire
1270  p->insert(pos, pw2);
1271  pw2->Port1->Connections.removeRef(pw2); // remove connection 1
1272  pw2->Port1->State |= 16+4;
1273  pw2->Port2->Connections.removeRef(pw2); // remove connection 2
1274  pw2->Port2->State |= 16+4;
1275  Wires->take(Wires->findRef(pw2));
1276 
1277  if(pw2->Port1 != pn2) {
1278  pw2->Port1 = (Node*)0;
1279  pw2->Port2->State |= mask;
1280  pw2->Port2 = (Node*)mask;
1281  }
1282  else {
1283  pw2->Port1->State |= mask;
1284  pw2->Port1 = (Node*)mask;
1285  pw2->Port2 = (Node*)0;
1286  }
1287  return;
1288  }
1289 
1290  // only x2 moving
1291  p->insert(pos, new Wire(pn->cx, pn->cy, pn->cx, pn->cy, (Node*)0, (Node*)1));
1292  // x1, x2, y2 moving
1293  p->insert(pos, new Wire(pn->cx, pn->cy, pn->cx, pn->cy, (Node*)1, (Node*)3));
1294 }
1295 
1296 // ---------------------------------------------------
1297 // For moving of elements: Copies all selected elements into the
1298 // list 'p' and deletes them from the document.
1299 int Schematic::copySelectedElements(QPtrList<Element> *p)
1300 {
1301  int i, count = 0;
1302  Port *pp;
1303  Component *pc;
1304  Wire *pw;
1305  Diagram *pd;
1306  Element *pe;
1307  Node *pn;
1308 
1309 
1310  // test all components *********************************
1311  // Insert components before wires in order to prevent short-cut removal.
1312  for(pc = Components->first(); pc != 0; )
1313  if(pc->isSelected) {
1314  p->append(pc);
1315  count++;
1316 
1317  // delete all port connections
1318  for(pp = pc->Ports.first(); pp!=0; pp = pc->Ports.next()) {
1319  pp->Connection->Connections.removeRef((Element*)pc);
1320  pp->Connection->State = 4;
1321  }
1322 
1323  Components->take(); // take component out of the document
1324  pc = Components->current();
1325  }
1326  else pc = Components->next();
1327 
1328  // test all wires and wire labels ***********************
1329  for(pw = Wires->first(); pw != 0; ) {
1330  if(pw->Label) if(pw->Label->isSelected)
1331  p->append(pw->Label);
1332 
1333  if(pw->isSelected) {
1334  p->append(pw);
1335 
1336  pw->Port1->Connections.removeRef(pw); // remove connection 1
1337  pw->Port1->State = 4;
1338  pw->Port2->Connections.removeRef(pw); // remove connection 2
1339  pw->Port2->State = 4;
1340  Wires->take();
1341  pw = Wires->current();
1342  }
1343  else pw = Wires->next();
1344  }
1345 
1346  // ..............................................
1347  // Inserts wires, if a connection to a not moving element is found.
1348  // The order of the "for"-loops is important to guarantee a stable
1349  // operation: components, new wires, old wires
1350  pc = (Component*)p->first();
1351  for(i=0; i<count; i++) {
1352  for(pp = pc->Ports.first(); pp!=0; pp = pc->Ports.next())
1353  newMovingWires(p, pp->Connection, count);
1354 
1355  p->findRef(pc); // back to the real current pointer
1356  pc = (Component*)p->next();
1357  }
1358 
1359  for(pe = (Element*)pc; pe != 0; pe = p->next()) // new wires
1360  if(pe->isSelected)
1361  break;
1362 
1363  for(pw = (Wire*)pe; pw != 0; pw = (Wire*)p->next())
1364  if(pw->Type == isWire) { // not working on labels
1365  newMovingWires(p, pw->Port1, count);
1366  newMovingWires(p, pw->Port2, count);
1367  p->findRef(pw); // back to the real current pointer
1368  }
1369 
1370 
1371  // ..............................................
1372  // delete the unused nodes
1373  for(pn = Nodes->first(); pn!=0; ) {
1374  if(pn->State & 8)
1375  if(pn->Connections.count() == 2)
1376  if(oneTwoWires(pn)) { // if possible, connect two wires to one
1377  pn = Nodes->current();
1378  continue;
1379  }
1380 
1381  if(pn->Connections.count() == 0) {
1382  if(pn->Label) {
1383  pn->Label->Type = isMovingLabel;
1384  if(pn->State & 1) {
1385  if(!(pn->State & 2)) pn->Label->Type = isHMovingLabel;
1386  }
1387  else if(pn->State & 2) pn->Label->Type = isVMovingLabel;
1388  p->append(pn->Label); // do not forget the node labels
1389  }
1390  Nodes->remove();
1391  pn = Nodes->current();
1392  continue;
1393  }
1394 
1395  pn->State = 0;
1396  pn = Nodes->next();
1397  }
1398 
1399  // test all node labels
1400  // do this last to avoid double copying
1401  for(pn = Nodes->first(); pn != 0; pn = Nodes->next())
1402  if(pn->Label) if(pn->Label->isSelected)
1403  p->append(pn->Label);
1404 
1405 
1406  // test all paintings **********************************
1407  for(Painting *ppa = Paintings->first(); ppa != 0; )
1408  if(ppa->isSelected) {
1409  p->append(ppa);
1410  Paintings->take();
1411  ppa = Paintings->current();
1412  }
1413  else ppa = Paintings->next();
1414 
1415  count = 0; // count markers now
1416  // test all diagrams **********************************
1417  for(pd = Diagrams->first(); pd != 0; )
1418  if(pd->isSelected) {
1419  p->append(pd);
1420  Diagrams->take();
1421  pd = Diagrams->current();
1422  }
1423  else {
1424  for(Graph *pg = pd->Graphs.first(); pg!=0; pg = pd->Graphs.next())
1425  for(Marker *pm = pg->Markers.first(); pm != 0; )
1426  if(pm->isSelected) {
1427  count++;
1428  p->append(pm);
1429  pg->Markers.take();
1430  pm = pg->Markers.current();
1431  }
1432  else pm = pg->Markers.next();
1433 
1434  pd = Diagrams->next();
1435  }
1436 
1437  return count;
1438 }
1439 
1440 // ---------------------------------------------------
1441 bool Schematic::copyComps2WiresPaints(int& x1, int& y1, int& x2, int& y2,
1442  QPtrList<Element> *ElementCache)
1443 {
1444  x1=INT_MAX;
1445  y1=INT_MAX;
1446  x2=INT_MIN;
1447  y2=INT_MIN;
1448  copyLabels(x1, y1, x2, y2, ElementCache); // must be first of all !
1449  copyComponents2(x1, y1, x2, y2, ElementCache);
1450  copyWires(x1, y1, x2, y2, ElementCache);
1451  copyPaintings(x1, y1, x2, y2, ElementCache);
1452 
1453  if(y1 == INT_MAX) return false; // no element selected
1454  return true;
1455 }
1456 
1457 // ---------------------------------------------------
1458 // Used in "aligning()", "distributeHorizontal()", "distributeVertical()".
1459 int Schematic::copyElements(int& x1, int& y1, int& x2, int& y2,
1460  QPtrList<Element> *ElementCache)
1461 {
1462  int bx1, by1, bx2, by2;
1463  Wires->setAutoDelete(false);
1464  Components->setAutoDelete(false);
1465 
1466  x1=INT_MAX;
1467  y1=INT_MAX;
1468  x2=INT_MIN;
1469  y2=INT_MIN;
1470  // take components and wires out of list, check their boundings
1471  int number = copyComponents(x1, y1, x2, y2, ElementCache);
1472  number += copyWires(x1, y1, x2, y2, ElementCache);
1473 
1474  Wires->setAutoDelete(true);
1475  Components->setAutoDelete(true);
1476 
1477  // find upper most selected diagram
1478  for(Diagram *pd = Diagrams->last(); pd != 0; pd = Diagrams->prev())
1479  if(pd->isSelected) {
1480  pd->Bounding(bx1, by1, bx2, by2);
1481  if(bx1 < x1) x1 = bx1;
1482  if(bx2 > x2) x2 = bx2;
1483  if(by1 < y1) y1 = by1;
1484  if(by2 > y2) y2 = by2;
1485  ElementCache->append(pd);
1486  number++;
1487  }
1488  // find upper most selected painting
1489  for(Painting *pp = Paintings->last(); pp != 0; pp = Paintings->prev())
1490  if(pp->isSelected) {
1491  pp->Bounding(bx1, by1, bx2, by2);
1492  if(bx1 < x1) x1 = bx1;
1493  if(bx2 > x2) x2 = bx2;
1494  if(by1 < y1) y1 = by1;
1495  if(by2 > y2) y2 = by2;
1496  ElementCache->append(pp);
1497  number++;
1498  }
1499 
1500  return number;
1501 }
1502 
1503 // ---------------------------------------------------
1504 // Deletes all selected elements.
1506 {
1507  bool sel = false;
1508 
1509  Component *pc = Components->first();
1510  while(pc != 0) // all selected component
1511  if(pc->isSelected) {
1512  deleteComp(pc);
1513  pc = Components->current();
1514  sel = true;
1515  }
1516  else pc = Components->next();
1517 
1518  Wire *pw = Wires->first();
1519  while(pw != 0) { // all selected wires and their labels
1520  if(pw->Label)
1521  if(pw->Label->isSelected) {
1522  delete pw->Label;
1523  pw->Label = 0;
1524  sel = true;
1525  }
1526 
1527  if(pw->isSelected) {
1528  deleteWire(pw);
1529  pw = Wires->current();
1530  sel = true;
1531  }
1532  else pw = Wires->next();
1533  }
1534 
1535  // all selected labels on nodes ***************************
1536  for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next())
1537  if(pn->Label)
1538  if(pn->Label->isSelected) {
1539  delete pn->Label;
1540  pn->Label = 0;
1541  sel = true;
1542  }
1543 
1544  Diagram *pd = Diagrams->first();
1545  while(pd != 0) // test all diagrams
1546  if(pd->isSelected) {
1547  Diagrams->remove();
1548  pd = Diagrams->current();
1549  sel = true;
1550  }
1551  else {
1552  bool wasGraphDeleted = false;
1553  // all graphs of diagram
1554  for(Graph *pg = pd->Graphs.first(); pg != 0; ) {
1555  // all markers of diagram
1556  for(Marker *pm = pg->Markers.first(); pm != 0; )
1557  if(pm->isSelected) {
1558  pg->Markers.remove();
1559  pm = pg->Markers.current();
1560  sel = true;
1561  }
1562  else pm = pg->Markers.next();
1563 
1564  if(pg->isSelected) {
1565  pd->Graphs.remove();
1566  pg = pd->Graphs.current();
1567  sel = wasGraphDeleted = true;
1568  }
1569  else pg = pd->Graphs.next();
1570  }
1571  if(wasGraphDeleted)
1572  pd->recalcGraphData(); // update diagram (resize etc.)
1573 
1574  pd = Diagrams->next();
1575  }
1576 
1577  Painting *pp = Paintings->first();
1578  while(pp != 0) { // test all paintings
1579  if(pp->isSelected)
1580  if(pp->Name.at(0) != '.') { // do not delete "PortSym", "ID_text"
1581  sel = true;
1582  Paintings->remove();
1583  pp = Paintings->current();
1584  continue;
1585  }
1586  pp = Paintings->next();
1587  }
1588 
1589  if(sel) {
1590  sizeOfAll(UsedX1, UsedY1, UsedX2, UsedY2); // set new document size
1591  setChanged(sel, true);
1592  }
1593  return sel;
1594 }
1595 
1596 // ---------------------------------------------------
1597 bool Schematic::aligning(int Mode)
1598 {
1599  int x1, y1, x2, y2;
1600  int bx1, by1, bx2, by2, *bx=0, *by=0, *ax=0, *ay=0;
1601  QPtrList<Element> ElementCache;
1602  int count = copyElements(x1, y1, x2, y2, &ElementCache);
1603  if(count < 1) return false;
1604 
1605 
1606  ax = ay = &x2; // = 0
1607  switch(Mode) {
1608  case 0: // align top
1609  bx = &x1;
1610  by = &by1;
1611  y2 = 1;
1612  break;
1613  case 1: // align bottom
1614  bx = &x1;
1615  y1 = y2;
1616  by = &by2;
1617  y2 = 1;
1618  break;
1619  case 2: // align left
1620  by = &y1;
1621  bx = &bx1;
1622  y2 = 1;
1623  break;
1624  case 3: // align right
1625  by = &y1;
1626  x1 = x2;
1627  bx = &bx2;
1628  y2 = 1;
1629  break;
1630  case 4: // center horizontally
1631  x1 = (x2+x1) / 2;
1632  by = &x2; // = 0
1633  ax = &bx1;
1634  bx = &bx2;
1635  y1 = 0;
1636  y2 = 2;
1637  break;
1638  case 5: // center vertically
1639  y1 = (y2+y1) / 2;
1640  bx = &x2; // = 0
1641  ay = &by1;
1642  by = &by2;
1643  x1 = 0;
1644  y2 = 2;
1645  break;
1646  }
1647  x2 = 0;
1648 
1649  Wire *pw;
1650  Component *pc;
1651  // re-insert elements
1652  // Go backwards in order to insert node labels before its component.
1653  for(Element *pe = ElementCache.last(); pe != 0; pe = ElementCache.prev())
1654  switch(pe->Type) {
1655  case isComponent:
1656  case isAnalogComponent:
1657  case isDigitalComponent:
1658  pc = (Component*)pe;
1659  pc->Bounding(bx1, by1, bx2, by2);
1660  pc->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true);
1661  insertRawComponent(pc);
1662  break;
1663 
1664  case isWire:
1665  pw = (Wire*)pe;
1666  bx1 = pw->x1;
1667  by1 = pw->y1;
1668  bx2 = pw->x2;
1669  by2 = pw->y2;
1670  pw->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true);
1671 // if(pw->Label) { }
1672  insertWire(pw);
1673  break;
1674 
1675  case isDiagram:
1676  // Should the axis label be counted for ? I guess everyone
1677  // has a different opinion.
1678 // ((Diagram*)pe)->Bounding(bx1, by1, bx2, by2);
1679 
1680  // Take size without axis label.
1681  bx1 = ((Diagram*)pe)->cx;
1682  by2 = ((Diagram*)pe)->cy;
1683  bx2 = bx1 + ((Diagram*)pe)->x2;
1684  by1 = by2 - ((Diagram*)pe)->y2;
1685  ((Diagram*)pe)->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true);
1686  break;
1687 
1688  case isPainting:
1689  ((Painting*)pe)->Bounding(bx1, by1, bx2, by2);
1690  ((Painting*)pe)->setCenter(x1-((*bx)+(*ax))/y2, y1-((*by)+(*ay))/y2, true);
1691  break;
1692 
1693  case isNodeLabel:
1694  if(((Element*)(((WireLabel*)pe)->pOwner))->Type & isComponent) {
1695  pc = (Component*)(((WireLabel*)pe)->pOwner);
1696  pc->Bounding(bx1, by1, bx2, by2);
1697  }
1698  else {
1699  pw = (Wire*)(((WireLabel*)pe)->pOwner);
1700  bx1 = pw->x1; by1 = pw->y1;
1701  bx2 = pw->x2; by2 = pw->y2;
1702  }
1703  ((WireLabel*)pe)->cx += x1-((*bx)+(*ax))/y2;
1704  ((WireLabel*)pe)->cy += y1-((*by)+(*ay))/y2;
1705  insertNodeLabel((WireLabel*)pe);
1706  break;
1707 
1708  default: ;
1709  }
1710 
1711  ElementCache.clear();
1712  if(count < 2) return false;
1713 
1714  setChanged(true, true);
1715  return true;
1716 }
1717 
1718 // ---------------------------------------------------
1720 {
1721  int x1, y1, x2, y2;
1722  int bx1, by1, bx2, by2;
1723  QPtrList<Element> ElementCache;
1724  int count = copyElements(x1, y1, x2, y2, &ElementCache);
1725  if(count < 1) return false;
1726 
1727  Element *pe;
1728  WireLabel *pl;
1729  // Node labels are not counted for, so put them to the end.
1730 /* for(pe = ElementCache.last(); pe != 0; pe = ElementCache.prev())
1731  if(pe->Type == isNodeLabel) {
1732  ElementCache.append(pe);
1733  ElementCache.removeRef(pe);
1734  }*/
1735 
1736  // using bubble sort to get elements x ordered
1737  if(count > 1)
1738  for(int i = count-1; i>0; i--) {
1739  pe = ElementCache.first();
1740  for(int j=0; j<i; j++) {
1741  pe->getCenter(bx1, by1);
1742  pe=ElementCache.next();
1743  pe->getCenter(bx2, by2);
1744  if(bx1 > bx2) { // change two elements ?
1745  ElementCache.replace(j+1, ElementCache.prev());
1746  ElementCache.replace(j, pe);
1747  pe = ElementCache.next();
1748  }
1749  }
1750  }
1751 
1752  ElementCache.getLast()->getCenter(x2, y2);
1753  ElementCache.getFirst()->getCenter(x1, y1);
1754  Wire *pw;
1755  int x = x2;
1756  int dx=0;
1757  if(count > 1) dx = (x2-x1)/(count-1);
1758  // re-insert elements and put them at right position
1759  // Go backwards in order to insert node labels before its component.
1760  for(pe = ElementCache.last(); pe != 0; pe = ElementCache.prev()) {
1761  switch(pe->Type) {
1762  case isComponent:
1763  case isAnalogComponent:
1764  case isDigitalComponent:
1765  pe->cx = x;
1767  break;
1768 
1769  case isWire:
1770  pw = (Wire*)pe;
1771  if(pw->isHorizontal()) {
1772  x1 = pw->x2 - pw->x1;
1773  pw->x1 = x - (x1 >> 1);
1774  pw->x2 = pw->x1 + x1;
1775  }
1776  else pw->x1 = pw->x2 = x;
1777 // if(pw->Label) { }
1778  insertWire(pw);
1779  break;
1780 
1781  case isDiagram:
1782  pe->cx = x - (pe->x2 >> 1);
1783  break;
1784 
1785  case isPainting:
1786  pe->getCenter(bx1, by1);
1787  pe->setCenter(x, by1, false);
1788  break;
1789 
1790  case isNodeLabel:
1791  pl = (WireLabel*)pe;
1792  if(((Element*)(pl->pOwner))->Type & isComponent)
1793  pe->cx += x - ((Component*)(pl->pOwner))->cx;
1794  else {
1795  pw = (Wire*)(pl->pOwner);
1796  if(pw->isHorizontal()) {
1797  x1 = pw->x2 - pw->x1;
1798  pe->cx += x - (x1 >> 1) - pw->x1;
1799  }
1800  else pe->cx += x - pw->x1;
1801  }
1802  insertNodeLabel(pl);
1803  x += dx;
1804  break;
1805 
1806  default: ;
1807  }
1808  x -= dx;
1809  }
1810 
1811  ElementCache.clear();
1812  if(count < 2) return false;
1813 
1814  setChanged(true, true);
1815  return true;
1816 }
1817 
1818 // ---------------------------------------------------
1820 {
1821  int x1, y1, x2, y2;
1822  int bx1, by1, bx2, by2;
1823  QPtrList<Element> ElementCache;
1824  int count = copyElements(x1, y1, x2, y2, &ElementCache);
1825  if(count < 1) return false;
1826 
1827  // using bubble sort to get elements x ordered
1828  Element *pe;
1829  if(count > 1)
1830  for(int i = count-1; i>0; i--) {
1831  pe = ElementCache.first();
1832  for(int j=0; j<i; j++) {
1833  pe->getCenter(bx1, by1);
1834  pe=ElementCache.next();
1835  pe->getCenter(bx2, by2);
1836  if(by1 > by2) { // change two elements ?
1837  ElementCache.replace(j+1, ElementCache.prev());
1838  ElementCache.replace(j, pe);
1839  pe = ElementCache.next();
1840  }
1841  }
1842  }
1843 
1844  ElementCache.getLast()->getCenter(x2, y2);
1845  ElementCache.getFirst()->getCenter(x1, y1);
1846  Wire *pw;
1847  int y = y2;
1848  int dy=0;
1849  if(count > 1) dy = (y2-y1)/(count-1);
1850  // re-insert elements and put them at right position
1851  // Go backwards in order to insert node labels before its component.
1852  for(pe = ElementCache.last(); pe != 0; pe = ElementCache.prev()) {
1853  switch(pe->Type) {
1854  case isComponent:
1855  case isAnalogComponent:
1856  case isDigitalComponent:
1857  pe->cy = y;
1859  break;
1860 
1861  case isWire:
1862  pw = (Wire*)pe;
1863  if(pw->isHorizontal()) pw->y1 = pw->y2 = y;
1864  else {
1865  y1 = pw->y2 - pw->y1;
1866  pw->y1 = y - (y1 >> 1);
1867  pw->y2 = pe->y1 + y1;
1868  }
1869 // if(pw->Label) { }
1870  insertWire(pw);
1871  break;
1872 
1873  case isDiagram:
1874  pe->cy = y + (pe->y2 >> 1);
1875  break;
1876 
1877  case isPainting:
1878  pe->getCenter(bx1, by1);
1879  pe->setCenter(bx1, y, false);
1880  break;
1881 
1882  case isNodeLabel:
1883  if(((Element*)(((WireLabel*)pe)->pOwner))->Type & isComponent)
1884  pe->cy += y - ((Component*)(((WireLabel*)pe)->pOwner))->cy;
1885  else {
1886  pw = (Wire*)(((WireLabel*)pe)->pOwner);
1887  if(!pw->isHorizontal()) {
1888  y1 = pw->y2 - pw->y1;
1889  pe->cy += y - (y1 >> 1) - pw->y1;
1890  }
1891  else pe->cy += y - pw->y1;
1892  }
1893  insertNodeLabel((WireLabel*)pe);
1894  y += dy;
1895  break;
1896 
1897  default: ;
1898  }
1899  y -= dy;
1900  }
1901 
1902  ElementCache.clear();
1903  if(count < 2) return false;
1904 
1905  setChanged(true, true);
1906  return true;
1907 }
1908 
1909 
1910 /* *******************************************************************
1911  ***** *****
1912  ***** Actions with components *****
1913  ***** *****
1914  ******************************************************************* */
1915 
1916 // Finds the correct number for power sources, subcircuit ports and
1917 // digital sources and sets them accordingly.
1919 {
1920  Property *pp = c->Props.getFirst();
1921  if(!pp) return;
1922  if(pp->Name != "Num") return;
1923 
1924  int n=1;
1925  QString s = pp->Value;
1926  QString cSign = c->Model;
1927  Component *pc;
1928  // First look, if the port number already exists.
1929  for(pc = Components->first(); pc != 0; pc = Components->next())
1930  if(pc->Model == cSign)
1931  if(pc->Props.getFirst()->Value == s) break;
1932  if(!pc) return; // was port number not yet in use ?
1933 
1934  // Find the first free number.
1935  do {
1936  s = QString::number(n);
1937  // look for existing ports and their numbers
1938  for(pc = Components->first(); pc != 0; pc = Components->next())
1939  if(pc->Model == cSign)
1940  if(pc->Props.getFirst()->Value == s) break;
1941 
1942  n++;
1943  } while(pc); // found not used component number
1944  pp->Value = s; // set new number
1945 }
1946 
1947 // ---------------------------------------------------
1948 void Schematic::insertComponentNodes(Component *c, bool noOptimize)
1949 {
1950  Port *pp;
1951  // connect every node of the component to corresponding schematic node
1952  for(pp = c->Ports.first(); pp != 0; pp = c->Ports.next())
1953  pp->Connection = insertNode(pp->x+c->cx, pp->y+c->cy, c);
1954 
1955  if(noOptimize) return;
1956 
1957  Node *pn;
1958  Element *pe, *pe1;
1959  QPtrList<Element> *pL;
1960  // if component over wire then delete this wire
1961  c->Ports.first(); // omit the first element
1962  for(pp = c->Ports.next(); pp != 0; pp = c->Ports.next()) {
1963  pn = pp->Connection;
1964  for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next())
1965  if(pe->Type == isWire) {
1966  if(((Wire*)pe)->Port1 == pn) pL = &(((Wire*)pe)->Port2->Connections);
1967  else pL = &(((Wire*)pe)->Port1->Connections);
1968 
1969  for(pe1 = pL->first(); pe1!=0; pe1 = pL->next())
1970  if(pe1 == c) {
1971  deleteWire((Wire*)pe);
1972  break;
1973  }
1974  }
1975  }
1976 }
1977 
1978 // ---------------------------------------------------
1979 // Used for example in moving components.
1980 void Schematic::insertRawComponent(Component *c, bool noOptimize)
1981 {
1982  // connect every node of component to corresponding schematic node
1983  insertComponentNodes(c, noOptimize);
1984  Components->append(c);
1985 
1986  // a ground symbol erases an existing label on the wire line
1987  if(c->Model == "GND") {
1988  c->Model = "x"; // prevent that this ground is found as label
1989  Element *pe = getWireLabel(c->Ports.getFirst()->Connection);
1990  if(pe) if((pe->Type & isComponent) == 0) {
1991  delete ((Conductor*)pe)->Label;
1992  ((Conductor*)pe)->Label = 0;
1993  }
1994  c->Model = "GND"; // rebuild component model
1995  }
1996 }
1997 
1998 // ---------------------------------------------------
2000 {
2001  Port *pp;
2002  WireLabel **plMem=0, **pl;
2003  int PortCount = Comp->Ports.count();
2004 
2005  if(PortCount > 0) {
2006  // Save the labels whose node is not connected to somewhere else.
2007  // Otherwise the label would be deleted.
2008  pl = plMem = (WireLabel**)malloc(PortCount * sizeof(WireLabel*));
2009  for(pp = Comp->Ports.first(); pp != 0; pp = Comp->Ports.next())
2010  if(pp->Connection->Connections.count() < 2) {
2011  *(pl++) = pp->Connection->Label;
2012  pp->Connection->Label = 0;
2013  }
2014  else *(pl++) = 0;
2015  }
2016 
2017 
2018  int x = Comp->tx, y = Comp->ty;
2019  int x1 = Comp->x1, x2 = Comp->x2, y1 = Comp->y1, y2 = Comp->y2;
2020  QString tmp = Comp->Name; // is sometimes changed by "recreate"
2021  Comp->recreate(this); // to apply changes to the schematic symbol
2022  Comp->Name = tmp;
2023  if(x < x1)
2024  x += Comp->x1 - x1;
2025  else if(x > x2)
2026  x += Comp->x2 - x2;
2027  if(y < y1)
2028  y += Comp->y1 - y1;
2029  else if(y > y2)
2030  y += Comp->y2 - y2;
2031  Comp->tx = x; Comp->ty = y;
2032 
2033 
2034  if(PortCount > 0) {
2035  // restore node labels
2036  pl = plMem;
2037  for(pp = Comp->Ports.first(); pp != 0; pp = Comp->Ports.next()) {
2038  if(*pl != 0) {
2039  (*pl)->cx = pp->Connection->cx;
2040  (*pl)->cy = pp->Connection->cy;
2041  placeNodeLabel(*pl);
2042  }
2043  pl++;
2044  if((--PortCount) < 1) break;
2045  }
2046  for( ; PortCount > 0; PortCount--) {
2047  delete (*pl); // delete not needed labels
2048  pl++;
2049  }
2050  free(plMem);
2051  }
2052 }
2053 
2054 // ---------------------------------------------------
2056 {
2057  // connect every node of component to corresponding schematic node
2058  insertComponentNodes(c, false);
2059 
2060  bool ok;
2061  QString s;
2062  int max=1, len = c->Name.length(), z;
2063  if(c->Name.isEmpty()) {
2064  // a ground symbol erases an existing label on the wire line
2065  if(c->Model == "GND") {
2066  c->Model = "x"; // prevent that this ground is found as label
2067  Element *pe = getWireLabel(c->Ports.getFirst()->Connection);
2068  if(pe) if((pe->Type & isComponent) == 0) {
2069  delete ((Conductor*)pe)->Label;
2070  ((Conductor*)pe)->Label = 0;
2071  }
2072  c->Model = "GND"; // rebuild component model
2073  }
2074  }
2075  else {
2076  // determines the name by looking for names with the same
2077  // prefix and increment the number
2078  for(Component *pc = Components->first(); pc != 0; pc = Components->next())
2079  if(pc->Name.left(len) == c->Name) {
2080  s = pc->Name.right(pc->Name.length()-len);
2081  z = s.toInt(&ok);
2082  if(ok) if(z >= max) max = z + 1;
2083  }
2084  c->Name += QString::number(max); // create name with new number
2085  }
2086 
2087  setComponentNumber(c); // important for power sources and subcircuit ports
2088  Components->append(c);
2089 }
2090 
2091 // ---------------------------------------------------
2092 void Schematic::activateCompsWithinRect(int x1, int y1, int x2, int y2)
2093 {
2094  bool changed = false;
2095  int cx1, cy1, cx2, cy2, a;
2096  // exchange rectangle coordinates to obtain x1 < x2 and y1 < y2
2097  cx1 = (x1 < x2) ? x1 : x2; cx2 = (x1 > x2) ? x1 : x2;
2098  cy1 = (y1 < y2) ? y1 : y2; cy2 = (y1 > y2) ? y1 : y2;
2099  x1 = cx1; x2 = cx2;
2100  y1 = cy1; y2 = cy2;
2101 
2102 
2103  for(Component *pc = Components->first(); pc != 0; pc = Components->next()) {
2104  pc->Bounding(cx1, cy1, cx2, cy2);
2105  if(cx1 >= x1) if(cx2 <= x2) if(cy1 >= y1) if(cy2 <= y2) {
2106  a = pc->isActive - 1;
2107 
2108  if(pc->Ports.count() > 1) {
2109  if(a < 0) a = 2;
2110  pc->isActive = a; // change "active status"
2111  }
2112  else {
2113  a &= 1;
2114  pc->isActive = a; // change "active status"
2115  if(a == COMP_IS_ACTIVE) // only for active (not shorten)
2116  if(pc->Model == "GND") // if existing, delete label on wire line
2117  oneLabel(pc->Ports.getFirst()->Connection);
2118  }
2119  changed = true;
2120  }
2121  }
2122 
2123  if(changed) setChanged(true, true);
2124 }
2125 
2126 // ---------------------------------------------------
2128 {
2129  int x1, y1, x2, y2, a;
2130  for(Component *pc = Components->first(); pc != 0; pc = Components->next()) {
2131  pc->Bounding(x1, y1, x2, y2);
2132  if(x >= x1) if(x <= x2) if(y >= y1) if(y <= y2) {
2133  a = pc->isActive - 1;
2134 
2135  if(pc->Ports.count() > 1) {
2136  if(a < 0) a = 2;
2137  pc->isActive = a; // change "active status"
2138  }
2139  else {
2140  a &= 1;
2141  pc->isActive = a; // change "active status"
2142  if(a == COMP_IS_ACTIVE) // only for active (not shorten)
2143  if(pc->Model == "GND") // if existing, delete label on wire line
2144  oneLabel(pc->Ports.getFirst()->Connection);
2145  }
2146  setChanged(true, true);
2147  return true;
2148  }
2149  }
2150  return false;
2151 }
2152 
2153 // ---------------------------------------------------
2155 {
2156  int a;
2157  bool sel = false;
2158  for(Component *pc = Components->first(); pc != 0; pc = Components->next())
2159  if(pc->isSelected) {
2160  a = pc->isActive - 1;
2161 
2162  if(pc->Ports.count() > 1) {
2163  if(a < 0) a = 2;
2164  pc->isActive = a; // change "active status"
2165  }
2166  else {
2167  a &= 1;
2168  pc->isActive = a; // change "active status"
2169  if(a == COMP_IS_ACTIVE) // only for active (not shorten)
2170  if(pc->Model == "GND") // if existing, delete label on wire line
2171  oneLabel(pc->Ports.getFirst()->Connection);
2172  }
2173  sel = true;
2174  }
2175 
2176  if(sel) setChanged(true, true);
2177  return sel;
2178 }
2179 
2180 // ---------------------------------------------------
2181 // Sets the component ports anew. Used after rotate, mirror etc.
2183 {
2184  Port *pp;
2185  WireLabel *pl;
2186  QPtrList<WireLabel> LabelCache;
2187 
2188  for(pp = pc->Ports.first(); pp!=0; pp = pc->Ports.next()) {
2189  pp->Connection->Connections.removeRef((Element*)pc);// delete connections
2190  switch(pp->Connection->Connections.count()) {
2191  case 0:
2192  pl = pp->Connection->Label;
2193  if(pl) {
2194  LabelCache.append(pl);
2195  pl->cx = pp->x + pc->cx;
2196  pl->cy = pp->y + pc->cy;
2197  }
2198  Nodes->removeRef(pp->Connection);
2199  break;
2200  case 2:
2201  oneTwoWires(pp->Connection); // try to connect two wires to one
2202  default: ;
2203  }
2204  }
2205 
2206  // Re-connect component node to schematic node. This must be done completely
2207  // after the first loop in order to avoid problems with node labels.
2208  for(pp = pc->Ports.first(); pp!=0; pp = pc->Ports.next())
2209  pp->Connection = insertNode(pp->x+pc->cx, pp->y+pc->cy, pc);
2210 
2211  for(pl = LabelCache.first(); pl != 0; pl = LabelCache.next())
2212  insertNodeLabel(pl);
2213 }
2214 
2215 // ---------------------------------------------------
2216 // Returns a pointer of the component on whose text x/y points.
2217 Component* Schematic::selectCompText(int x_, int y_, int& w, int& h)
2218 {
2219  int a, b, dx, dy;
2220  for(Component *pc = Components->first(); pc != 0; pc = Components->next()) {
2221  a = pc->cx + pc->tx;
2222  if(x_ < a) continue;
2223  b = pc->cy + pc->ty;
2224  if(y_ < b) continue;
2225 
2226  pc->textSize(dx, dy);
2227  if(x_ > a+dx) continue;
2228  if(y_ > b+dy) continue;
2229 
2230  w = dx;
2231  h = dy;
2232  return pc;
2233  }
2234 
2235  return 0;
2236 }
2237 
2238 // ---------------------------------------------------
2240 {
2241  Component *sub=0;
2242  // test all components
2243  for(Component *pc = Components->first(); pc != 0; pc = Components->next()) {
2244  if(!pc->isSelected) continue;
2245  if(pc->Model != "Sub")
2246  if(pc->Model != "VHDL")
2247  if(pc->Model != "Verilog") continue;
2248 
2249  if(sub != 0) return 0; // more than one subcircuit selected
2250  sub = pc;
2251  }
2252  return sub;
2253 }
2254 
2255 // ---------------------------------------------------
2257 {
2258  // test all components
2259  for(Component *pc = Components->first(); pc != 0; pc = Components->next())
2260  if(pc->getSelected(x, y))
2261  return pc;
2262 
2263  return 0;
2264 }
2265 
2266 // ---------------------------------------------------
2267 // Deletes the component 'c'.
2269 {
2270  Port *pn;
2271 
2272  // delete all port connections
2273  for(pn = c->Ports.first(); pn!=0; pn = c->Ports.next())
2274  switch(pn->Connection->Connections.count()) {
2275  case 1 : if(pn->Connection->Label) delete pn->Connection->Label;
2276  Nodes->removeRef(pn->Connection); // delete open nodes
2277  pn->Connection = 0; // (auto-delete)
2278  break;
2279  case 3 : pn->Connection->Connections.removeRef(c);// delete connection
2280  oneTwoWires(pn->Connection); // two wires -> one wire
2281  break;
2282  default : pn->Connection->Connections.removeRef(c);// remove connection
2283  break;
2284  }
2285 
2286  Components->removeRef(c); // delete component
2287 }
2288 
2289 // ---------------------------------------------------
2290 int Schematic::copyComponents(int& x1, int& y1, int& x2, int& y2,
2291  QPtrList<Element> *ElementCache)
2292 {
2293  Component *pc;
2294  int bx1, by1, bx2, by2, count=0;
2295  // find bounds of all selected components
2296  for(pc = Components->first(); pc != 0; ) {
2297  if(pc->isSelected) {
2298  pc->Bounding(bx1, by1, bx2, by2); // is needed because of "distribute
2299  if(bx1 < x1) x1 = bx1; // uniformly"
2300  if(bx2 > x2) x2 = bx2;
2301  if(by1 < y1) y1 = by1;
2302  if(by2 > y2) y2 = by2;
2303 
2304  count++;
2305  ElementCache->append(pc);
2306 
2307  Port *pp; // rescue non-selected node labels
2308  for(pp = pc->Ports.first(); pp != 0; pp = pc->Ports.next())
2309  if(pp->Connection->Label)
2310  if(pp->Connection->Connections.count() < 2) {
2311  ElementCache->append(pp->Connection->Label);
2312 
2313  // Don't set pp->Connection->Label->pOwner=0,
2314  // so text position stays unchanged, but
2315  // remember component for align/distribute.
2316  pp->Connection->Label->pOwner = (Node*)pc;
2317 
2318  pp->Connection->Label = 0;
2319  }
2320 
2321  deleteComp(pc);
2322  pc = Components->current();
2323  continue;
2324  }
2325  pc = Components->next();
2326  }
2327  return count;
2328 }
2329 
2330 // ---------------------------------------------------
2331 void Schematic::copyComponents2(int& x1, int& y1, int& x2, int& y2,
2332  QPtrList<Element> *ElementCache)
2333 {
2334  Component *pc;
2335  // find bounds of all selected components
2336  for(pc = Components->first(); pc != 0; ) {
2337  if(pc->isSelected) {
2338  // is better for unsymmetrical components
2339  if(pc->cx < x1) x1 = pc->cx;
2340  if(pc->cx > x2) x2 = pc->cx;
2341  if(pc->cy < y1) y1 = pc->cy;
2342  if(pc->cy > y2) y2 = pc->cy;
2343 
2344  ElementCache->append(pc);
2345 
2346  Port *pp; // rescue non-selected node labels
2347  for(pp = pc->Ports.first(); pp != 0; pp = pc->Ports.next())
2348  if(pp->Connection->Label)
2349  if(pp->Connection->Connections.count() < 2) {
2350  ElementCache->append(pp->Connection->Label);
2351  pp->Connection->Label = 0;
2352  // Don't set pp->Connection->Label->pOwner=0,
2353  // so text position stays unchanged.
2354  }
2355 
2356  deleteComp(pc);
2357  pc = Components->current();
2358  continue;
2359  }
2360  pc = Components->next();
2361  }
2362 }
2363 
2364 
2365 /* *******************************************************************
2366  ***** *****
2367  ***** Actions with labels *****
2368  ***** *****
2369  ******************************************************************* */
2370 
2371 // Test, if wire connects wire line with more than one label and delete
2372 // all further labels. Also delete all labels if wire line is grounded.
2374 {
2375  Wire *pw;
2376  Node *pn, *pNode;
2377  Element *pe;
2378  WireLabel *pl = 0;
2379  bool named=false; // wire line already named ?
2380  QPtrList<Node> Cons;
2381 
2382  for(pn = Nodes->first(); pn!=0; pn = Nodes->next())
2383  pn->y1 = 0; // mark all nodes as not checked
2384 
2385  Cons.append(n1);
2386  n1->y1 = 1; // mark Node as already checked
2387  for(pn = Cons.first(); pn!=0; pn = Cons.next()) {
2388  if(pn->Label) {
2389  if(named) {
2390  delete pn->Label;
2391  pn->Label = 0; // erase double names
2392  }
2393  else {
2394  named = true;
2395  pl = pn->Label;
2396  }
2397  }
2398 
2399  for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next()) {
2400  if(pe->Type != isWire) {
2401  if(((Component*)pe)->isActive == COMP_IS_ACTIVE)
2402  if(((Component*)pe)->Model == "GND") {
2403  named = true;
2404  if(pl) {
2405  pl->pOwner->Label = 0;
2406  delete pl;
2407  }
2408  pl = 0;
2409  }
2410  continue;
2411  }
2412  pw = (Wire*)pe;
2413 
2414  if(pn != pw->Port1) pNode = pw->Port1;
2415  else pNode = pw->Port2;
2416 
2417  if(pNode->y1) continue;
2418  pNode->y1 = 1; // mark Node as already checked
2419  Cons.append(pNode);
2420  Cons.findRef(pn);
2421 
2422  if(pw->Label) {
2423  if(named) {
2424  delete pw->Label;
2425  pw->Label = 0; // erase double names
2426  }
2427  else {
2428  named = true;
2429  pl = pw->Label;
2430  }
2431  }
2432  }
2433  }
2434 }
2435 
2436 // ---------------------------------------------------
2438 {
2439  Node *pn;
2440  int x = pl->cx;
2441  int y = pl->cy;
2442 
2443  // check if new node lies upon an existing node
2444  for(pn = Nodes->first(); pn != 0; pn = Nodes->next())
2445  if(pn->cx == x) if(pn->cy == y) break;
2446 
2447  if(!pn) return -1;
2448 
2449  Element *pe = getWireLabel(pn);
2450  if(pe) { // name found ?
2451  if(pe->Type & isComponent) {
2452  delete pl;
2453  return -2; // ground potential
2454  }
2455 
2456  delete ((Conductor*)pe)->Label;
2457  ((Conductor*)pe)->Label = 0;
2458  }
2459 
2460  pn->Label = pl; // insert node label
2461  pl->Type = isNodeLabel;
2462  pl->pOwner = pn;
2463  return 0;
2464 }
2465 
2466 // ---------------------------------------------------
2467 // Test, if wire line is already labeled and returns a pointer to the
2468 // labeled element.
2470 {
2471  Wire *pw;
2472  Node *pn, *pNode;
2473  Element *pe;
2474  QPtrList<Node> Cons;
2475 
2476  for(pn = Nodes->first(); pn!=0; pn = Nodes->next())
2477  pn->y1 = 0; // mark all nodes as not checked
2478 
2479  Cons.append(pn_);
2480  pn_->y1 = 1; // mark Node as already checked
2481  for(pn = Cons.first(); pn!=0; pn = Cons.next())
2482  if(pn->Label) return pn;
2483  else
2484  for(pe = pn->Connections.first(); pe!=0; pe = pn->Connections.next()) {
2485  if(pe->Type != isWire) {
2486  if(((Component*)pe)->isActive == COMP_IS_ACTIVE)
2487  if(((Component*)pe)->Model == "GND") return pe;
2488  continue;
2489  }
2490 
2491  pw = (Wire*)pe;
2492  if(pw->Label) return pw;
2493 
2494  if(pn != pw->Port1) pNode = pw->Port1;
2495  else pNode = pw->Port2;
2496 
2497  if(pNode->y1) continue;
2498  pNode->y1 = 1; // mark Node as already checked
2499  Cons.append(pNode);
2500  Cons.findRef(pn);
2501  }
2502  return 0; // no wire label found
2503 }
2504 
2505 // ---------------------------------------------------
2506 // Inserts a node label.
2508 {
2509  if(placeNodeLabel(pl) != -1)
2510  return;
2511 
2512  // Go on, if label don't lie on existing node.
2513 
2514  Wire *pw = selectedWire(pl->cx, pl->cy);
2515  if(pw) { // lies label on existing wire ?
2516  if(getWireLabel(pw->Port1) == 0) // wire not yet labeled ?
2517  pw->setName(pl->Name, pl->initValue, 0, pl->cx, pl->cy);
2518 
2519  delete pl;
2520  return;
2521  }
2522 
2523 
2524  Node *pn = new Node(pl->cx, pl->cy);
2525  Nodes->append(pn);
2526 
2527  pn->Label = pl;
2528  pl->Type = isNodeLabel;
2529  pl->pOwner = pn;
2530 }
2531 
2532 // ---------------------------------------------------
2533 void Schematic::copyLabels(int& x1, int& y1, int& x2, int& y2,
2534  QPtrList<Element> *ElementCache)
2535 {
2536  WireLabel *pl;
2537  // find bounds of all selected wires
2538  for(Wire *pw = Wires->first(); pw != 0; pw = Wires->next()) {
2539  pl = pw->Label;
2540  if(pl) if(pl->isSelected) {
2541  if(pl->x1 < x1) x1 = pl->x1;
2542  if(pl->y1-pl->y2 < y1) y1 = pl->y1-pl->y2;
2543  if(pl->x1+pl->x2 > x2) x2 = pl->x1+pl->x2;
2544  if(pl->y1 > y2) y2 = pl->y1;
2545  ElementCache->append(pl);
2546  }
2547  }
2548 
2549  for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next()) {
2550  pl = pn->Label;
2551  if(pl) if(pl->isSelected) {
2552  if(pl->x1 < x1) x1 = pl->x1;
2553  if(pl->y1-pl->y2 < y1) y1 = pl->y1-pl->y2;
2554  if(pl->x1+pl->x2 > x2) x2 = pl->x1+pl->x2;
2555  if(pl->y1 > y2) y2 = pl->y1;
2556  ElementCache->append(pl);
2557  pl->pOwner->Label = 0; // erase connection
2558  pl->pOwner = 0;
2559  }
2560  }
2561 }
2562 
2563 
2564 /* *******************************************************************
2565  ***** *****
2566  ***** Actions with paintings *****
2567  ***** *****
2568  ******************************************************************* */
2569 
2571 {
2572  float Corr = 5.0 / Scale; // size of line select
2573 
2574  for(Painting *pp = Paintings->first(); pp != 0; pp = Paintings->next())
2575  if(pp->getSelected(fX, fY, Corr))
2576  return pp;
2577 
2578  return 0;
2579 }
2580 
2581 // ---------------------------------------------------
2582 void Schematic::copyPaintings(int& x1, int& y1, int& x2, int& y2,
2583  QPtrList<Element> *ElementCache)
2584 {
2585  Painting *pp;
2586  int bx1, by1, bx2, by2;
2587  // find boundings of all selected paintings
2588  for(pp = Paintings->first(); pp != 0; )
2589  if(pp->isSelected) {
2590  pp->Bounding(bx1, by1, bx2, by2);
2591  if(bx1 < x1) x1 = bx1;
2592  if(bx2 > x2) x2 = bx2;
2593  if(by1 < y1) y1 = by1;
2594  if(by2 > y2) y2 = by2;
2595 
2596  ElementCache->append(pp);
2597  Paintings->take();
2598  pp = Paintings->current();
2599  }
2600  else pp = Paintings->next();
2601 }