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 Tue May 5 20:55:15 2009
19 ****************************************************************************/
20 /*
21 General purpose functions used by the editor.
22 */
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <ctype.h>
27 #include <unistd.h>
28 #include <pwd.h>
29 #include <sys/time.h>
30 #include <string.h>
31 #include <assert.h>
32 #include "tkgate.h"
33
34 int stepsize;
35
36 int did_interface_resize = 0;
37
38 int debugmode = 0;
39
40 /*****************************************************************************
41 *
42 * Draws a line in circuit space with appropriate adjustments for scaling
43 * and scroll position.
44 *
45 *****************************************************************************/
line(int x1,int y1,int x2,int y2)46 void line(int x1,int y1,int x2,int y2)
47 {
48 ZDrawLine(TkGate.D,TkGate.W,TkGate.toolGC,ctow_x(x1), ctow_y(y1), ctow_x(x2), ctow_y(y2));
49 }
50
51 /*****************************************************************************
52 *
53 * Draws a box in circuit space with appropriate adjustments for scaling
54 * and scroll position.
55 *
56 *****************************************************************************/
box(int x,int y,int w,int h)57 void box(int x,int y,int w,int h)
58 {
59 ZDrawRectangle(TkGate.D,TkGate.W,TkGate.toolGC,ctow_x(x),ctow_y(y),w,h);
60 }
61
62 /*****************************************************************************
63 *
64 * Displays, or erases a gate symbol on the screen.
65 *
66 *****************************************************************************/
mk_gate(int x,int y,GGateInfo * gi,int rot,int selected)67 void mk_gate(int x,int y,GGateInfo *gi,int rot,int selected)
68 {
69 int idx;
70
71 idx = rot;
72 if (selected) idx += 4;
73
74 Icon_draw(TkGate.D,TkGate.W,TkGate.instGC,ctow_x(x),ctow_y(y),gi->icon[idx]);
75 }
76
77 /*****************************************************************************
78 *
79 * Draws the mark symbol
80 *
81 *****************************************************************************/
mark_draw()82 void mark_draw()
83 {
84 Icon_draw(TkGate.D,TkGate.W,TkGate.toolGC,ctow_x(TkGate.ed->mark_x),ctow_y(TkGate.ed->mark_y),Mark);
85 }
86
87 /*****************************************************************************
88 *
89 * Flush the mark state (as a result of screen being cleared)
90 *
91 *****************************************************************************/
mark_flush()92 void mark_flush()
93 {
94 #if TOUCH_XGATE_ED
95 ob_touch(TkGate.ed);
96 #endif
97 TkGate.ed->mark_vis = 0;
98 }
99
100 /*****************************************************************************
101 *
102 * Temporarily hide the mark symbol
103 *
104 *****************************************************************************/
mark_hide()105 void mark_hide()
106 {
107 if (TkGate.ed->mark_vis)
108 mark_draw();
109 mark_flush();
110 }
111
112 /*****************************************************************************
113 *
114 * Redraw mark is posted but not visible
115 *
116 *****************************************************************************/
mark_redraw()117 void mark_redraw()
118 {
119 if (TkGate.ed->mark_posted && !TkGate.ed->mark_vis) {
120 mark_draw();
121 #if TOUCH_XGATE_ED
122 ob_touch(TkGate.ed);
123 #endif
124 TkGate.ed->mark_vis = 1;
125 }
126 }
127
128 /*****************************************************************************
129 *
130 * Displays the mark on the screen and marks it as visible.
131 *
132 *****************************************************************************/
mark_post()133 void mark_post()
134 {
135 if (EditState_getMode() != MODE_MOVE ||
136 TkGate.circuit->select ||
137 TkGate.circuit->labelsel->net ||
138 TkGate.circuit->mg_selection ||
139 TkGate.circuit->wnsel ||
140 editstate_isInterfaceMode() ||
141 Hyperlink_isPending())
142 return;
143
144 if (TkGate.ed->mark_vis)
145 mark_draw();
146
147 #if TOUCH_XGATE_ED
148 ob_touch(TkGate.ed);
149 #endif
150 TkGate.ed->mark_x = TkGate.ed->tx;
151 TkGate.ed->mark_y = TkGate.ed->ty;
152 mark_draw();
153 TkGate.ed->mark_vis = 1;
154 TkGate.ed->mark_posted = 1;
155 }
156
157 /******************************************************************************
158 *
159 * Removes the mark from the screen and marks it as not visible.
160 *
161 *****************************************************************************/
mark_unpost()162 void mark_unpost()
163 {
164 if (!TkGate.ed->mark_vis) return;
165 mark_draw();
166 #if TOUCH_XGATE_ED
167 ob_touch(TkGate.ed);
168 #endif
169 TkGate.ed->mark_vis = 0;
170 TkGate.ed->mark_posted = 0;
171 }
172
HandScroll_set(EditState * es)173 void HandScroll_set(EditState *es)
174 {
175 int x = TkGate.ed->rx;
176 int y = TkGate.ed->ry;
177
178 ob_suggest_name("Scroll");
179
180 ob_touch(TkGate.ed);
181 TkGate.ed->handScroll.orgSave_x = TkGate.circuit->org_x;
182 TkGate.ed->handScroll.orgSave_y = TkGate.circuit->org_y;
183 TkGate.ed->handScroll.setSave_x = x;
184 TkGate.ed->handScroll.setSave_y = y;
185
186 }
187
HandScroll_move(EditState * es)188 void HandScroll_move(EditState *es)
189 {
190 int sx = TkGate.ed->handScroll.setSave_x;
191 int sy = TkGate.ed->handScroll.setSave_y;
192 int x = TkGate.ed->rx;
193 int y = TkGate.ed->ry;
194 int ox = TkGate.ed->handScroll.orgSave_x;
195 int oy = TkGate.ed->handScroll.orgSave_y;
196 int dx = (x-sx)/TkGate.circuit->zoom_factor;
197 int dy = (y-sy)/TkGate.circuit->zoom_factor;
198
199 if (TkGate.smoothScroll) {
200 TkGate.idle_ev.scroll_new_x = ox + dx;
201 TkGate.idle_ev.scroll_new_y = oy + dy;
202 FlagScrolling();
203 } else {
204 ob_touch(TkGate.circuit);
205 TkGate.circuit->org_x = ox + dx;
206 TkGate.circuit->org_y = oy + dy;
207 FlagRedraw();
208 }
209 }
210
HandScroll_drop(EditState * es)211 void HandScroll_drop(EditState *es)
212 {
213 /** @TODO to remove */
214 /*
215 int x = TkGate.ed->rx;
216 int y = TkGate.ed->ry;
217 */
218
219 HandScroll_move(es);
220 }
221
222 /*****************************************************************************
223 *
224 * Try to select a gate at the specified position.
225 *
226 *****************************************************************************/
EditState_selectGate(EditState * es,int tx,int ty)227 void EditState_selectGate(EditState *es,int tx,int ty)
228 {
229 GModuleDef *env = es->env;
230 GCElement *g;
231
232 g = gate_hit(env,tx,ty);
233
234 if (!(TkGate.state & ControlMask))
235 sel_clear(es,1);
236
237 if (g) {
238 int n;
239
240 sel_appendGate(es,g,1);
241 sel_refinish(es);
242
243 ob_touch(TkGate.circuit);
244 TkGate.circuit->last = 0;
245 n = sel_num(es);
246 TkGate.circuit->select = (n == 1) ? g : 0;
247 if (n > 1) {
248 EditState_setMode( MODE_MOVESEL);
249 }
250 }
251 }
252
253 /*****************************************************************************
254 *
255 * Unselect any selected gate or gates.
256 *
257 *****************************************************************************/
EditState_unselectGate(EditState * es)258 void EditState_unselectGate(EditState *es)
259 {
260 if (TkGate.circuit->select) {
261 gate_draw(TkGate.circuit->select,GD_NORMAL);
262 gate_mark(TkGate.circuit->select,0);
263 gate_draw(TkGate.circuit->select,GD_NORMAL);
264 }
265 ob_touch(TkGate.circuit);
266 TkGate.circuit->last = NULL;
267 TkGate.circuit->select = NULL;
268 }
269
270 /*****************************************************************************
271 *
272 * Do a "snap" operation on a wire.
273 *
274 *****************************************************************************/
DoSnap(GWire * w)275 void DoSnap(GWire *w)
276 {
277 GWire_draw(w->driver);
278 GWire_snap(w->driver);
279 GWire_draw(w->driver);
280 }
281
282 /*****************************************************************************
283 *
284 * Update the bat cursor if we are in move mode.
285 *
286 *****************************************************************************/
SetBatCursor()287 void SetBatCursor()
288 {
289 if (EditState_getMode() != MODE_MOVE) return;
290 if (TkGate.circuit->wnsel) return;
291
292 switch (TkGate.batc) {
293 case 0 :
294 wm_SetCursor(BATCURSOR1);
295 break;
296 case 1 :
297 wm_SetCursor(BATCURSOR2);
298 break;
299 case 2 :
300 wm_SetCursor(BATCURSOR3);
301 break;
302 case 3 :
303 wm_SetCursor(BATCURSOR2);
304 break;
305 }
306 TkGate.batc = (TkGate.batc + 1) % 4;
307 }
308
309 /*****************************************************************************
310 *
311 * Set the anchor end of rubber band line at the current position.
312 *
313 *****************************************************************************/
setrubberband(EditState * es)314 void setrubberband(EditState *es)
315 {
316 #if TOUCH_XGATE_ED
317 ob_touch(TkGate.ed);
318 #endif
319 TkGate.ed->lx = TkGate.ed->sx = TkGate.ed->tx;
320 TkGate.ed->lx = TkGate.ed->sy = TkGate.ed->ty;
321
322 ZDrawLine(TkGate.D,TkGate.W,TkGate.toolGC,ctow_x(TkGate.ed->sx),ctow_y(TkGate.ed->sy),ctow_x(TkGate.ed->tx),ctow_y(TkGate.ed->ty));
323 }
324
325 /*****************************************************************************
326 *
327 * Move the free end of rubber band line to the current position.
328 *
329 *****************************************************************************/
moverubberband(EditState * es)330 void moverubberband(EditState *es)
331 {
332 ZDrawLine(TkGate.D,TkGate.W,TkGate.toolGC,ctow_x(TkGate.ed->sx),ctow_y(TkGate.ed->sy),ctow_x(TkGate.ed->lx),ctow_y(TkGate.ed->ly));
333 ZDrawLine(TkGate.D,TkGate.W,TkGate.toolGC,ctow_x(TkGate.ed->sx),ctow_y(TkGate.ed->sy),ctow_x(TkGate.ed->tx),ctow_y(TkGate.ed->ty));
334 }
335
336 /*****************************************************************************
337 *
338 * Set the anchor corner of a rubber band box at the current position.
339 *
340 *****************************************************************************/
setRubberBox(EditState * es)341 void setRubberBox(EditState *es)
342 {
343 int x = ctow_x(TkGate.ed->sx);
344 int y = ctow_y(TkGate.ed->sy);
345 int width = TkGate.ed->tx-TkGate.ed->sx;
346 int height = TkGate.ed->ty-TkGate.ed->sy;
347
348 if (width < 0) {
349 width = -width;
350 x = x - width;
351 }
352 if (height < 0) {
353 height = -height;
354 y = y - height;
355 }
356
357 ZDrawRectangle(TkGate.D,TkGate.W,TkGate.toolGC,x,y,width,height);
358 }
359
360 /*****************************************************************************
361 *
362 * Set the free corner of a rubber band box to the current position.
363 *
364 *****************************************************************************/
moveRubberBox(EditState * es)365 void moveRubberBox(EditState *es)
366 {
367 int x = ctow_x(TkGate.ed->sx);
368 int y = ctow_y(TkGate.ed->sy);
369 int lx = ctow_x(TkGate.ed->sx);
370 int ly = ctow_y(TkGate.ed->sy);
371 int width = TkGate.ed->tx-TkGate.ed->sx;
372 int height = TkGate.ed->ty-TkGate.ed->sy;
373 int lwidth = TkGate.ed->lx-TkGate.ed->sx;
374 int lheight = TkGate.ed->ly-TkGate.ed->sy;
375
376 if (width < 0) {
377 width = -width;
378 x = x - width;
379 }
380 if (height < 0) {
381 height = -height;
382 y = y - height;
383 }
384 if (lwidth < 0) {
385 lwidth = -lwidth;
386 lx = lx - lwidth;
387 }
388 if (lheight < 0) {
389 lheight = -lheight;
390 ly = ly - lheight;
391 }
392
393 ZDrawRectangle(TkGate.D,TkGate.W,TkGate.toolGC,x,y,width,height);
394 ZDrawRectangle(TkGate.D,TkGate.W,TkGate.toolGC,lx,ly,lwidth,lheight);
395 }
396
397 /*****************************************************************************
398 *
399 * Move selected objects in response to mouse movement.
400 *
401 * Parameters:
402 *
403 * es Editstate in which to perform operation
404 *
405 * Move selected object(s) to the new cursor position. The effect is mode
406 * dependent and may result in moving either an object, a selection, a rubber
407 * band line/box depending on context.
408 *
409 *****************************************************************************/
EditState_moveobject(EditState * es)410 void EditState_moveobject(EditState *es)
411 {
412 if (GModuleDef_isDataProtected(TkGate.circuit->es->env)) {
413 message(0,msgLookup("err.protdata"));
414 return;
415 }
416
417 if (TkGate.circuit->labelsel->net) {
418 GrabbedLabel_draw(TkGate.ed->lx,TkGate.ed->ly);
419 GrabbedLabel_draw(TkGate.ed->tx,TkGate.ed->ty);
420 return;
421 }
422
423 switch (EditState_getMode()) {
424 case MODE_MOVENULL :
425 break;
426 case MODE_MOVESEL :
427 if (TkGate.state & ControlMask) {
428 EditState_setMode( MODE_MOVENULL);
429 wm_SetCursor(ARROWCURSOR);
430 return;
431 }
432
433 ob_suggest_name("MultiMove");
434 sel_draw(es);
435 sel_move(es,TkGate.ed->tx-TkGate.ed->lx,TkGate.ed->ty-TkGate.ed->ly);
436 sel_draw(es);
437 break;
438 case MODE_MOVE :
439 mark_unpost();
440
441 if (TkGate.circuit->wnsel) {
442 if (!TkGate.circuit->wsel)
443 printf("Huh? wsel is NULL\n");
444 ob_suggest_name("MoveWire");
445 GWire_draw(TkGate.circuit->wsel);
446 wire_move(TkGate.circuit->wnsel,
447 TkGate.ed->tx-TkGate.ed->lx,TkGate.ed->ty-TkGate.ed->ly,
448 TkGate.circuit->wnsel->stype);
449 GWire_draw(TkGate.circuit->wsel);
450 } else {
451 if (TkGate.circuit->select && TkGate.circuit->select->typeinfo->Flags.special_move) {
452 if (!TkGate.circuit->select->anchored) {
453 sel_draw(es);
454 ob_suggest_name("MoveGate");
455 if (es->env->m_isSpecial) SetModified(MF_BEGINSPEC);
456 gate_move(TkGate.circuit->select,TkGate.ed->tx-TkGate.ed->lx,TkGate.ed->ty-TkGate.ed->ly);
457 if (es->env->m_isSpecial) SetModified(MF_ENDSPEC);
458 sel_draw(es);
459 } else
460 message(0,msgLookup("err.gatanchor")); /* "Gate is anchored and can not be moved." */
461
462 } else if (TkGate.circuit->mg_selection) {
463 if (!TkGate.circuit->mg_selection->s_hasAnchored) {
464 sel_draw(es);
465 ob_suggest_name("MoveGate");
466 sel_move(es,TkGate.ed->tx-TkGate.ed->lx,TkGate.ed->ty-TkGate.ed->ly);
467 sel_draw(es);
468 } else
469 message(0,msgLookup("err.gatanchor")); /* "Gate is anchored and can not be moved." */
470 }
471 }
472 if (!TkGate.circuit->select && !TkGate.circuit->wnsel && !editstate_isInterfaceMode()) {
473 int dx = TkGate.ed->tx-TkGate.ed->sx;
474 int dy = TkGate.ed->ty-TkGate.ed->sy;
475
476 if (dx*dx+dy*dy > SELMODETHRESH) {
477 EditState_setMode( MODE_MAKESEL);
478 wm_SetCursor(ARROWCURSOR);
479 setRubberBox(es);
480 }
481 }
482
483 mark_post();
484 break;
485 case MODE_MAKESEL :
486 moveRubberBox(es);
487 break;
488 case MODE_REPLICATE :
489 if (TkGate.circuit->select) {
490 gate_hashrepline(es,TkGate.ed->lx,TkGate.ed->ly);
491 gate_hashrepline(es,TkGate.ed->tx,TkGate.ed->ty);
492 moverubberband(es);
493 }
494 break;
495 }
496 }
497
498 /*****************************************************************************
499 *
500 * Respond to a wire being dropped on a gate. Special things happen when the
501 * gate is a joint or a block.
502 *
503 *****************************************************************************/
DropWireOnGate(EditState * es,GCElement * g)504 void DropWireOnGate(EditState *es,GCElement *g)
505 {
506 extern int blockDropConnect;
507 GWire *w;
508 int p;
509
510 w = TkGate.circuit->wnsel->end;
511
512 /*
513 * Wire is already connected to something.
514 */
515 if (w->gate) return;
516
517 GWire_draw(TkGate.circuit->wsel->driver);
518
519
520 wire_deletezeronodes(TkGate.circuit->wnsel->in ? w->driver->nodes : w->nodes);
521 ob_touch(TkGate.circuit);
522 TkGate.circuit->wnsel = w->nodes;
523
524 switch (g->typeinfo->code) {
525 case GC_JOINT :
526 joint_connect(g,TkGate.circuit->wnsel);
527 GWire_draw(TkGate.circuit->wsel->driver);
528 wire_finalizeNet(TkGate.circuit->wsel);
529 break;
530 case GC_BLOCK :
531 if (blockDropConnect) {
532 if (block_isIntfProtected(g)) {
533 message(0,msgLookup("err.protintf"),g->u.block.moduleName);
534 } else {
535 p = block_connect(g,TkGate.circuit->wnsel,IN);
536 if (p >= 0) {
537 GWire_snap(TkGate.circuit->wsel->driver);
538 GWire_draw(TkGate.circuit->wsel->driver);
539 DrawPinIOMark(TkGate.circuit->wnsel->end,p,TkGate.circuit->wnsel->in ? IN : OUT,IODT_PLAIN);
540 block_setPortName(g,TkGate.circuit->wnsel->end,es);
541 wire_finalizeNet(TkGate.circuit->wnsel->end);
542 }
543 break;
544 }
545 }
546 /* fall through */
547 default :
548 GWire_snap(w->driver);
549 wire_finalizeNet(w);
550 GWire_draw(w->driver);
551 break;
552 }
553 }
554
555 /*****************************************************************************
556 *
557 * Hit an object at a location and return either the gate in g, or the wire
558 * in w and n. gbais is an amount to bias toward selecting a gate.
559 *
560 *****************************************************************************/
hit_choose(int x,int y,int gbias,GCElement ** g,GWire ** w,GWireNode ** n)561 static void hit_choose(int x,int y,int gbias,GCElement **g,GWire **w,GWireNode **n)
562 {
563 int dg, dw, dn;
564
565 dg = dw = dn = NOHIT;
566
567 if (g && *g) {
568 int dx = (*g)->xpos - x;
569 int dy = (*g)->ypos - y;
570 dg = dx*dx+dy*dy - gbias;
571 }
572
573 if (w && *w) {
574 int dx = (*w)->nodes->x - x;
575 int dy = (*w)->nodes->y - y;
576 dw = dx*dx+dy*dy;
577 }
578
579 if (n && *n) {
580 GWire *e1,*e2;
581
582 int dx = (*n)->x - x;
583 int dy = (*n)->y - y;
584
585 e1 = wirenode_driver(*n);
586 e2 = wirenode_drivee(*n);
587
588 if (g && (e1->gate == *g || e2->gate == *g))
589 dn = NOHIT;
590 else {
591 switch ((*n)->stype) {
592 case FULL :
593 dn = dx*dx + dy*dy;
594 break;
595 case VERTICAL :
596 dn = dx*dx;
597 break;
598 case HORIZONTAL :
599 dn = dy*dy;
600 break;
601 default :
602 logError(ERL_WARN,"Unknown stype %d in hit_all.",(*n)->stype);
603 break;
604 }
605 }
606 }
607
608 if (dn <= dw && dn <= dg) {
609 if (w) *w = 0;
610 if (g) *g = 0;
611 } else if (dw <= dn && dw <= dg) {
612 if (n) *n = 0;
613 if (g) *g = 0;
614 } else {
615 if (n) *n = 0;
616 if (w) *w = 0;
617 }
618 }
619
620 /*****************************************************************************
621 *
622 * Drop a wire and determine what to do from context.
623 *
624 *****************************************************************************/
DropWire(EditState * es)625 void DropWire(EditState *es)
626 {
627 GWire *csel = 0;
628 GWireNode *nsel = 0;
629 GCElement *g;
630 GWire *kw1,*kw2;
631
632 if (!TkGate.circuit->wsel) {
633 printf("Huh? wsel is NULL\n");
634 return;
635 }
636
637 net_unselect(1);
638
639 if (TkGate.circuit->wnsel->end) {
640 g = gate_hit(es->env,TkGate.ed->tx,TkGate.ed->ty);
641 if (TkGate.circuit->wnsel->stype == FULL) {
642 nsel = wire_hit_other(TkGate.circuit->wnsel->end,es->env->m_wires);
643 csel = wire_endhit(TkGate.circuit->wnsel->end,es->env->m_wires);
644 }
645
646 hit_choose(TkGate.ed->tx,TkGate.ed->ty,9,&g,&csel,&nsel);
647
648 if (g) {
649 DropWireOnGate(es,g);
650 } else if (csel) {
651 GWire *kw1 = wire_sigroot(TkGate.circuit->wnsel->end);
652 GWire *kw2 = wire_sigroot(csel);
653 GWire *rw;
654
655 if (!net_connectOK(kw1->net,kw2->net,0)) return;
656
657 GNet_draw(kw1->net);
658 GNet_draw(kw2->net);
659 rw = wire_connect(es->env,TkGate.circuit->wnsel->end,csel);
660 GNet_draw(rw->net);
661 ob_touch(TkGate.circuit); /* JPH 121703 */
662 TkGate.circuit->wsel = rw;
663 } else if (nsel) {
664 GCElement *tap_g;
665 GNet *n1,*n2;
666
667 kw1 = wire_sigroot(TkGate.circuit->wnsel->end);
668 kw2 = wire_sigroot(wirenode_driver(nsel));
669
670 n1 = kw1->net;
671 n2 = kw2->net;
672
673 if (!net_connectOK(n1,n2,1)) return;
674 if (nsel->stype != VERTICAL && nsel->stype != HORIZONTAL && n1->n_nbits != n2->n_nbits) {
675 message(0,msgLookup("err.badconbitw")); /* Connection refused because bit widths do not match. */
676 return;
677 }
678
679 GNet_draw(n1);
680 GNet_draw(n2);
681
682 net_incref(n1);
683 net_incref(n2);
684
685 tap_g = join_wires(TkGate.circuit->wnsel->end,nsel,es);
686
687 wire_finalizeNet(TkGate.circuit->wsel);
688
689 if (n1->n_refs > 1) {
690 wire_finalizeNet(n1->n_driver);
691 GNet_draw(n1);
692 }
693 if (n2->n_refs > 1) {
694 wire_finalizeNet(n2->n_driver);
695 GNet_draw(n2);
696 }
697
698 net_decref(n1);
699 net_decref(n2);
700
701 if (tap_g)
702 gate_draw(tap_g,GD_NOWIRE);
703 }
704 }
705
706 if (!(TkGate.state & Mod1Mask))
707 DoSnap(TkGate.circuit->wsel);
708 wire_finalizeNet(TkGate.circuit->wsel);
709
710 if (EditState_getMode() == MODE_MOVE)
711 net_select(TkGate.circuit->wsel->net,1);
712 }
713
714 /*****************************************************************************
715 *
716 * Drop an object in response to a mouse button release
717 *
718 * Parameters:
719 * es Edit state in which to perform operation
720 *
721 *
722 *****************************************************************************/
EditState_dropobject(EditState * es)723 void EditState_dropobject(EditState *es)
724 {
725 DoTcl("tkg_unpostNetDelay");
726
727 if (TkGate.circuit->labelsel->net) {
728 GrabbedLabel_draw(TkGate.ed->lx,TkGate.ed->ly);
729 GNet_labelClosest(TkGate.circuit->labelsel->net,TkGate.ed->tx,TkGate.ed->ty);
730 GrabbedLabel_unset();
731 return;
732 }
733
734 switch (EditState_getMode()) {
735 case MODE_MOVENULL :
736 EditState_setMode( MODE_MOVE);
737 break;
738 case MODE_CUT :
739 if (TkGate.startrekp)
740 wm_SetCursor(TREKDELETEUP);
741 else
742 wm_SetCursor(OPENCUTTERS);
743 break;
744 case MODE_INVERT :
745 wm_SetCursor(INVERTUPCURSOR);
746 break;
747 case MODE_MOVESEL :
748 sel_dropFixup(es);
749 break;
750 case MODE_MOVE :
751 if (!modifyOK(es,0x2)) {
752 if (TkGate.batp) {
753 SetBatCursor();
754 } else
755 wm_SetCursor(ARROWCURSOR);
756 return;
757 }
758
759 if (TkGate.circuit->wnsel) {
760 DropWire(es);
761 } else
762 if (TkGate.circuit->select) {
763 if (!(TkGate.state & Mod1Mask))
764 wire_snapgate(TkGate.circuit->select,1);
765 }
766 if (TkGate.batp) {
767 SetBatCursor();
768 } else
769 wm_SetCursor(ARROWCURSOR);
770
771 mark_post();
772
773 break;
774 case MODE_DELETE :
775 if (TkGate.startrekp)
776 wm_SetCursor(TREKDELETEUP);
777 else
778 wm_SetCursor(DELETEUPCURSOR);
779 break;
780 case MODE_SETSIZE :
781 if (!modifyOK(es,0x2)) return;
782 ob_suggest_name("Resize");
783 setwiresize(es);
784 break;
785 case MODE_REPLICATE :
786 if (!modifyOK(es,0x2)) return;
787 ob_append_frame("Replicate");
788 if (TkGate.circuit->select)
789 gate_doReplication(es);
790 setEditMode(es,MODE_MOVE);
791 ob_end_frame();
792 break;
793 case MODE_MAKESEL :
794 if (!modifyOK(es,0x2)) return;
795 EditState_setMode( MODE_MOVE);
796 setRubberBox(es);
797 if (sel_select(es))
798 EditState_setMode( MODE_MOVESEL);
799 break;
800 default :
801 break;
802 }
803 sel_updateMenuState();
804 }
805
806 /*****************************************************************************
807 *
808 * Unselect everything
809 *
810 *****************************************************************************/
EditState_unselectAll(EditState * es)811 void EditState_unselectAll(EditState *es)
812 {
813 ClearErrorMark();
814
815 mark_unpost();
816
817 if (TkGate.circuit->select) {
818 EditState_unselectGate(es);
819 }
820 sel_clear(es,1);
821 net_unselect(1);
822 }
823
824 /*****************************************************************************
825 *
826 * Sets initial wires for an object
827 *
828 *****************************************************************************/
initial_wires(GModuleDef * env,GCElement * select,int invertp)829 void initial_wires(GModuleDef *env,GCElement *select,int invertp)
830 {
831 int i,j;
832 int N = GCElement_numPads(select);
833
834 for (i = 0;i < N;i++)
835 for (j = 0;j < GCElement_getPadNum(select,i);j++)
836 wire_addToGate(select,i,env,(select->typeinfo->Pad[i].iotype == OUT && invertp));
837
838 }
839
840 /*****************************************************************************
841 *
842 * Create a string with formatted information about a net for debugging
843 * purposes.
844 *
845 *****************************************************************************/
PrintNet(char * p,GNet * net)846 char *PrintNet(char *p,GNet *net)
847 {
848 char *name;
849
850 if (!net) {
851 p += sprintf(p,"NetID: *null*\n");
852 return p;
853 }
854
855 name = net->n_signame ? net->n_signame : "*none*";
856 p += sprintf(p,"NetID: 0x%p Name: %s\n",(void*)net,name);
857 p += sprintf(p," Bits: %d Refs: %d",net->n_nbits,net->n_refs);
858 if (net->n_finalized)
859 p += sprintf(p," Finalized: ok\n");
860 else
861 p += sprintf(p," Finalized: %d/%d\n",net->n_wnum,net->n_gnum);
862
863 p += sprintf(p," Flags:");
864 if (net->n_mark) p += sprintf(p," mark");
865 if (net->n_ionet) p += sprintf(p," ionet");
866 if (GNet_getShowName(net)) p += sprintf(p," show_name");
867 p += sprintf(p,"\n");
868
869 return p;
870 }
871
872 /*****************************************************************************
873 *
874 * Create a string with formatted information about a wire end for debugging
875 * purposes.
876 *
877 *****************************************************************************/
PrintWireEnd(char * p,GWire * w)878 char *PrintWireEnd(char *p,GWire *w)
879 {
880 GCElement *g = w->gate;
881
882 p += sprintf(p,"Port: %s (0x%p) {%d}\n",w->name ? w->name : "*none*",(void*)w,w->nidx);
883
884 if (!g)
885 p += sprintf(p,"Gate: *none*\n");
886 else {
887
888 if (!g->typeinfo)
889 p += sprintf(p,"Gate: typeinfo is null\n");
890 else if (badaddr(g->typeinfo))
891 p += sprintf(p,"Gate: typeinfo is bad address\n");
892 else if (!g->typeinfo->vnames)
893 p += sprintf(p,"Gate: typeinfo name is null\n");
894 else {
895 int pos,n;
896
897 posongate(w,g,&pos,&n);
898 p += sprintf(p,"Gate: %s.%s[%d]\n",g->typeinfo->name,
899 g->typeinfo->Pad[pos].name,n);
900 if (GCElement_getType(g) == GC_BLOCK)
901 p += sprintf(p,"Offset: %d/%d\n",w->offset.num,w->offset.den);
902 }
903 }
904
905 p += sprintf(p,"Orient: %d\n",w->orient);
906 p += sprintf(p,"Wtype: %d\n",w->wtype);
907
908 if (w == (GWire*)wire_sigroot(w))
909 p += sprintf(p,"DType: root driver\n");
910 else if (w == w->driver)
911 p += sprintf(p,"DType: segment driver\n");
912 else
913 p += sprintf(p,"DType: segment drivee\n");
914
915 return p;
916 }
917
918 /*****************************************************************************
919 *
920 * Create a string with formatted information about a wire node for debugging
921 * purposes.
922 *
923 *****************************************************************************/
PrintWireNode(char * p,GWireNode * n)924 char *PrintWireNode(char *p,GWireNode *n)
925 {
926 p += sprintf(p," Pos: (%d, %d) [ss:%d il:%d/%d off:%d] %s\n",n->x,n->y,
927 n->showSize,n->isLabeled,n->labelSide,n->offset,n->end ? "*end*" : "");
928
929 if (n->in && n->in->out != n)
930 p += sprintf(p," n->in is wrong\n");
931 if (n->out && n->out->in != n)
932 p += sprintf(p," n->out is wrong\n");
933 if (n->end && n->in && n->out)
934 p += sprintf(p," n->end is wrong\n");
935
936 return p;
937 }
938
939 /*****************************************************************************
940 *
941 * Handle mouse down action while in debug mode (the wrench tool).
942 *
943 *****************************************************************************/
DoDebug(EditState * es)944 void DoDebug(EditState *es)
945 {
946 GWireNode *n;
947 GWire *W = 0;
948 GCElement *g;
949 GGateInfo *gi;
950 char msg[1024*10];
951 char *p = msg;
952
953 *msg = 0;
954
955 if ((g = gate_hit(es->env,TkGate.ed->tx,TkGate.ed->ty))) {
956 int N = GCElement_numPads(g);
957 GWire *w;
958 int i;
959
960 gi = g->typeinfo;
961
962 p += sprintf(p,"Type: %s\n",gi->name);
963 p += sprintf(p,"Name: %s (%p)\n",g->ename ? g->ename : "*none*",g);
964 if (GCElement_getType(g) == GC_BLOCK) {
965 p += sprintf(p,"Size: %dx%d\n",g->u.block.gwidth,g->u.block.gheight);
966 }
967 p += sprintf(p,"Orient: %d\n",g->orient);
968 p += sprintf(p,"Pads:\n");
969
970 for (i = 0;i < N;i++) {
971 p += sprintf(p," %s:",GCElement_getPadName(g,i));
972 for (w = g->wires[i];w;w = w->next) {
973 p += sprintf(p," ");
974 if (w->net->n_signame)
975 p += sprintf(p,"%s(0x%p) {%d}",w->net->n_signame,(void*)w->net,w->nidx);
976 else
977 p += sprintf(p,"0x%p {%d}",(void*)w->net,w->nidx);
978 if (w == (GWire*)wire_sigroot(w))
979 p += sprintf(p,"[r]");
980 else if (w == w->driver)
981 p += sprintf(p,"[d]");
982 else
983 p += sprintf(p,"[e]");
984 }
985 p += sprintf(p,"\n");
986 }
987 } else if ((n = wire_iohit(TkGate.ed->tx,TkGate.ed->ty,es->env->m_wires))) {
988 GNet *net;
989
990 while (n->in) n = n->in;
991
992 net = n->end->net;
993 p = PrintNet(p,net);
994 p = PrintWireEnd(p,n->end);
995 for (;n;n = n->out) {
996 p = PrintWireNode(p,n);
997 W = n->end;
998 }
999 p = PrintWireEnd(p,W);
1000 if (W->net != net) {
1001 p += sprintf(p,"####Warning other end on different net...\n");
1002 p = PrintNet(p,W->net);
1003 }
1004 p += sprintf(p,"\n");
1005 }
1006
1007 if (*msg)
1008 DoTcl("tkg_debugMessage {%s}",msg);
1009 }
1010
1011 /*****************************************************************************
1012 *
1013 * Perform main edit window actions in response to a mouse press in Move mode.
1014 *
1015 * Parameters:
1016 * es Editstate in which to perform operation
1017 *
1018 *****************************************************************************/
EditState_selectobject_Move(EditState * es)1019 static int EditState_selectobject_Move(EditState *es)
1020 {
1021 /*
1022 * Check to see what gate we may have clicked on.
1023 */
1024 GCElement *g = gate_hit(es->env,TkGate.ed->tx,TkGate.ed->ty);
1025 GWireNode *n;
1026 GWire *w;
1027
1028 if (g && GCElement_getType(g) == GC_BLOCK) {
1029 Block_HitComponent(g,TkGate.ed->tx,TkGate.ed->ty);
1030 }
1031
1032 if (EditState_getMode() == MODE_MOVESEL) {
1033 /*
1034 * We already have a set of selected gates (mode MOVESEL). If the gate we
1035 * clicked on is already in the selected set, and we have the control key
1036 * pressed, unselect it.
1037 */
1038 if (g && sel_isSelGate(g)) {
1039 if ((TkGate.state & ControlMask)) {
1040 gate_draw(g,GD_NOWIRE);
1041 sel_unselectGate(es,g);
1042 gate_draw(g,GD_NOWIRE);
1043 }
1044 return 0;
1045 }
1046 EditState_setMode( MODE_MOVE);
1047 }
1048
1049 /*
1050 * If the control key is not pressed, unselect all gates.
1051 */
1052 if (!(TkGate.state & ControlMask))
1053 sel_clear(es,1);
1054
1055 #if TOUCH_XGATE_ED
1056 ob_touch(TkGate.ed);
1057 #endif
1058 TkGate.ed->sx = TkGate.ed->tx;
1059 TkGate.ed->sy = TkGate.ed->ty;
1060
1061 if (GModuleDef_grabLabel(es->env,TkGate.ed->tx,TkGate.ed->ty,TkGate.circuit->labelsel)) {
1062 return 0;
1063 }
1064
1065 if (g && GCElement_getType(g) == GC_TAP) {
1066 /*
1067 * Favor tap selection over wire selection.
1068 */
1069 } else if ((n = wire_hit(TkGate.ed->tx,TkGate.ed->ty,es->env->m_wires))) {
1070 /*
1071 * Standard wire hit - wire can be moved
1072 */
1073 if (!editstate_isInterfaceMode()) {
1074 ob_touch(TkGate.circuit);
1075 TkGate.circuit->wnsel = n;
1076
1077 if (((!TkGate.circuit->wnsel->in)
1078 || (!TkGate.circuit->wnsel->out)) && (TkGate.circuit->wnsel->stype == FULL) ) {
1079 /*
1080 * We have a connectable wire end
1081 */
1082 TkGate.batc = 0;
1083 wm_SetCursor(IRON);
1084 }
1085
1086 TkGate.circuit->wsel = wirenode_driver(TkGate.circuit->wnsel);
1087 EditState_unselectGate(es);
1088 }
1089 } else if ((n = wire_iohit(TkGate.ed->tx,TkGate.ed->ty,es->env->m_wires))) {
1090
1091 if (!editstate_isInterfaceMode()) {
1092 /*
1093 * I/O port wire hit - wire can not be moved unless we create new segments
1094 */
1095 if (GModuleDef_isDataProtected(TkGate.circuit->es->env)) {
1096 message(0,msgLookup("err.protdata"));
1097 ob_touch(TkGate.circuit);
1098 TkGate.circuit->wsel = wirenode_driver(TkGate.circuit->wnsel);
1099 EditState_unselectGate(es);
1100 net_select(TkGate.circuit->wsel->net,1);
1101
1102 return 0;
1103 }
1104
1105 /*
1106 * If button1 is pressed and we are clicking on a segment with an anchored end, we may
1107 * need to create a corner to grab on to. Otherwise, assume we are right clicking on the
1108 * wire segment to change wire/net/segment properties.
1109 */
1110 if (TkGate.button == 1) {
1111 if ((n = wire_makecorner(n,TkGate.ed->tx,TkGate.ed->ty))) {
1112 w = wirenode_driver(n);
1113 }
1114 } else {
1115 if (n) {
1116 w = wirenode_driver(n);
1117 }
1118 }
1119
1120 if (n && w) {
1121 ob_touch(TkGate.circuit);
1122 TkGate.circuit->wnsel = n;
1123 TkGate.circuit->wsel = w;
1124 }
1125
1126 EditState_unselectGate(es);
1127 }
1128 }
1129
1130 if (TkGate.circuit->wnsel) {
1131 sel_clear(es,1);
1132 }
1133
1134 /*
1135 * If we selected a wire, unselect any gate selection.
1136 */
1137 if (!TkGate.circuit->wnsel) {
1138 if (g && g->selected && (TkGate.state & ControlMask)) {
1139 gate_draw(g,GD_NOWIRE);
1140 sel_unselectGate(es,g);
1141 gate_draw(g,GD_NOWIRE);
1142 } else {
1143 EditState_selectGate(es,TkGate.ed->tx,TkGate.ed->ty);
1144 }
1145 }
1146
1147 /*
1148 * If there is no selection, we are setting the mark and will show the current
1149 * direction while the mouse button is held down.
1150 */
1151 if (!Circuit_isSelection(TkGate.circuit) && ! editstate_isInterfaceMode()) {
1152 TkGate.batc = 0;
1153 switch (EditState_getRotation()) {
1154 case ROT0 :
1155 wm_SetCursor(ARROW0);
1156 break;
1157 case ROT90 :
1158 wm_SetCursor(ARROW90);
1159 break;
1160 case ROT180 :
1161 wm_SetCursor(ARROW180);
1162 break;
1163 case ROT270 :
1164 wm_SetCursor(ARROW270);
1165 break;
1166 }
1167 }
1168
1169
1170 /*
1171 * If we selected a wire or a joint, mark the appropriate net as selected.
1172 */
1173 if (TkGate.circuit->wsel) {
1174 net_select(TkGate.circuit->wsel->net,1);
1175 } else if (TkGate.circuit->select && TkGate.circuit->select->typeinfo->code == GC_JOINT) {
1176 GCElement *g = TkGate.circuit->select;
1177 int i;
1178 for (i = 0;i < 4;i++)
1179 if (g->wires[i]) {
1180 net_select(g->wires[i]->net,1);
1181
1182 return 0;
1183 }
1184 } else
1185 net_unselect(1);
1186
1187 /*
1188 * If the control key is pressed, start a rubber-band selection box.
1189 */
1190 if (TkGate.state & ControlMask) {
1191 EditState_setMode( MODE_MAKESEL);
1192 wm_SetCursor(ARROWCURSOR);
1193 setRubberBox(es);
1194 }
1195
1196 return 1;
1197 }
1198
1199 /*****************************************************************************
1200 *
1201 * Perform main edit window actions in response to a mouse press in Replicate mode.
1202 *
1203 * Parameters:
1204 * es Editstate in which to perform operation
1205 *
1206 *****************************************************************************/
EditState_selectobject_Replicate(EditState * es)1207 static int EditState_selectobject_Replicate(EditState *es)
1208 {
1209 if (!modifyOK(es,0)) return 0;
1210
1211 ob_append_frame("Replicate");
1212 EditState_selectGate(es,TkGate.ed->tx,TkGate.ed->ty);
1213 if (TkGate.circuit->select) {
1214 #if TOUCH_XGATE_ED
1215 ob_touch(TkGate.ed);
1216 #endif
1217 TkGate.ed->tx = TkGate.circuit->select->xpos;
1218 TkGate.ed->ty = TkGate.circuit->select->ypos;
1219 setrubberband(es);
1220 }
1221 ob_end_frame();
1222
1223 return 1;
1224 }
1225
1226 /*****************************************************************************
1227 *
1228 * Perform main edit window actions in response to a mouse press in Cut mode.
1229 *
1230 * Parameters:
1231 * es Editstate in which to perform operation
1232 *
1233 *****************************************************************************/
EditState_selectobject_Cut(EditState * es)1234 static int EditState_selectobject_Cut(EditState *es)
1235 {
1236 if (!modifyOK(es,0x2)) return 0;
1237
1238 if (TkGate.startrekp)
1239 wm_SetCursor(TREKDELETEDN);
1240 else
1241 wm_SetCursor(CLOSEDCUTTERS);
1242 if ((TkGate.circuit->wnsel = wire_iohit(TkGate.ed->tx,TkGate.ed->ty,es->env->m_wires))) {
1243 ob_suggest_name("Cut");
1244 SetModified(MF_NET);
1245 net_unselect(1);
1246 wire_cut(TkGate.ed->tx,TkGate.ed->ty,TkGate.circuit->wnsel,es->env);
1247 }
1248 ob_touch(TkGate.circuit);
1249 TkGate.circuit->wsel = NULL;
1250 TkGate.circuit->wnsel = NULL;
1251
1252 return 1;
1253 }
1254
1255 /*****************************************************************************
1256 *
1257 * Perform main edit window actions in response to a mouse press in Invert mode.
1258 *
1259 * Parameters:
1260 * es Editstate in which to perform operation
1261 *
1262 *****************************************************************************/
EditState_selectobject_Invert(EditState * es)1263 static int EditState_selectobject_Invert(EditState *es)
1264 {
1265 if (!modifyOK(es,0)) return 0;
1266 wm_SetCursor(INVERTDNCURSOR);
1267
1268 ob_touch(TkGate.circuit);
1269 if ((TkGate.circuit->wnsel = wire_iohit(TkGate.ed->tx,TkGate.ed->ty,es->env->m_wires)))
1270 if (TkGate.circuit->wnsel->end && TkGate.circuit->wnsel->end->gate) {
1271 if (!TkGate.circuit->wnsel->end->gate->typeinfo->Flags.NoInvert) {
1272 ob_suggest_name("Invert");
1273 GWire_draw(TkGate.circuit->wnsel->end->driver);
1274 ob_touch(TkGate.circuit->wnsel->end);
1275 TkGate.circuit->wnsel->end->invert = !TkGate.circuit->wnsel->end->invert;
1276 GWire_draw(TkGate.circuit->wnsel->end->driver);
1277 SetModified(MF_NET);
1278 } else
1279 message(0,msgLookup("err.noinvgate"));
1280 }
1281 TkGate.circuit->wnsel = NULL;
1282
1283 return 1;
1284 }
1285
1286 /*****************************************************************************
1287 *
1288 * Perform main edit window actions in response to a mouse press in Delete mode.
1289 *
1290 * Parameters:
1291 * es Editstate in which to perform operation
1292 *
1293 *****************************************************************************/
EditState_selectobject_Delete(EditState * es)1294 static int EditState_selectobject_Delete(EditState *es)
1295 {
1296 if (!modifyOK(es,0)) return 0;
1297 if (TkGate.startrekp)
1298 wm_SetCursor(TREKDELETEDN);
1299 else
1300 wm_SetCursor(DELETEDNCURSOR);
1301 EditState_unselectGate(es);
1302 EditState_selectGate(es,TkGate.ed->tx,TkGate.ed->ty);
1303 if (TkGate.circuit->select) {
1304 ob_suggest_name("Delete");
1305 sel_delete(es);
1306 }
1307 ob_touch(TkGate.circuit);
1308 TkGate.circuit->last = TkGate.circuit->select = NULL;
1309
1310 return 1;
1311 }
1312
1313 /*****************************************************************************
1314 *
1315 * Perform main edit window actions in response to a mouse press.
1316 *
1317 * Parameters:
1318 * es Editstate in which to perform operation
1319 *
1320 * Select an object at the current mouse position. The selected object
1321 * could be a gate or a wire.
1322 *
1323 *****************************************************************************/
EditState_selectobject(EditState * es)1324 void EditState_selectobject(EditState *es)
1325 {
1326 switch (EditState_getMode()) {
1327 case MODE_MOVENULL :
1328 break;
1329 case MODE_MOVESEL :
1330 case MODE_MOVE :
1331 EditState_selectobject_Move(es);
1332 break;
1333 case MODE_DEBUG :
1334 DoDebug(es);
1335 break;
1336 case MODE_REPLICATE :
1337 EditState_selectobject_Replicate(es);
1338 break;
1339 case MODE_CUT :
1340 EditState_selectobject_Cut(es);
1341 break;
1342 case MODE_INVERT :
1343 EditState_selectobject_Invert(es);
1344 break;
1345 case MODE_DELETE :
1346 EditState_selectobject_Delete(es);
1347 break;
1348 default :
1349 break;
1350 }
1351
1352 if (TkGate.circuit->wsel && tkgate_currentMode() == MM_ANALYZE)
1353 cpath_showNetDelay(TkGate.circuit->wsel->net);
1354 }
1355
1356 /*****************************************************************************
1357 *
1358 * Set the cursor for the current mode.
1359 *
1360 *****************************************************************************/
setEditCursor(int mode)1361 void setEditCursor(int mode)
1362 {
1363 switch (mode) {
1364 case MODE_MOVE :
1365 default :
1366 if (TkGate.batp) {
1367 SetBatCursor();
1368 } else
1369 wm_SetCursor(ARROWCURSOR);
1370 break;
1371 case MODE_INVERT :
1372 wm_SetCursor(INVERTUPCURSOR);
1373 break;
1374 case MODE_CUT :
1375 if (TkGate.startrekp)
1376 wm_SetCursor(TREKDELETEUP);
1377 else
1378 wm_SetCursor(OPENCUTTERS);
1379 break;
1380 case MODE_SCROLL :
1381 wm_SetCursor(SCROLLCURSOR);
1382 break;
1383 case MODE_DELETE :
1384 if (TkGate.startrekp)
1385 wm_SetCursor(TREKDELETEUP);
1386 else
1387 wm_SetCursor(DELETEUPCURSOR);
1388 break;
1389 case MODE_DEBUG :
1390 wm_SetCursor(WRENCHCURSOR);
1391 break;
1392 case MODE_SETSIZE :
1393 wm_SetCursor(SIZECURSOR);
1394 break;
1395 case MODE_REPLICATE :
1396 wm_SetCursor(REPCURSOR);
1397 break;
1398 }
1399
1400 }
1401
1402 /*****************************************************************************
1403 *
1404 * Set the edit mode.
1405 *
1406 *****************************************************************************/
setEditMode(EditState * es,int mode)1407 void setEditMode(EditState *es,int mode)
1408 {
1409 int iomodep;
1410 static int lastmode = 0;
1411
1412 ob_begin_frame("-Unselect");
1413
1414 iomodep = 0;
1415 switch (EditState_getMode()) {
1416 case MODE_MOVENULL :
1417 case MODE_MOVE :
1418 lastmode = MODE_MOVE;
1419 break;
1420 case MODE_INVERT :
1421 lastmode = EditState_getMode();
1422 break;
1423 case MODE_CUT :
1424 lastmode = EditState_getMode();
1425 break;
1426 case MODE_SCROLL :
1427 lastmode = EditState_getMode();
1428 break;
1429 case MODE_DELETE :
1430 lastmode = EditState_getMode();
1431 break;
1432 case MODE_SETSIZE :
1433 lastmode = EditState_getMode();
1434 break;
1435 case MODE_DEBUG :
1436 lastmode = EditState_getMode();
1437 break;
1438 default :
1439 break;
1440 }
1441
1442 if (lastmode == MODE_MOVE && TkGate.batp) lastmode = -1;
1443
1444 if (mode == MODE_REPLICATE)
1445 DoTcl("set ::tkg_replicateOn 1");
1446 else
1447 DoTcl("set ::tkg_replicateOn 0");
1448
1449
1450 TkGate.batc = 0;
1451 EditState_setMode( mode);
1452 switch (mode) {
1453 case MODE_MOVE :
1454 TkGate.ed->mark_vis = 0;
1455 break;
1456 case MODE_INVERT :
1457 net_unselect(1);
1458 sel_clear(es,1);
1459 break;
1460 case MODE_CUT :
1461 net_unselect(1);
1462 sel_clear(es,1);
1463 break;
1464 case MODE_SCROLL :
1465 net_unselect(1);
1466 sel_clear(es,1);
1467 break;
1468 case MODE_DELETE :
1469 net_unselect(1);
1470 sel_clear(es,1);
1471 break;
1472 case MODE_DEBUG :
1473 net_unselect(1);
1474 break;
1475 case MODE_SETSIZE :
1476 net_unselect(1);
1477 sel_clear(es,1);
1478 break;
1479 case MODE_REPLICATE :
1480 net_unselect(1);
1481 break;
1482 default :
1483 net_unselect(1);
1484 break;
1485 }
1486
1487 setEditCursor(mode);
1488
1489 if (!iomodep) {
1490 mark_unpost();
1491 EditState_unselectGate(es);
1492 ob_touch(TkGate.circuit);
1493 TkGate.circuit->wnsel = NULL;
1494 TkGate.circuit->wsel = NULL;
1495 }
1496 ob_end_frame();
1497 }
1498
1499 /*****************************************************************************
1500 *
1501 * Write a message to the log file.
1502 *
1503 *****************************************************************************/
logError(int level,const char * fileName,int lineNum,const char * msg,...)1504 void logError(int level,const char *fileName,int lineNum,const char *msg,...)
1505 {
1506 FILE *f;
1507 struct passwd *pw;
1508 struct tm *tm;
1509 time_t clock[1];
1510 char buf[STRMAX],msgBuf[STRMAX],fname[STRMAX];
1511 /** @TODO to check the necessity */
1512 /* char *lstr = 0; */
1513
1514 static char *mon[] = {
1515 "Jan","Feb","Mar","Apr","May","Jun",
1516 "Jul","Aug","Sep","Oct","Nov","Dec"
1517 };
1518 va_list ap;
1519 const char *home = 0;
1520
1521 if (TkGate.tcl)
1522 home = Tcl_GetVar(TkGate.tcl,"tkg_gateHome",TCL_GLOBAL_ONLY);
1523 else
1524 home = "<tkgate-home>";
1525
1526 va_start(ap,msg);
1527 vsprintf(msgBuf,msg,ap);
1528 va_end(ap);
1529
1530 /** @TODO to check the necessity */
1531 /*
1532 switch (level) {
1533 case 0 : lstr = "Warning: "; break;
1534 case 1 : lstr = "Error: "; break;
1535 case 2 : lstr = "FATAL: "; break;
1536 default: lstr = "Unknown: "; break;
1537 }
1538 */
1539
1540 pw = getpwuid(getuid());
1541 time(clock);
1542 tm = localtime(clock);
1543 sprintf(buf,"<%s> %s [%s] (%d-%s-%02d %d:%02d) %s (%s, line %d)"
1544 ,TKGATE_FULL_VERSION
1545 ,pw->pw_name,GetSysType()
1546 ,tm->tm_mday,mon[tm->tm_mon],(tm->tm_year % 100),tm->tm_hour,tm->tm_min
1547 ,msgBuf,fileName,lineNum);
1548
1549 if (TkGate.errorLogFile) {
1550 sprintf(fname,"%s/%s",home,TkGate.errorLogFile);
1551 if ((f = fopen(fname,"a"))) {
1552 fprintf(f,"%s\n",buf);
1553 fclose(f);
1554 } else if ((f = fopen(TkGate.errorLogFile,"a"))) {
1555 fprintf(f,"%s\n",buf);
1556 fclose(f);
1557 }
1558 }
1559
1560 printf("tkgate: %s\n",buf);
1561 switch (level) {
1562 case 0 :
1563 if (TkGate.baderp)
1564 printf("Oh! Look what you almost did, Miles!\n");
1565 else if (TkGate.startrekp)
1566 printf("Captain! Romulan ship decloaking dead ahead!\n");
1567 break;
1568 case 1 :
1569 if (TkGate.baderp)
1570 printf("Oh! Look what you did, Miles!\n");
1571 else if (TkGate.startrekp)
1572 printf("We have engaged the Borg!\n");
1573 break;
1574 case 2 :
1575 panicSave(0);
1576 }
1577 }
1578
1579 /*****************************************************************************
1580 *
1581 *****************************************************************************/
UpdateModifiedIndicator()1582 void UpdateModifiedIndicator()
1583 {
1584 if (TkGate.tcl)
1585 Tcl_SetVar(TkGate.tcl,"tkg_modifiedFlag",
1586 binstr(TkGate.circuit->modified_flags),TCL_GLOBAL_ONLY);
1587 }
1588
1589 /*****************************************************************************
1590 *
1591 * Mark the circuit as modified. Two types of flags are set 'modified_flags'
1592 * and 'sync_flags'. The 'modified_flags' are used to indicate that there
1593 * are changes that have not been saved to the current save file. The
1594 * 'sync_flags' are used to indicate that there have been changes to the circuit
1595 * data that may require 'synching' with the tcl/tk interface. The sync flags
1596 * are cleared as soon as the tcl/tk interface has been updated. Different bits
1597 * in the 'sync_flags' indicate what has been changed.
1598 *
1599 *****************************************************************************/
SetModified(unsigned flags)1600 void SetModified(unsigned flags)
1601 {
1602 static int inSpecial = 0;
1603
1604 if (!(flags & MF_FORCE)) {
1605 if ((flags & MF_BEGINSPEC)) {
1606 inSpecial++;
1607 return;
1608 }
1609 if ((flags & MF_ENDSPEC)) {
1610 inSpecial--;
1611 return;
1612 }
1613
1614 if (inSpecial)
1615 flags |= MF_SYNCONLY;
1616 }
1617
1618 if ((flags & MF_SYNCONLY)) {
1619 TkGate.sync_flags |= flags;
1620 } else {
1621 if (TkGate.circuit->no_set_modify)
1622 return;
1623
1624 GSearchContext_clear(TkGate.circuit->search);
1625
1626 ob_touch(TkGate.circuit);
1627 TkGate.circuit->modified_flags |= flags;
1628 TkGate.sync_flags |= flags;
1629
1630 UpdateModifiedIndicator();
1631 }
1632 }
1633
1634 /*****************************************************************************
1635 *
1636 * Mark the circuit as unmodified. This is called after saving (or loading)
1637 * a file.
1638 *
1639 *****************************************************************************/
ClearModified()1640 void ClearModified()
1641 {
1642 ob_touch(TkGate.circuit);
1643 TkGate.circuit->modified_flags = 0;
1644 UpdateModifiedIndicator();
1645 }
1646
1647 /*****************************************************************************
1648 *
1649 * Clear the synchronization flags.
1650 *
1651 *****************************************************************************/
SynchronizeInterface()1652 void SynchronizeInterface()
1653 {
1654 if (!TkGate.tcl) return;
1655
1656
1657 /*
1658 * Debug printing of sync flags.
1659 */
1660 #if 0
1661 if (TkGate.sync_flags) {
1662 printf("SYNC:");
1663 if ((TkGate.sync_flags & MF_INTERFACE)) {
1664 printf(" interface");
1665 }
1666 if ((TkGate.sync_flags & MF_MODULE)) {
1667 printf(" module");
1668 }
1669 if ((TkGate.sync_flags & MF_GATE)) {
1670 printf(" gate");
1671 }
1672 if ((TkGate.sync_flags & MF_NET)) {
1673 printf(" net");
1674 }
1675 printf("\n");
1676 }
1677 #endif
1678
1679 if ((TkGate.sync_flags & MF_MODULE)) {
1680 env_updateMTCircuit();
1681 }
1682
1683 if ((TkGate.sync_flags & MF_INTERFACE)) {
1684 int interface_updated = 0;
1685
1686 if (editstate_getInterfaceMode() == INTFMODE_SINGLE) {
1687 GModuleDef *M = 0;
1688 GCElement *g = 0;
1689 SHash *H = TkGate.circuit->mid_display->m_gates;
1690 HashElem *E;
1691
1692 for (E = Hash_first(H);E;E = Hash_next(H,E)) {
1693 GCElement *dg = HashElem_obj(E);
1694
1695 if (GCElement_isModule(dg)) {
1696 g = dg;
1697 if (!interface_updated)
1698 ob_begin_framef("ItfUpdate",FF_TRANSPARENT||FF_BACKGROUND);
1699 interface_updated = 1;
1700 M = env_findAdd(g->u.block.moduleName,0);
1701 }
1702 }
1703
1704 if (M && g) {
1705 #if 0
1706 printf("setInterface: M.g=%p g=%p\n",M->m_interface,g);
1707 #endif
1708 if (!interface_updated)
1709 ob_begin_framef("ItfUpdate",FF_TRANSPARENT||FF_BACKGROUND);
1710 interface_updated = 1;
1711 modint_setInterface(M,g);
1712 }
1713
1714 DoTcl("IPanel::loadCurrent");
1715
1716 if (interface_updated)
1717 ob_end_frame();
1718 }
1719 }
1720
1721 if (TkGate.sync_flags)
1722 Concat_updateAutos(TkGate.circuit->es->env,1);
1723
1724 TkGate.sync_flags = 0;
1725 }
1726
1727