1 /****************************************************************************
2 Copyright (C) 1987-2015 by Jeffery P. Hansen
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 Last edit by hansen on Wed Mar 18 05:13:57 2009
19 ****************************************************************************/
20 /*
21 Functions for manageing the multi-gate selection and cut buffer.
22
23 We have separate handling for single-gate and multi-gate selection
24 mainly due to historical baggage. One day, I will merge them into
25 a single selection
26 */
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <ctype.h>
30 #include <pwd.h>
31 #include <sys/time.h>
32 #include <string.h>
33 #include <assert.h>
34 #include "tkgate.h"
35 #include "comment.h"
36
new_GSelection()37 GSelection *new_GSelection()
38 {
39 GSelection *S = (GSelection*) ob_malloc(sizeof(GSelection),"GSelection");
40
41 ob_touch(S);
42 S->s_gates = new_SHash();
43 S->s_wires = new_NHash();
44 S->s_edgeWires = new_NHash();
45 S->s_hasAnchored = 0;
46
47 return S;
48 }
49
delete_GSelection(GSelection * S)50 void delete_GSelection(GSelection *S)
51 {
52 delete_SHash(S->s_gates);
53 delete_NHash(S->s_wires);
54 delete_NHash(S->s_edgeWires);
55 ob_free(S);
56 }
57
new_GCutBuffer()58 GCutBuffer *new_GCutBuffer()
59 {
60 GCutBuffer *C = (GCutBuffer*) ob_malloc(sizeof(GCutBuffer),"GCutBuffer");
61
62 ob_touch(C);
63 C->cb_minx = C->cb_maxx = C->cb_miny = C->cb_maxy = 0;
64 C->cb_lastTarget = 0;
65 C->cb_dx = C->cb_dy = 0;
66 C->cb_buf = new_GModuleDef("<cut-buffer>");
67
68 return C;
69 }
70
71 /*
72 * Compute the bounding box of a sub-circuit defined by the hash table of gates and wires.
73 */
subcircuitBBX(SHash * ghash,NHash * whash,GWireList * wires,int * minX,int * minY,int * maxX,int * maxY,int append)74 static void subcircuitBBX(SHash *ghash,NHash *whash,GWireList *wires,
75 int *minX,int *minY,int *maxX,int *maxY,int append)
76 {
77 HashElem *E;
78 GWireList *wl;
79 int is_first = !append;
80
81 /*
82 * This will only be used if this is not an append, and there are no gates or wires.
83 */
84 if (is_first) {
85 *minX = 0;
86 *maxX = 0;
87 *minY = 0;
88 *maxY = 0;
89 }
90
91 if (ghash) {
92 for (E = Hash_first(ghash);E;E = Hash_next(ghash,E)) {
93 GCElement *g = (GCElement *) HashElem_obj(E);
94 int MinX,MinY,MaxX,MaxY;
95
96 gate_getbbx(g,TD_X11,&MinX,&MinY,&MaxX,&MaxY);
97
98 if (is_first || MinX < *minX) *minX = MinX;
99 if (is_first || MaxX > *maxX) *maxX = MaxX;
100 if (is_first || MinY < *minY) *minY = MinY;
101 if (is_first || MaxY > *maxY) *maxY = MaxY;
102 is_first = 0;
103
104 }
105 }
106
107 if (whash) {
108 for (E = Hash_first(whash);E;E = Hash_next(whash,E)) {
109 GWire *w = (GWire *) HashElem_obj(E);
110 GWireNode *n;
111
112 w = w->driver;
113 for (n = w->nodes;n;n = n->out) {
114 int x = n->x;
115 int y = n->y;
116
117 if (is_first || x < *minX) *minX = x;
118 if (is_first || x > *maxX) *maxX = x;
119 if (is_first || y < *minY) *minY = y;
120 if (is_first || y > *maxY) *maxY = y;
121 is_first = 0;
122 }
123 }
124 }
125
126 for (wl = wires;wl;wl = wl->wl_next) {
127 GWire *w = wl->wl_wire;
128 GWireNode *n;
129
130 w = w->driver;
131 for (n = w->nodes;n;n = n->out) {
132 int x = n->x;
133 int y = n->y;
134
135 if (is_first || x < *minX) *minX = x;
136 if (is_first || x > *maxX) *maxX = x;
137 if (is_first || y < *minY) *minY = y;
138 if (is_first || y > *maxY) *maxY = y;
139 is_first = 0;
140 }
141 }
142
143 }
144
145 /*
146 * Compute the bounding box of the cut buffer.
147 */
GCutBuffer_computeBounds(GCutBuffer * C)148 void GCutBuffer_computeBounds(GCutBuffer *C)
149 {
150 subcircuitBBX(C->cb_buf->m_gates,0, C->cb_buf->m_wires,
151 &C->cb_minx, &C->cb_miny, &C->cb_maxx, &C->cb_maxy, 0);
152
153 C->cb_ctrx = (C->cb_minx + C->cb_maxx)/2;
154 C->cb_ctry = (C->cb_miny + C->cb_maxy)/2;
155 }
156
delete_GCutBuffer(GCutBuffer * C)157 void delete_GCutBuffer(GCutBuffer *C)
158 {
159 delete_GModuleDef(C->cb_buf);
160 ob_free(C);
161 }
162
163 /*
164 * Change the state of menu entries and toolbar icons depending on whether we
165 * can cut and/or paste.
166 */
sel_updateMenuState()167 void sel_updateMenuState()
168 {
169 static char *states[] = {"disabled","normal"};
170 int paste_ok = TkGate.circuit->cut_buffer != 0;
171 int sel_ok;
172
173 if (!TkGate.tcl) return;
174
175
176 if (TkGate.circuit && TkGate.circuit->es && hdl_isactive) { /* GModuleDef_getType(TkGate.circuit->es->env) == MT_TEXTHDL*/
177 DoTcl("HdlEditor::isselection");
178 sel_ok = (Tcl_GetStringResult(TkGate.tcl)[0] == '1');
179 } else {
180 sel_ok = (TkGate.circuit->select != 0) || (TkGate.circuit->mg_selection != 0);
181 }
182
183 DoTcl("Menu::setFlags %s C %s P",(sel_ok ? "-set" : "-clear"),(paste_ok ? "-set" : "-clear"));
184
185 DoTcl("ToolBar::toolConfigure Edit cut -state %s",states[sel_ok]);
186 DoTcl("ToolBar::toolConfigure Edit copy -state %s",states[sel_ok]);
187 DoTcl("ToolBar::toolConfigure Edit paste -state %s",states[paste_ok]);
188
189 DoTcl("set ::tkg_cutBufferActive %d",paste_ok);
190 DoTcl("set ::tkg_selectionActive %d",sel_ok);
191 }
192
sel_isSelGate(GCElement * g)193 int sel_isSelGate(GCElement *g)
194 {
195 if (!TkGate.circuit->mg_selection)
196 return 0;
197
198 if (SHash_find(TkGate.circuit->mg_selection->s_gates,g->ename))
199 return 1;
200 else
201 return 0;
202 }
203
204
sel_num(EditState * es)205 int sel_num(EditState *es)
206 {
207 GSelection *S = TkGate.circuit->mg_selection;
208
209 if (!S) return 0;
210
211 return Hash_numElems(S->s_gates);
212 }
213
sel_addGate(EditState * es,GCElement * g,int doDraw)214 static void sel_addGate(EditState *es,GCElement *g,int doDraw)
215 {
216 GSelection *S = TkGate.circuit->mg_selection;
217
218 SHash_insert(S->s_gates,g->ename,g);
219
220 ob_touch(S);
221 ob_touch(g);
222
223 if (g->anchored)
224 S->s_hasAnchored = 1;
225
226 if (doDraw) gate_draw(g,GD_NOWIRE);
227 g->selected = 1;
228 if (doDraw) gate_draw(g,GD_NOWIRE);
229 }
230
sel_refinish(EditState * es)231 int sel_refinish(EditState *es)
232 {
233 if (TkGate.circuit->mg_selection) {
234 NHash_flush(TkGate.circuit->mg_selection->s_wires);
235 NHash_flush(TkGate.circuit->mg_selection->s_edgeWires);
236 sel_finish(es);
237 }
238 return 0;
239 }
240
241 /*
242 * Finish up making a selection. Add the wires to the hash tables.
243 */
sel_finish(EditState * es)244 int sel_finish(EditState *es)
245 {
246 GWireList *wl;
247 GSelection *S = TkGate.circuit->mg_selection;
248 int n = Hash_numElems(S->s_gates);
249
250 if (n == 0) {
251 sel_updateMenuState();
252 return 0;
253 }
254
255 ob_touch(TkGate.circuit);
256
257 if (n == 1) {
258 GCElement *g = (GCElement*) HashElem_obj(Hash_first(TkGate.circuit->mg_selection->s_gates));
259 TkGate.circuit->select = g;
260 } else
261 TkGate.circuit->select = 0;
262
263 for (wl = es->env->m_wires;wl;wl = wl->wl_next) {
264 GWire *w1 = wl->wl_wire;
265 GWire *w2 = w1->driver;
266
267 if (w1 == w2) continue; /* Process each each wire only once */
268
269 if (!w1->gate || !SHash_find(S->s_gates,w1->gate->ename))
270 w1 = 0;
271
272 if (!w2->gate || !SHash_find(S->s_gates,w2->gate->ename))
273 w2 = 0;
274
275 if (w1 && w2) {
276 PHash_insert(S->s_wires,w2,w2);
277 } else if (w1) {
278 PHash_insert(S->s_edgeWires,w1,w1);
279 } else if (w2) {
280 PHash_insert(S->s_edgeWires,w2,w2);
281 }
282 }
283
284 sel_updateMenuState();
285 return n;
286 }
287
sel_clear(EditState * es,int doDraw)288 void sel_clear(EditState *es,int doDraw)
289 {
290 ob_touch(TkGate.circuit);
291
292 if (TkGate.circuit->mg_selection) {
293 HashElem *gl;
294 SHash *H = TkGate.circuit->mg_selection->s_gates;
295
296 for (gl = Hash_first(H);gl;gl = Hash_next(H,gl)) {
297 GCElement *g = (GCElement*) HashElem_obj(gl);
298 ob_touch(g);
299 if (doDraw)
300 gate_draw(g,GD_NOWIRE);
301 g->selected = 0;
302 if (doDraw)
303 gate_draw(g,GD_NOWIRE);
304 }
305
306 delete_GSelection(TkGate.circuit->mg_selection);
307 TkGate.circuit->mg_selection = 0;
308 }
309
310 TkGate.circuit->select = 0;
311
312 sel_updateMenuState();
313 }
314
sel_interfaceReset(EditState * es)315 void sel_interfaceReset(EditState *es)
316 {
317 if (TkGate.circuit->mg_selection) {
318 HashElem *E;
319 SHash *H = TkGate.circuit->mg_selection->s_gates;
320
321 for (E = Hash_first(H);E;E = Hash_next(H,E)) {
322 GCElement *g = (GCElement*) HashElem_obj(E);
323 modint_reset(es,g);
324 }
325
326 sel_clear(es,1);
327 }
328 }
329
sel_select(EditState * es)330 int sel_select(EditState *es)
331 {
332 int x = TkGate.ed->sx;
333 int y = TkGate.ed->sy;
334 int width = TkGate.ed->tx-TkGate.ed->sx;
335 int height = TkGate.ed->ty-TkGate.ed->sy;
336 HashElem *gl;
337
338 ob_touch(TkGate.circuit);
339
340 if (!TkGate.circuit->mg_selection)
341 TkGate.circuit->mg_selection = new_GSelection();
342 else {
343 NHash_flush(TkGate.circuit->mg_selection->s_wires);
344 NHash_flush(TkGate.circuit->mg_selection->s_edgeWires);
345 }
346
347 if (width < 0) {
348 width = -width;
349 x = x - width;
350 }
351 if (height < 0) {
352 height = -height;
353 y = y - height;
354 }
355
356 for (gl = Hash_first(es->env->m_gates);gl;gl = Hash_next(es->env->m_gates,gl)) {
357 GCElement *g = (GCElement*) HashElem_obj(gl);
358 int gx,gy;
359
360 gx = g->xpos;
361 gy = g->ypos;
362 if (g->typeinfo->code == GC_BLOCK) {
363 gx += g->u.block.gwidth/2;
364 gy += g->u.block.gheight/2;
365 }
366
367 if (gx >= x && gx <= x+width && gy >= y && gy <=y+height)
368 sel_addGate(es,g,1);
369 }
370
371 return sel_finish(es);
372 }
373
374 /*
375 * Add an additional gate to the selection.
376 */
sel_appendGate(EditState * es,GCElement * g,int doDraw)377 void sel_appendGate(EditState *es,GCElement *g,int doDraw)
378 {
379 ob_touch(TkGate.circuit);
380
381 if (!TkGate.circuit->mg_selection)
382 TkGate.circuit->mg_selection = new_GSelection();
383
384 NHash_flush(TkGate.circuit->mg_selection->s_wires);
385 NHash_flush(TkGate.circuit->mg_selection->s_edgeWires);
386
387 sel_addGate(es,g,doDraw);
388 }
389
sel_unselectGate(EditState * es,GCElement * g)390 void sel_unselectGate(EditState *es,GCElement *g)
391 {
392 GSelection *S = TkGate.circuit->mg_selection;
393
394 if (!S) return;
395
396 SHash_remove(S->s_gates,g->ename);
397 g->selected = 0;
398
399 if (Hash_numElems(S->s_gates) == 0)
400 sel_clear(es,1);
401
402 sel_refinish(es);
403 }
404
405
sel_selectMarked(EditState * es)406 int sel_selectMarked(EditState *es)
407 {
408 HashElem *gl;
409
410 ob_touch(TkGate.circuit);
411 TkGate.circuit->mg_selection = new_GSelection();
412
413 for (gl = Hash_first(es->env->m_gates);gl;gl = Hash_next(es->env->m_gates,gl)) {
414 GCElement *g = (GCElement*) HashElem_obj(gl);
415 if (g->selected)
416 sel_addGate(es,g,1);
417 }
418 return sel_finish(es);
419 }
420
sel_selectAll(EditState * es)421 int sel_selectAll(EditState *es)
422 {
423 HashElem *gl;
424
425 ob_touch(TkGate.circuit);
426
427 if (!TkGate.circuit->mg_selection)
428 TkGate.circuit->mg_selection = new_GSelection();
429
430 for (gl = Hash_first(es->env->m_gates);gl;gl = Hash_next(es->env->m_gates,gl)) {
431 GCElement *g = (GCElement*) HashElem_obj(gl);
432 sel_addGate(es,g,1);
433 }
434
435 return sel_finish(es);
436 }
437
438 /*
439 * Rotate the selection.
440 */
sel_rotate(EditState * es,int rdir)441 void sel_rotate(EditState *es,int rdir)
442 {
443 int minX, minY, maxX, maxY, centX, centY, newcentX, newcentY;
444 GSelection *S = TkGate.circuit->mg_selection;
445 HashElem *E;
446
447 if (!S) return;
448
449 if (GModuleDef_isDataProtected(TkGate.circuit->es->env)) {
450 message(0,msgLookup("err.protdata"));
451 return;
452 }
453 if (S->s_hasAnchored) {
454 message(0,msgLookup("err.gatanchor")); /* Gate(s) are anchored and can not be moved. */
455 return;
456 }
457
458 /*
459 * If there are edge wires, make sure that non are attached to anything.
460 */
461 if (Hash_numElems(S->s_edgeWires) > 0) {
462 int ok = 1;
463
464 for (E = Hash_first(S->s_edgeWires);E;E = Hash_next(S->s_edgeWires,E)) {
465 GWire *w = (GWire*) HashElem_obj(E);
466
467 w = w->driver;
468 if (w->gate && !w->gate->selected)
469 ok = 0;
470
471 w = wire_drivee(w);
472 if (w->gate && !w->gate->selected)
473 ok = 0;
474 }
475
476 if (!ok) {
477 message(0,msgLookup("err.wirerot"));
478 return;
479 }
480 }
481
482 SetModified(MF_NET|MF_GATE);
483 ob_touch(TkGate.circuit);
484
485 subcircuitBBX(S->s_gates, S->s_wires, 0,
486 &minX, &minY, &maxX, &maxY, 0);
487
488 centX = (minX + maxX)/2;
489 centY = (minY + maxY)/2;
490
491 for (E = Hash_first(S->s_wires);E;E = Hash_next(S->s_wires,E)) {
492 GWire *w = (GWire*) HashElem_obj(E);
493 GWireNode *n;
494
495 w = w->driver;
496 for (n = w->nodes;n;n = n->out) {
497 int x = n->x;
498 int y = n->y;
499 ob_touch(n);
500 n->x = rotateX(x - centX,y - centY,rdir) + centX;
501 n->y = rotateY(x - centX,y - centY,rdir) + centY;
502 }
503
504 ob_touch(w);
505 w->orient = (w->orient + 4 + rdir) % 4;
506 w = wire_drivee(w);
507 ob_touch(w);
508 w->orient = (w->orient + 4 + rdir) % 4;
509 }
510 for (E = Hash_first(S->s_edgeWires);E;E = Hash_next(S->s_edgeWires,E)) {
511 GWire *w = (GWire*) HashElem_obj(E);
512 GWireNode *n;
513
514 w = w->driver;
515 for (n = w->nodes;n;n = n->out) {
516 int x = n->x;
517 int y = n->y;
518 ob_touch(n);
519 n->x = rotateX(x - centX,y - centY,rdir) + centX;
520 n->y = rotateY(x - centX,y - centY,rdir) + centY;
521 }
522
523 ob_touch(w);
524 w->orient = (w->orient + 4 + rdir) % 4;
525 w = wire_drivee(w);
526 ob_touch(w);
527 w->orient = (w->orient + 4 + rdir) % 4;
528 }
529
530 for (E = Hash_first(S->s_gates);E;E = Hash_next(S->s_gates,E)) {
531 GCElement *g = (GCElement*) HashElem_obj(E);
532
533 (*g->typeinfo->Rotate)(g,centX,centY,rdir);
534 }
535
536 /*
537 * Compute new center after rotation and nudge it back to the before
538 * rotation center position. This prevents gates from "walking" as
539 * they are rotated.
540 */
541 subcircuitBBX(S->s_gates, S->s_wires, 0,
542 &minX, &minY, &maxX, &maxY, 0);
543 newcentX = (minX + maxX)/2;
544 newcentY = (minY + maxY)/2;
545 if (newcentX != centX || newcentY != centY) {
546 sel_move(es,centX-newcentX,centY-newcentY);
547 }
548 }
549
sel_move(EditState * es,int dx,int dy)550 void sel_move(EditState *es,int dx,int dy)
551 {
552 HashElem *E;
553 SHash *GH;
554 NHash *WH,*EWH;
555
556 if (!TkGate.circuit->mg_selection) return;
557
558 if (GModuleDef_isDataProtected(TkGate.circuit->es->env)) {
559 message(0,msgLookup("err.protdata"));
560 return;
561 }
562 if (TkGate.circuit->mg_selection->s_hasAnchored) {
563 message(0,msgLookup("err.gatanchor")); /* Gate(s) are anchored and can not be moved. */
564 return;
565 }
566
567 SetModified(MF_NET|MF_GATE);
568 ob_touch(TkGate.circuit);
569
570 GH = TkGate.circuit->mg_selection->s_gates;
571 WH = TkGate.circuit->mg_selection->s_wires;
572 EWH = TkGate.circuit->mg_selection->s_edgeWires;
573
574 for (E = Hash_first(GH);E;E = Hash_next(GH,E)) {
575 GCElement *g = (GCElement*) HashElem_obj(E);
576
577 ob_touch(g);
578 g->xpos += dx;
579 g->ypos += dy;
580
581 }
582
583 for (E = Hash_first(WH);E;E = Hash_next(WH,E)) {
584 GWire *w = (GWire*) HashElem_obj(E);
585 GWireNode *n;
586
587 for (n = w->driver->nodes;n;n = n->out) {
588 ob_touch(n);
589 n->x += dx;
590 n->y += dy;
591 }
592 }
593
594 for (E = Hash_first(EWH);E;E = Hash_next(EWH,E)) {
595 GWire *w = (GWire*) HashElem_obj(E);
596 wire_move(w->nodes,dx,dy,FULL);
597 }
598 }
599
sel_draw(EditState * es)600 void sel_draw(EditState *es)
601 {
602 HashElem *E;
603 SHash *GH;
604 NHash *WH,*EWH;
605
606 if (!TkGate.circuit->mg_selection) return;
607
608 GH = TkGate.circuit->mg_selection->s_gates;
609 WH = TkGate.circuit->mg_selection->s_wires;
610 EWH = TkGate.circuit->mg_selection->s_edgeWires;
611
612 for (E = Hash_first(GH);E;E = Hash_next(GH,E)) {
613 GCElement *g = (GCElement*) HashElem_obj(E);
614 gate_draw(g,GD_NOWIRE);
615 }
616
617 for (E = Hash_first(WH);E;E = Hash_next(WH,E)) {
618 GWire *w = (GWire*) HashElem_obj(E);
619 GWire_draw(w->driver);
620 }
621
622 for (E = Hash_first(EWH);E;E = Hash_next(EWH,E)) {
623 GWire *w = (GWire*) HashElem_obj(E);
624 GWire_draw(w->driver);
625 }
626 }
627
sel_dropFixup(EditState * es)628 void sel_dropFixup(EditState *es)
629 {
630 HashElem *E;
631 NHash *EWH;
632
633 if (!TkGate.circuit->mg_selection) return;
634
635 EWH = TkGate.circuit->mg_selection->s_edgeWires;
636
637 for (E = Hash_first(EWH);E;E = Hash_next(EWH,E)) {
638 GWire *w = (GWire*) HashElem_obj(E);
639
640 GWire_draw(w->driver);
641 GWire_snap(w->driver);
642 GWire_draw(w->driver);
643 }
644 }
645
sel_copy(EditState * es)646 void sel_copy(EditState *es)
647 {
648 GModuleDef *m = es->env;
649 GModuleDef *cbm;
650
651 if (TkGate.circuit->cut_buffer) delete_GCutBuffer(TkGate.circuit->cut_buffer);
652
653 ob_touch(TkGate.circuit);
654
655 TkGate.circuit->cut_buffer = new_GCutBuffer();
656 cbm = TkGate.circuit->cut_buffer->cb_buf;
657
658 if (hdl_isactive) {
659 DoTcl("HdlEditor::dumpSelection");
660 cbm->m_type = MT_TEXTHDL;
661 GModuleDef_saveText(cbm, Tcl_GetStringResult(TkGate.tcl));
662 } else {
663 GModuleDef_copyInto(cbm, m, 0,0,1,0);
664 GCutBuffer_computeBounds(TkGate.circuit->cut_buffer);
665 TkGate.circuit->cut_buffer->cb_dx = 0;
666 TkGate.circuit->cut_buffer->cb_dy = 0;
667 TkGate.circuit->cut_buffer->cb_lastTarget = es->env;
668 }
669
670 sel_updateMenuState();
671 }
672
sel_copyAppend(EditState * es)673 void sel_copyAppend(EditState *es)
674 {
675 /** @TODO to remove */
676 /*
677 GModuleDef *m = es->env;
678 */
679 GModuleDef *cbm;
680
681 ob_touch(TkGate.circuit);
682
683 if (!TkGate.circuit->cut_buffer) {
684 printf("bad copyappend(1)\n");
685 return;
686 }
687
688 cbm = TkGate.circuit->cut_buffer->cb_buf;
689
690 if (!hdl_isactive) {
691 printf("bad copyappend(2)\n");
692 return;
693 }
694 if (!hdl_isactive) {
695 printf("bad copyappend(3)\n");
696 return;
697 }
698
699 ob_touch(TkGate.circuit->cut_buffer);
700 DoTcl("HdlEditor::dumpSelection");
701
702 ob_touch(cbm);
703 cbm->m_type = MT_TEXTHDL;
704 GModuleDef_allocText(cbm, strlen(cbm->m_text) + strlen(Tcl_GetStringResult(TkGate.tcl)) + 1);
705 strcat(cbm->m_text, Tcl_GetStringResult(TkGate.tcl));
706
707 sel_updateMenuState();
708 }
709
sel_kill(EditState * es)710 void sel_kill(EditState *es)
711 {
712 /** @TODO to remove */
713 /*
714 GModuleDef *m = es->env;
715 */
716 if (hdl_isactive) {
717 DoTcl("HdlEditor::isselection2");
718 if (Tcl_GetStringResult(TkGate.tcl)[0] != '1') return;
719 sel_copy(es);
720 DoTcl("HdlEditor::doDelete 0");
721 } else {
722 sel_copy(es);
723 sel_delete(es);
724 ob_touch(TkGate.circuit->cut_buffer);
725 TkGate.circuit->cut_buffer->cb_dx = 0;
726 TkGate.circuit->cut_buffer->cb_dy = 0;
727 }
728 }
729
sel_killAppend(EditState * es)730 void sel_killAppend(EditState *es)
731 {
732 /** @TODO to remove */
733 /*
734 GModuleDef *m = es->env;
735 */
736 sel_copyAppend(es);
737
738 if (hdl_isactive) {
739 DoTcl("HdlEditor::doDelete 0");
740 } else {
741 sel_delete(es);
742 ob_touch(TkGate.circuit->cut_buffer);
743 TkGate.circuit->cut_buffer->cb_dx = 0;
744 TkGate.circuit->cut_buffer->cb_dy = 0;
745 }
746 }
747
sel_clearDelta()748 void sel_clearDelta()
749 {
750 if (TkGate.circuit->cut_buffer) {
751 ob_touch(TkGate.circuit->cut_buffer);
752 TkGate.circuit->cut_buffer->cb_dx = 0;
753 TkGate.circuit->cut_buffer->cb_dy = 0;
754 }
755 }
756
757 /*****************************************************************************
758 *
759 * Yank data from the cut buffer into an HDL module.
760 *
761 *****************************************************************************/
sel_hdlyank(EditState * es)762 void sel_hdlyank(EditState *es)
763 {
764 GModuleDef *cbm;
765
766 if (!TkGate.circuit->cut_buffer) return;
767
768 cbm = TkGate.circuit->cut_buffer->cb_buf;
769
770 if (hdl_isactive) {
771 DoTclL("HdlEditor::insert",cbm->m_text,NULL);
772 } else {
773 char fileName[STRMAX];
774 getSimTempFile(fileName);
775 sel_writeToFile(fileName);
776 DoTcl("HdlEditor::insertFile %s",fileName);
777 unlink(fileName);
778 }
779 }
780
781 /*****************************************************************************
782 *
783 * Yank data from the cut buffer into a netlist module.
784 *
785 *****************************************************************************/
sel_yank(EditState * es)786 void sel_yank(EditState *es)
787 {
788 GModuleDef *cbm;
789
790 if (!TkGate.circuit->cut_buffer) return;
791
792 cbm = TkGate.circuit->cut_buffer->cb_buf;
793
794 if (TkGate.ed->mark_vis) {
795 ob_touch(TkGate.circuit->cut_buffer);
796 TkGate.circuit->cut_buffer->cb_dx = TkGate.ed->tx - TkGate.circuit->cut_buffer->cb_ctrx;
797 TkGate.circuit->cut_buffer->cb_dy = TkGate.ed->ty - TkGate.circuit->cut_buffer->cb_ctry;
798 mark_unpost();
799 }
800
801 sel_clear(es,1);
802
803 if (hdl_isactive) {
804 GGateInfo *GI = GGateInfo_lookup("COMMENT");
805 EditState **pes = &TkGate.circuit->es;
806 GCElement *g;
807 char *text = cbm->m_text;
808
809 if (GI) {
810 const char *argv[2];
811 argv[0] = "-nodialog";
812 argv[1] = "1";
813
814 g = (*GI->MakeFunction)(pes,es->env,GI->code,TkGate.ed->tx,TkGate.ed->ty,0,0,0,argv,2);
815 if (g) {
816 char *p,*q;
817
818 p = text;
819 while ((q = strchr(p,'\n'))) {
820 *q = 0;
821 Comment_addLine(g,p);
822 *q = '\n';
823 p = q+1;
824 }
825 Comment_addLine(g,p);
826
827
828 gate_draw(g,0);
829 sel_appendGate(*pes,g,1);
830 sel_finish(*pes);
831 ob_touch(TkGate.circuit);
832 TkGate.circuit->select = g;
833 scrollbar_bbx_update();
834 SynchronizeInterface();
835 }
836 }
837 } else {
838 ob_touch(TkGate.circuit->cut_buffer);
839 if (TkGate.circuit->cut_buffer->cb_lastTarget == es->env) {
840 TkGate.circuit->cut_buffer->cb_dx += 20;
841 TkGate.circuit->cut_buffer->cb_dy += 20;
842 }
843 TkGate.circuit->cut_buffer->cb_lastTarget = es->env;
844
845 GModuleDef_copyInto(es->env, cbm, TkGate.circuit->cut_buffer->cb_dx,TkGate.circuit->cut_buffer->cb_dy,0,1);
846 if (sel_selectMarked(es)) {
847 EditState_setMode(MODE_MOVESEL);
848 }
849
850 if (GModuleDef_hasSubModules(cbm))
851 SetModified(MF_NET|MF_GATE|MF_MODULE);
852 else
853 SetModified(MF_NET|MF_GATE);
854 }
855
856 sel_updateMenuState();
857 }
858
sel_delete(EditState * es)859 void sel_delete(EditState *es)
860 {
861 if (sel_num(es) == 0) return;
862
863 SetModified(MF_NET|MF_GATE);
864
865 ob_touch(TkGate.circuit);
866
867 /*
868 * A single gate was selected.
869 */
870 if (sel_num(es) == 1) {
871
872 if (GCElement_isModule(TkGate.circuit->select))
873 SetModified(MF_MODULE);
874
875 gate_delete(TkGate.circuit->select,es->env,1);
876
877 delete_GSelection(TkGate.circuit->mg_selection);
878 TkGate.circuit->mg_selection = 0;
879 TkGate.circuit->last = TkGate.circuit->select = 0;
880
881 return;
882 }
883
884 if (TkGate.circuit->mg_selection) {
885 HashElem *gl;
886 SHash *H = TkGate.circuit->mg_selection->s_gates;
887 PHash *delGates = new_PHash();
888
889 for (gl = Hash_first(H);gl;gl = Hash_next(H,gl)) {
890 GCElement *g = (GCElement*) HashElem_obj(gl);
891 if (g->typeinfo->code != GC_JOINT)
892 PHash_insert(delGates,g,g);
893 }
894
895 for (gl = Hash_first(delGates);gl;gl = Hash_next(delGates,gl)) {
896 GCElement *g = (GCElement*) HashElem_obj(gl);
897 if (GCElement_isModule(g))
898 SetModified(MF_MODULE);
899
900 gate_delete(g,es->env,0);
901 }
902
903 delete_PHash(delGates);
904
905 delete_GSelection(TkGate.circuit->mg_selection);
906 TkGate.circuit->mg_selection = 0;
907 }
908 sel_updateMenuState();
909 TkGate.circuit->last = TkGate.circuit->select = 0;
910
911 FlagRedraw();
912 }
913
sel_anchor(EditState * es,int isSet)914 void sel_anchor(EditState *es,int isSet)
915 {
916 HashElem *E;
917 SHash *GH;
918
919 if (!TkGate.circuit->mg_selection) return;
920
921 ob_touch(TkGate.circuit->mg_selection);
922 TkGate.circuit->mg_selection->s_hasAnchored = (isSet != 0);
923
924 GH = TkGate.circuit->mg_selection->s_gates;
925 for (E = Hash_first(GH);E;E = Hash_next(GH,E)) {
926 GCElement *g = (GCElement*) HashElem_obj(E);
927 ob_touch(g);
928 g->anchored = (isSet != 0);
929 }
930 }
931
sel_setTech(EditState * es,const char * tech)932 void sel_setTech(EditState *es,const char *tech)
933 {
934 HashElem *E;
935 SHash *GH;
936
937 if (!TkGate.circuit->mg_selection) return;
938
939 GH = TkGate.circuit->mg_selection->s_gates;
940 for (E = Hash_first(GH);E;E = Hash_next(GH,E)) {
941 GCElement *g = (GCElement*) HashElem_obj(E);
942
943 if (g->tech && g->typeinfo->num_delays > 0) {
944 ob_free(g->tech);
945 ob_touch(g);
946 g->tech = ob_strdup(tech);
947 }
948
949 }
950 }
951
952
sel_alignHorz(EditState * es)953 void sel_alignHorz(EditState *es)
954 {
955 HashElem *E;
956 SHash *GH;
957 int y,n;
958
959 if (!TkGate.circuit->mg_selection) return;
960
961 n = y = 0;
962 GH = TkGate.circuit->mg_selection->s_gates;
963 for (E = Hash_first(GH);E;E = Hash_next(GH,E)) {
964 GCElement *g = (GCElement*) HashElem_obj(E);
965 y += g->ypos;
966 n++;
967 }
968 if (n < 2) return;
969 y /= n;
970
971 n = 0;
972 for (E = Hash_first(GH);E;E = Hash_next(GH,E)) {
973 GCElement *g = (GCElement*) HashElem_obj(E);
974 if (!g->anchored && y != g->ypos)
975 gate_moveObject(g,0,y-g->ypos);
976 if (g->anchored) n++;
977 }
978 if (n) message(0,msgLookup("err.gatanchor")); /* Gate(s) are anchored and can not be moved. */
979 }
980
sel_alignVert(EditState * es)981 void sel_alignVert(EditState *es)
982 {
983 HashElem *E;
984 SHash *GH;
985 int x,n;
986
987 if (!TkGate.circuit->mg_selection) return;
988
989 n = x = 0;
990 GH = TkGate.circuit->mg_selection->s_gates;
991 for (E = Hash_first(GH);E;E = Hash_next(GH,E)) {
992 GCElement *g = (GCElement*) HashElem_obj(E);
993 x += g->xpos;
994 n++;
995 }
996 if (n < 2) return;
997 x /= n;
998
999 n = 0;
1000 for (E = Hash_first(GH);E;E = Hash_next(GH,E)) {
1001 GCElement *g = (GCElement*) HashElem_obj(E);
1002 if (!g->anchored && x != g->xpos)
1003 gate_moveObject(g,x-g->xpos,0);
1004 if (g->anchored) n++;
1005 }
1006 if (n) message(0,msgLookup("err.gatanchor")); /* Gate(s) are anchored and can not be moved. */
1007 }
1008
1009 /*****************************************************************************
1010 *
1011 * Write the contents of the selection buffer to a file.
1012 *
1013 *****************************************************************************/
sel_writeToFile(const char * fileName)1014 int sel_writeToFile(const char *fileName)
1015 {
1016 HashElem *E;
1017 SHash *GH;
1018 FILE *f;
1019
1020 GH = TkGate.circuit->cut_buffer->cb_buf->m_gates;
1021
1022 f = fopen(fileName,"w");
1023 if (!f) return -1;
1024
1025 VerilogWriteInit();
1026 for (E = Hash_first(GH);E;E = Hash_next(GH,E)) {
1027 GCElement *g = (GCElement*) HashElem_obj(E);
1028
1029 if (g->typeinfo->VerSave)
1030 (*g->typeinfo->VerSave)(f,g);
1031 }
1032
1033 fclose(f);
1034
1035 return 0;
1036 }
1037
1038