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 Mon Dec 22 06:31:44 2008
19 ****************************************************************************/
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include "tkgate.h"
25 
26 #define DEBUG_NET 0
27 
28 static char *vtype_table[] = {
29   "wire", "tri", "wand", "triand", "wor", "trior", "tri0", "tri1", "trireg"
30 };
31 static int vtype_table_length = sizeof(vtype_table)/sizeof(vtype_table[0]);
32 
33 int ycIsKW(char*);
34 
35 /*****************************************************************************
36  *
37  * Get a string for the "display type" of a net.
38  *
39  * Parameters:
40  *      n		Net on which to lookup the dtype.
41  *
42  * Returns:		String representing the display type.
43  *
44  * Get the string for the net's "dtype".  The dtype is the type used to determine what
45  * type of symbol should be displayed next to the net in the list of nets.  It
46  * is not necessarily the actual verilog type.
47  *
48  *****************************************************************************/
GNet_getDTypeStr(GNet * n)49 const char *GNet_getDTypeStr(GNet *n)
50 {
51   /*
52    * Translate type code from HDL modules
53    */
54   switch (n->n_dtype) {
55   case NT_INPUT : return "input";
56   case NT_OUTPUT : return "output";
57   case NT_INOUT : return "inout";
58   case NT_REG : return "reg";
59   case NT_WIRE : return "wire";
60   }
61 
62   if (n->n_ionet) {
63     switch (n->n_ionet->typeinfo->code) {
64       case GC_LOGICIN : return "input";
65       case GC_LOGICOUT : return "output";
66       case GC_LOGICTRI : return "inout";
67     }
68   }
69 
70   return "wire";
71 }
72 
73 /*****************************************************************************
74  *
75  * Get a string for the "verilog type" of a net.
76  *
77  * Parameters:
78  *      n		Net on which to lookup the dtype.
79  *
80  * Returns:		String representing the verilog type.
81  *
82  *****************************************************************************/
GNet_getVType(GNet * n)83 const char *GNet_getVType(GNet *n)
84 {
85   int code = 0;
86 
87   if (n->n_ionet) {
88     switch (n->n_ionet->typeinfo->code) {
89     case GC_SWITCH :
90     case GC_DIP :
91       return "switch";
92     case GC_LOGICIN :
93     case GC_LOGICOUT :
94     case GC_LOGICTRI :
95       return "port";
96     }
97     return n->n_ionet->typeinfo->vnames;
98   }
99 
100   code = n->n_vtype;
101   if (code > vtype_table_length)
102     code = 0;
103 
104 
105   return vtype_table[code];
106 }
107 
GNet_setVType(GNet * n,const char * vtype)108 void GNet_setVType(GNet *n,const char *vtype)
109 {
110   int i;
111 
112   ob_touch(n);
113 
114   for (i = 0;i < vtype_table_length;i++)
115     if (strcmp(vtype_table[i],vtype) == 0) break;
116 
117   if (i >= vtype_table_length)
118     i = 0;
119 
120   n->n_vtype = i;
121   n->n_labelWidth = 0;
122 }
123 
124 
125 /*****************************************************************************
126  *
127  * Create a new net in a module with properties similar to another net
128  *
129  * Parameters:
130  *      name		Net name hint
131  *      rnet		Reference net on which to base the new net's properties
132  *      M		Module in which to create net
133  *
134  *****************************************************************************/
new_GNet_compatable(const char * name,GNet * rnet,GModuleDef * M)135 GNet *new_GNet_compatable(const char *name,GNet *rnet,GModuleDef *M)
136 {
137   GNet *net;
138   static unsigned generation = 0;
139 
140   net = (GNet*) ob_malloc(sizeof(GNet),"GNet");
141 
142   if (M) {
143     char buf[STRMAX];
144 
145     pickValidName(buf,name,"w",M->m_nets);
146     net->n_signame = ob_strdup(buf);
147     if (name) {
148       net->n_show_name = 1;
149     } else {
150       net->n_show_name = 0;
151     }
152   } else {
153     net->n_signame = 0;
154     net->n_show_name = 0;
155   }
156 
157   net->n_nbits = rnet ? rnet->n_nbits : 1;
158   net->n_dtype = NT_NONE;
159   net->n_vtype = NV_WIRE;
160   net->n_refs = 0;
161   net->n_mark = 0;
162   net->n_ionet = 0;
163   net->n_mod = M;
164   net->n_driver = 0;
165   net->n_next = 0;
166   net->n_finalized = 0;
167   net->n_labelWidth = 0;
168   net->n_generation = generation++;
169 
170   SHash_insert(M->m_nets,net->n_signame,net);
171 
172   if (M && TkGate.circuit->es && M == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE) {
173     DoTcl("NetList::add %s -hidden %d -bits %d -type %s",net->n_signame,!net->n_show_name,net->n_nbits,GNet_getDTypeStr(net));
174   }
175 
176 #if DEBUG_NET
177   printf("new_GNet() -> %x",net);
178   if (net->n_signame)
179     printf("  (%s)\n",net->n_signame);
180   else
181     printf("\n");
182 #endif
183 
184   return net;
185 }
186 
187 /*****************************************************************************
188  *
189  * Create a new net in a module
190  *
191  * Parameters:
192  *      name		Net name hint
193  *      M		Module in which to create net
194  *
195  *****************************************************************************/
new_GNet(const char * name,GModuleDef * M)196 GNet *new_GNet(const char *name,GModuleDef *M)
197 {
198   return new_GNet_compatable(name,0,M);
199 }
200 
201 /*****************************************************************************
202  *
203  * Update net in the net list box
204  *
205  * Parameters:
206  *      n		Target net for operation.
207  *
208  *****************************************************************************/
net_update(GNet * n)209 void net_update(GNet *n)
210 {
211   if (n->n_mod && TkGate.circuit->es && n->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE)
212     DoTcl("NetList::replace %s -hidden %d -bits %d -type %s",n->n_signame,!n->n_show_name,n->n_nbits,GNet_getDTypeStr(n));
213 }
214 
delete_GNet(GNet * net)215 void delete_GNet(GNet *net)
216 {
217   ob_touch(net);
218 #if DEBUG_NET
219   printf("GNet::Delete(%s) %x",net->n_signame ?: "",net);
220 #endif
221 
222   if (net->n_signame) {
223     SHash_remove(net->n_mod->m_nets,net->n_signame);
224     if (net->n_mod && TkGate.circuit->es && net->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE) {
225       DoTcl("NetList::del %s",net->n_signame);
226     }
227     ob_free(net->n_signame);
228 #if DEBUG_NET
229     printf(" [%d]",r);
230 #endif
231   }
232 #if DEBUG_NET
233   printf("\n");
234 #endif
235   ob_free(net);
236 }
237 
238 /*****************************************************************************
239  *
240  * Increment the reference count of a net.
241  *
242  * Parameters:
243  *      net		Target net for operation.
244  *
245  *****************************************************************************/
net_incref(GNet * net)246 void net_incref(GNet *net)
247 {
248   ob_touch(net);
249 #if 0
250   printf("net_incref(%s) [%d]\n",net->n_signame,net->n_refs+1);
251 #endif
252   net->n_refs++;
253 }
254 
255 /*
256  * Decrement the reference count of a net.  If the reference
257  * count goes to zero, the net is deleted.
258  */
net_decref(GNet * net)259 void net_decref(GNet *net)
260 {
261   ob_touch(net);
262 #if 0
263   printf("net_decref(%s) [%d]\n",net->n_signame,net->n_refs-1);
264 #endif
265   if (--net->n_refs <= 0)
266     delete_GNet(net);
267 }
268 
269 /*
270  * Select one of the nets 'a' or 'b'.  Typically used when joining two wires
271  * to determine which net name will be retained and which will be deleted.
272  */
net_pickOne(GNet * a,GNet * b,int decref_loser)273 GNet *net_pickOne(GNet *a,GNet *b,int decref_loser)
274 {
275   GNet *r = 0;	/* Net to return */
276   GNet *l = 0;	/* Losing net */
277 
278   if (!a)
279     r = b;
280   else if (!b)
281     r = a;
282   else if (a == b) {
283     r = a;
284     l = b;
285   } else if (a->n_ionet) {
286     r = a;
287     l = b;
288   } else if (b->n_ionet) {
289     r = b;
290     l = a;
291   } else if (a->n_show_name) {
292     r = a;
293     l = b;
294   } else if (b->n_show_name) {
295     r = b;
296     l = a;
297   } else if (a->n_generation < b->n_generation) {
298     r = a;
299     l = b;
300   } else {
301     r = b;
302     l = a;
303   }
304 
305   if (l && decref_loser) net_decref(l);
306 
307   return r;
308 }
309 
310 /*
311    Check to see if it is OK to connect wires from the
312    specified nets.  Return 1 if OK, return 0 and display
313    a status bar message if not OK.
314 */
net_connectOK(GNet * n1,GNet * n2,int isMidWire)315 int net_connectOK(GNet *n1,GNet *n2,int isMidWire)
316 {
317   if (n1 == n2) {
318     message(0,msgLookup("err.badconsame"));	/* Connection refused because wires are part of the same net. */
319     return 0;
320   }
321   if (n1->n_ionet && n2->n_ionet) {
322     message(0,msgLookup("err.badconptsp"));	/* Connection refused because both wires are module ports or supply. */
323     return 0;
324   }
325 
326   if (!isMidWire && n1->n_nbits != n2->n_nbits) {
327     message(0,msgLookup("err.badconbitw"));	/* Connection refused because bit widths do not match. */
328     return 0;
329   }
330 
331   return 1;
332 }
333 
334 /*
335   Unselect all nets.
336  */
net_unselect(int drawp)337 void net_unselect(int drawp)
338 {
339   if (TkGate.circuit->nsel) {
340     GNet *n = TkGate.circuit->nsel;
341     if (drawp) GNet_draw(n);
342     TkGate.circuit->nsel = 0;
343     if (drawp) GNet_draw(n);
344   }
345 }
346 
347 /*
348   Make 'n' the selected net.
349  */
net_select(GNet * n,int drawp)350 void net_select(GNet *n,int drawp)
351 {
352   if (TkGate.circuit->nsel == n) return;
353   net_unselect(drawp);
354 
355   if (!n) return;
356 
357   DoTcl("NetList::shadowselection %s",n->n_signame);
358 
359   ob_touch(TkGate.circuit);
360 
361   if (drawp) GNet_draw(n);
362   TkGate.circuit->nsel = n;
363   if (drawp) GNet_draw(n);
364 }
365 
366 
367 
368 /*
369    Redraw an entire net.
370 */
GNet_draw(GNet * net)371 void GNet_draw(GNet *net)
372 {
373   wire_drawnet(net->n_driver);
374 }
375 
net_setDType(GNet * net,int dtype)376 void net_setDType(GNet *net,int dtype)
377 {
378   if (net->n_dtype == dtype) return;
379 
380   ob_touch(net);
381   net->n_dtype = dtype;
382   net->n_labelWidth = 0;
383 
384   if (net->n_mod && TkGate.circuit->es && net->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE) {
385     DoTcl("NetList::replace %s -hidden %d -bits %d -type %s",net->n_signame,!net->n_show_name,net->n_nbits,GNet_getDTypeStr(net));
386   }
387 }
388 
net_setSize(GNet * net,int nbits)389 void net_setSize(GNet *net,int nbits)
390 {
391   if (net->n_nbits == nbits) return;
392 
393   ob_touch(net);
394   net->n_nbits = nbits;
395 
396   if (net->n_mod && TkGate.circuit->es && net->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE) {
397     DoTcl("NetList::replace %s -hidden %d -bits %d -type %s",net->n_signame,!net->n_show_name,net->n_nbits,GNet_getDTypeStr(net));
398   }
399 }
400 
net_editProps(GNet * n,int x,int y)401 void net_editProps(GNet *n,int x,int y)
402 {
403   char *sn = n->n_show_name ? "" :"@";
404   int ioCode = 0;
405   int wx = ctow_x(x-50);
406   int wy = ctow_y(y-50);
407   const char *result;
408   const char *vtype = GNet_getVType(n);
409 
410   if (n->n_ionet) {
411     ioCode = n->n_ionet->typeinfo->code;
412     if (ioCode != GC_LOGICIN && ioCode != GC_LOGICOUT && ioCode != GC_LOGICTRI)
413       ioCode = 0;	/* yappari yameta */
414   }
415 
416 
417   if (n->n_nbits == 1)
418     DoTcl("tkg_editNet %d %d {%s%s} %d %s\n",wx,wy,n->n_signame,sn,ioCode,vtype);
419   else
420     DoTcl("tkg_editNet %d %d {%s[%d:0]%s} %d %s\n",wx,wy,n->n_signame,n->n_nbits-1,sn,ioCode,vtype);
421 
422   result = Tcl_GetStringResult(TkGate.tcl);
423 
424   if (*result != '0')
425     SetModified(MF_NET);
426 }
427 
428 /*
429    Set the signal name of a wire to s.
430 */
net_rename(GNet * net,const char * s,int showName)431 void net_rename(GNet *net,const char *s,int showName)
432 {
433   char *oldName = ob_strdup(net->n_signame);
434   char buf[STRMAX];
435 
436   if (net->n_signame) {
437     if (net->n_mod && TkGate.circuit->es && net->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE)
438       DoTcl("NetList::del %s",net->n_signame);
439 
440     SHash_remove(net->n_mod->m_nets,net->n_signame);
441     ob_free(net->n_signame);
442   }
443   ob_touch(net);
444   net->n_signame = 0;
445   net->n_labelWidth = 0;
446 
447   pickValidName(buf,s,"w",net->n_mod->m_nets);
448   net->n_signame = ob_strdup(buf);
449 
450   if (showName)
451     GNet_showName(net);
452   else
453     GNet_hideName(net);
454 
455   SHash_insert(net->n_mod->m_nets,net->n_signame,net);
456 
457   if (net->n_mod && TkGate.circuit->es && net->n_mod == TkGate.circuit->es->env && editstate_getInterfaceMode() == INTFMODE_NONE) {
458     DoTcl("NetList::replace %s -hidden %d -bits %d -type %s",
459 	  net->n_signame,!net->n_show_name,net->n_nbits,GNet_getDTypeStr(net));
460   }
461   ob_free(oldName);
462 }
463 
464 /*
465  * Check 'name' to see if it is a valid name.  If 'H' is non-null, then the
466  * name may not appear as a key in the hash table.  Returns 0 if the name
467  * is valid.
468  */
checkValidName(const char * name,SHash * H)469 int checkValidName(const char *name,SHash *H)
470 {
471   const char *p = name;
472 
473   if (!isalpha(*p) && *p != '_')
474     return -1;
475 
476   for (p++;*p;p++) {
477     if (!isalpha(*p) && !isdigit(*p) && *p != '_')
478       return -1;
479   }
480 
481   if (H && SHash_find(H,name))
482     return -1;
483 
484   return 0;
485 }
486 
487 /*****************************************************************************
488  *
489  * Pick name for an object based on suggested name.
490  *
491  * Parameters:
492  *      buf		Return for generated name
493  *      name		Suggested name
494  *      base		Type-dependent base name for name generation
495  *      H		Table of already registered names
496  *
497  * Pick a valid name for an object based on a possible suggested name 'name',
498  * a base name 'base' for objects of a that type, and a hash table 'H' for objects
499  * of that type.  One or more of 'name', 'base' and 'H' may be null.  The generated
500  * name will be placed in 'buf'.  If 'name' is a valid name that does not appear in the
501  * hash table 'H', 'name' will become the selected name.
502  *
503  *****************************************************************************/
pickValidName(char * buf,const char * name,const char * base,SHash * H)504 void pickValidName(char *buf,const char *name,const char *base,SHash *H)
505 {
506   int reason;
507 
508   if (!base || !*base)
509     base = "n";
510 
511   reason = 0;
512   if (name) {
513     if (buf != (char*)name)
514       strcpy(buf,name);
515 
516     if (trimName(buf)) {
517       reason = 1;
518       if (!*buf) {
519 	if (base)
520 	  strcpy(buf,base);
521 	else
522 	  strcpy(buf,"name");
523       }
524     }
525 
526     if (!*buf)
527       sprintf(buf,"%s0",base);
528 
529     if (H && SHash_find(H,buf))
530       reason = 2;
531     else if (ycIsKW(buf))
532       reason = 4;
533     else {
534       if (reason)
535 	message(0,msgLookup("err.badnetname"));		/* "Illegal characters in identifier deleted." */
536       return;
537     }
538   } else
539     sprintf(buf,"%s0",base);
540 
541   /** @TODO to remove */
542   /*p = buf+strlen(buf);*/
543 
544   if ((H && SHash_find(H,buf)) || ycIsKW(buf)) {
545     char *p;
546     int n;
547 
548     p = buf + strlen(buf);
549     while (p > buf && isdigit((int)p[-1])) p--;
550 
551     n = 0;
552     if (*p) sscanf(p,"%d",&n);
553 
554     do {
555       sprintf(p,"%d",n++);
556     } while ((H && SHash_find(H,buf)) || ycIsKW(buf));
557   }
558 
559   switch (reason) {
560   case 1 :
561     message(0,msgLookup("err.netbcrename"),buf);	/* "Identifier renamed to '%s' because of illegal characters." */
562     break;
563   case 2 :
564     message(0,msgLookup("err.netconfnet"),buf);
565     break;
566   case 3 :
567     message(0,msgLookup("err.netconfgat"));
568     break;
569   case 4 :
570     message(0,msgLookup("err.netconfkw"));
571     break;
572   }
573 }
574 
GWire_pickProbePosition(GWire * w,int * x,int * y)575 int GWire_pickProbePosition(GWire *w,int *x,int *y)
576 {
577   int orig_x = *x;
578   int orig_y = *y;
579   int best_d = 0x7ffffff;
580   int best_x = 0, best_y = 0;
581   GWireNode *n;
582 
583 
584   w = wire_driver(w);
585   for (n = w->nodes;n && n->out;n = n->out) {
586     int x1 = n->x;
587     int y1 = n->y;
588     int x2 = n->out->x;
589     int y2 = n->out->y;
590     int d = 0x7fffffff;
591     int test_x, test_y;
592 
593     if (x1 == x2) {
594       if (iabs(orig_y-y1) <= iabs(y1-y2) && iabs(orig_y-y2) <= iabs(y1-y2)) {
595 	d = iabs(orig_x-x1)*iabs(orig_x-x1);
596 	test_x = x1;
597 	test_y = orig_y;
598       }
599     } else {
600       if (iabs(orig_x-x1) <= iabs(x1-x2) && iabs(orig_x-x2) <= iabs(x1-x2)) {
601 	d = iabs(orig_y-y1)*iabs(orig_y-y1);
602 	test_x = orig_x;
603 	test_y = y1;
604       }
605     }
606     if (d == 0x7fffffff) {
607       int d1 = iabs(orig_x-x1)*iabs(orig_x-x1) + iabs(orig_y-y1)*iabs(orig_y-y1);
608       int d2 = iabs(orig_x-x2)*iabs(orig_x-x2) + iabs(orig_y-y2)*iabs(orig_y-y2);
609       if (d1 < d2) {
610 	d = d1;
611 	test_x = x1;
612 	test_y = y1;
613       } else {
614 	d = d2;
615 	test_x = x2;
616 	test_y = y2;
617       }
618     }
619 
620     if (d < best_d) {
621       best_d = d;
622       best_x = test_x;
623       best_y = test_y;
624     }
625   }
626 
627   *x = best_x;
628   *y = best_y;
629 
630   return best_d;
631 }
632 
GNet_getDisplayLabel(GNet * net,char label[],int len,int mode)633 int GNet_getDisplayLabel(GNet *net,char label[],int len,int mode)
634 {
635   *label = 0;
636 
637   if (net->n_ionet && mode == DLM_GET_VISIBLE) {
638     switch (net->n_ionet->typeinfo->code) {
639     case GC_LOGICIN :
640     case GC_LOGICOUT :
641     case GC_LOGICTRI :
642       return 0;
643     }
644   }
645 
646   if ((net->n_show_name && net->n_signame) || mode != DLM_GET_VISIBLE) {
647     if (net->n_vtype != NV_WIRE)
648       sprintf(label,"%s(%s)",net->n_signame,GNet_getVType(net));
649     else
650       sprintf(label,"%s",net->n_signame);
651   } else if (net->n_vtype != NV_WIRE)
652     sprintf(label,"(%s)",GNet_getVType(net));
653 
654   return strlen(label);
655 }
656 
657 /*
658    Get the position (x,y) and justification p for a signal name
659    on wire w.
660 */
SignalNamePos(GWireNode * n1,GWireNode * n2,int * x,int * y,int * p,int * q)661 void SignalNamePos(GWireNode *n1,GWireNode *n2,int *x,int *y,int *p,int *q)
662 {
663   *x = n1->x + (n2->x - n1->x)/3;
664   *y = n1->y + (n2->y - n1->y)/3;
665 
666   if (n1->x == n2->x) {
667     *x += 5;
668     if (p) *p = AtLeft|BetweenTopAndBottom;
669   } else {
670     *x -= 5;
671     if (p) *p = BetweenLeftAndRight|AtBottom;
672   }
673 
674 
675   if (q) *q = (n1->x == n2->x) ? (n1->y <= n2->y) : 2 + (n1->x <= n2->x);
676 }
677 
GNet_getWires(GNet * n,GWire ** wlist,unsigned which)678 int GNet_getWires(GNet *n,GWire **wlist,unsigned which)
679 {
680   return GWire_getNetWires(n->n_driver,wlist,which);
681 }
682 
683 /*****************************************************************************
684  *
685  * Make sure the name on a net is hidden
686  *
687  * Parameter:
688  *     net			Net on which to make all labels hidden
689  *
690  *****************************************************************************/
GNet_hideName(GNet * net)691 void GNet_hideName(GNet *net)
692 {
693   ob_touch(net);
694   net->n_show_name = 0;
695   GNet_checkNameVisibility(net,0);
696   net_update(net);
697 }
698 
699 /*****************************************************************************
700  *
701  * Make sure the name on a net is visible
702  *
703  * Parameter:
704  *     net			Net on which to make the label visible
705  *
706  *****************************************************************************/
GNet_showName(GNet * net)707 void GNet_showName(GNet *net)
708 {
709   ob_touch(net);
710   net->n_show_name = 1;
711   GNet_checkNameVisibility(net,1);
712   net_update(net);
713 }
714 
GNet_checkNameVisibility(GNet * net,int action)715 void GNet_checkNameVisibility(GNet *net,int action)
716 {
717   if (net->n_show_name) {
718     GWire *wlist[GNet_numWires(net)];
719     GWireNode *n;
720     int count = GNet_getWires(net,wlist,GW_DRIVER);
721     int i;
722 
723 #if 0
724     printf("checkNameVis %s nw=%d count=%d\n",net->n_signame,GNet_numWires(net),count);
725 #endif
726 
727     /*
728      * Look for a labeled wire, if there is one, then return and do nothing further.
729      */
730     for (i = 0;i < count;i++) {
731 #if 0
732       printf("  pad %d\n",i);
733 #endif
734       for (n = wlist[i]->nodes;n;n = n->out) {
735 #if 0
736 	printf("    wire %p islab=%d\n",n,n->isLabeled);
737 #endif
738 	if (n->isLabeled) return;
739       }
740     }
741 
742     /*
743      * None of the existing wires were labeled, so pick one and label it.
744      */
745     for (n = net->n_driver->nodes;n && n->out;n = n->out)
746       if (!n->showSize)
747 	break;
748 
749     if (action) {
750       ob_touch(n);
751       //printf("%p: make labeled (1)\n",n);
752       n->isLabeled = 1;
753       n->offset = 50;
754     } else {
755       ob_touch(net);
756       net->n_show_name = 0;
757     }
758   }
759 }
760 
761 
GNet_getLabelWidth(GNet * n)762 int GNet_getLabelWidth(GNet *n)
763 {
764   if (!n->n_labelWidth) {
765     char label[STRMAX];
766 
767     if (GNet_getDisplayLabel(n, label, STRMAX, DLM_GET_ALWAYS) > 0) {
768       n->n_labelWidth = GKTextWidth(TkGate.stextbXF[TkGate.circuit->zoom_factor],label,strlen(label));
769     } else
770       n->n_labelWidth = 42;
771   }
772 
773   return n->n_labelWidth;
774 }
775 
776 /*****************************************************************************
777  *
778  * Square of distance from a point to a line segment.
779  *
780  *****************************************************************************/
segment_distance(int x,int y,int x1,int y1,int x2,int y2)781 int segment_distance(int x,int y,int x1,int y1,int x2,int y2)
782 {
783   if (x1 == x2) {	/* Veritical segment */
784     if (y1 > y2) { int t = y1;y1=y2;y2=t;}
785 
786     if (y < y1) {
787       return (y-y1)*(y-y1) + (x-x1)*(x-x1);
788     } else if (y > y2) {
789       return (y-y2)*(y-y2) + (x-x2)*(x-x2);
790     } else {
791       return (x-x1)*(x-x1);
792     }
793 
794   } else {		/* Horizontal segment */
795     if (x1 > x2) { int t = x1;x1=x2;x2=t;}
796 
797     if (x < x1) {
798       return (y-y1)*(y-y1) + (x-x1)*(x-x1);
799     } else if (x > x2) {
800       return (y-y2)*(y-y2) + (x-x2)*(x-x2);
801     } else {
802       return (y-y1)*(y-y1);
803     }
804   }
805 }
806 
GNet_labelClosest(GNet * net,int x,int y)807 void GNet_labelClosest(GNet *net,int x,int y)
808 {
809   GWire *wlist[GNet_numWires(net)];
810   GWireNode *n,*best_n = 0;
811   int best_dist = 0;
812   int count = GNet_getWires(net,wlist,GW_DRIVER);
813   int offset;
814   int side;
815   int i;
816 
817 
818   for (i = 0;i < count;i++) {
819     for (n = wlist[i]->nodes;n && n->out;n = n->out) {
820       int d = segment_distance(x,y,n->x,n->y,n->out->x,n->out->y);
821 
822       if (!best_n || d < best_dist) {
823 	best_dist = d;
824 	best_n = n;
825       }
826     }
827   }
828 
829   if (best_dist > 50*50) {
830     GNet_checkNameVisibility(net,0);
831     net_update(net);
832     return;
833   }
834 
835 
836   /*
837    * We found the node we wish to label...
838    */
839   if (best_n) {
840     int x1 = best_n->x;
841     int y1 = best_n->y;
842     int x2 = best_n->out->x;
843     int y2 = best_n->out->y;
844     GrabbedLabel *gl = TkGate.circuit->labelsel;
845 
846     GNet_draw(net);
847     ob_touch(best_n);
848     best_n->isLabeled = 1;
849 
850     if (y1 != y2) {
851       /* Vertical */
852       int ay = y + gl->oy;
853 
854       if ((gl->position & AtTop))
855 	ay += 12;
856 
857       offset = 100*(ay-y1)/(y2-y1);
858       side = (x < x1);
859     } else if (x1 != x2) {
860       /* Horizontal */
861       int ax = x + gl->ox;
862 
863       if ((gl->position & AtRight))
864 	ax -= GNet_getLabelWidth(net);
865 
866       offset = 100*(ax-x1)/(x2-x1);
867       side = (y > y1);
868     } else {
869       offset = 50;
870       side = 0;
871     }
872 
873     if (offset < 1) offset = 1;
874     if (offset > 99) offset = 99;
875     best_n->offset = offset;
876     best_n->labelSide = side;
877     GNet_draw(net);
878   }
879 }
880 
881