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