1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 
5 #include <stdio.h>
6 #include <stdarg.h>
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #include "xincludes.h"
11 
12 #include "compat.h"
13 #include "global.h"
14 #include "data.h"
15 
16 #include "find.h"
17 #include "flags.h"
18 #include "rats.h"
19 #include "select.h"
20 #include "undo.h"
21 #include "remove.h"
22 #include "crosshair.h"
23 #include "draw.h"
24 
25 #include "hid.h"
26 #include "../hidint.h"
27 #include "lesstif.h"
28 
29 #ifdef HAVE_LIBDMALLOC
30 #include <dmalloc.h>
31 #endif
32 
33 static Arg args[30];
34 static int n;
35 #define stdarg(t,v) XtSetArg(args[n], t, v); n++
36 
37 static Widget netlist_dialog = 0;
38 static Widget netlist_list, netnode_list;
39 
40 static XmString *netlist_strings = 0;
41 static XmString *netnode_strings = 0;
42 static int n_netnode_strings;
43 static int last_pick = -1;
44 
45 static int LesstifNetlistChanged (int argc, char **argv, Coord x, Coord y);
46 
47 static void
pick_net(int pick)48 pick_net (int pick)
49 {
50   LibraryMenuType *menu = PCB->NetlistLib.Menu + pick;
51   int i;
52 
53   if (pick == last_pick)
54     return;
55   last_pick = pick;
56 
57   if (netnode_strings)
58     free (netnode_strings);	/* XXX leaked all XmStrings??? */
59   n_netnode_strings = menu->EntryN;
60   netnode_strings = (XmString *) malloc (menu->EntryN * sizeof (XmString));
61   for (i = 0; i < menu->EntryN; i++)
62     netnode_strings[i] = XmStringCreatePCB (menu->Entry[i].ListEntry);
63   n = 0;
64   stdarg (XmNitems, netnode_strings);
65   stdarg (XmNitemCount, menu->EntryN);
66   XtSetValues (netnode_list, args, n);
67 }
68 
69 static void
netlist_select(Widget w,void * v,XmListCallbackStruct * cbs)70 netlist_select (Widget w, void *v, XmListCallbackStruct * cbs)
71 {
72   XmString str;
73   int pos = cbs->item_position;
74   LibraryMenuType *net = & (PCB->NetlistLib.Menu[pos - 1]);
75   char *name = net->Name;
76   if (name[0] == ' ')
77     {
78       name[0] = '*';
79       net->flag = 0;
80     }
81   else
82     {
83       name[0] = ' ';
84       net->flag = 1;
85     }
86 
87   str = XmStringCreatePCB (name);
88   XmListReplaceItemsPos (netlist_list, &str, 1, pos);
89   XmStringFree (str);
90   XmListSelectPos (netlist_list, pos, False);
91 }
92 
93 static void
netlist_extend(Widget w,void * v,XmListCallbackStruct * cbs)94 netlist_extend (Widget w, void *v, XmListCallbackStruct * cbs)
95 {
96   if (cbs->selected_item_count == 1)
97     pick_net (cbs->item_position - 1);
98 }
99 
100 typedef void (*Std_Nbcb_Func)(LibraryMenuType *, int);
101 
102 static void
nbcb_rat_on(LibraryMenuType * net,int pos)103 nbcb_rat_on (LibraryMenuType *net, int pos)
104 {
105   XmString str;
106   char *name = net->Name;
107   name[0] = ' ';
108   net->flag = 1;
109   str = XmStringCreatePCB (name);
110   XmListReplaceItemsPos (netlist_list, &str, 1, pos);
111   XmStringFree (str);
112 }
113 
114 static void
nbcb_rat_off(LibraryMenuType * net,int pos)115 nbcb_rat_off (LibraryMenuType *net, int pos)
116 {
117   XmString str;
118   char *name = net->Name;
119   name[0] = '*';
120   net->flag = 0;
121   str = XmStringCreatePCB (name);
122   XmListReplaceItemsPos (netlist_list, &str, 1, pos);
123   XmStringFree (str);
124 }
125 
126 
127 /* Select on the layout the current net treeview selection
128  */
129 static void
nbcb_select_common(LibraryMenuType * net,int pos,int select_flag)130 nbcb_select_common (LibraryMenuType *net, int pos, int select_flag)
131 {
132   LibraryEntryType *entry;
133   ConnectionType conn;
134   int i;
135 
136   InitConnectionLookup ();
137   ClearFlagOnAllObjects (FOUNDFLAG, true);
138 
139   for (i = net->EntryN, entry = net->Entry; i; i--, entry++)
140     if (SeekPad (entry, &conn, false))
141       RatFindHook (conn.type, conn.ptr1, conn.ptr2, conn.ptr2, true, FOUNDFLAG, true);
142 
143   SelectByFlag (FOUNDFLAG, select_flag);
144   ClearFlagOnAllObjects (FOUNDFLAG, false);
145   FreeConnectionLookupMemory ();
146   IncrementUndoSerialNumber ();
147   Draw ();
148 }
149 
150 static void
nbcb_select(LibraryMenuType * net,int pos)151 nbcb_select (LibraryMenuType *net, int pos)
152 {
153   nbcb_select_common (net, pos, 1);
154 }
155 
156 static void
nbcb_deselect(LibraryMenuType * net,int pos)157 nbcb_deselect (LibraryMenuType *net, int pos)
158 {
159   nbcb_select_common (net, pos, 0);
160 }
161 
162 static void
nbcb_find(LibraryMenuType * net,int pos)163 nbcb_find (LibraryMenuType *net, int pos)
164 {
165   char *name = net->Name + 2;
166   hid_actionl ("netlist", "find", name, NULL);
167 }
168 
169 static void
nbcb_std_callback(Widget w,Std_Nbcb_Func v,XmPushButtonCallbackStruct * cbs)170 nbcb_std_callback (Widget w, Std_Nbcb_Func v, XmPushButtonCallbackStruct * cbs)
171 {
172   int *posl, posc, i;
173   XmString **items, **selected;
174   if (XmListGetSelectedPos (netlist_list, &posl, &posc) == False)
175     return;
176   if (v == nbcb_find)
177     hid_actionl ("connection", "reset", NULL);
178   for (i=0; i<posc; i++)
179     {
180       LibraryMenuType *net = & (PCB->NetlistLib.Menu[posl[i] - 1]);
181       v(net, posl[i]);
182     }
183   n = 0;
184   stdarg (XmNitems, &items);
185   XtGetValues (netlist_list, args, n);
186   selected = (XmString **) malloc (posc * sizeof (XmString *));
187   for (i=0; i<posc; i++)
188     selected[i] = items[posl[i]-1];
189 
190   n = 0;
191   stdarg (XmNselectedItems, selected);
192   XtSetValues (netlist_list, args, n);
193 }
194 
195 static void
nbcb_ripup(Widget w,Std_Nbcb_Func v,XmPushButtonCallbackStruct * cbs)196 nbcb_ripup (Widget w, Std_Nbcb_Func v, XmPushButtonCallbackStruct * cbs)
197 {
198   nbcb_std_callback (w, nbcb_find, cbs);
199 
200   VISIBLELINE_LOOP (PCB->Data);
201   {
202     if (TEST_FLAG (FOUNDFLAG, line) && !TEST_FLAG (LOCKFLAG, line))
203       RemoveObject (LINE_TYPE, layer, line, line);
204   }
205   ENDALL_LOOP;
206 
207   VISIBLEARC_LOOP (PCB->Data);
208   {
209     if (TEST_FLAG (FOUNDFLAG, arc) && !TEST_FLAG (LOCKFLAG, arc))
210       RemoveObject (ARC_TYPE, layer, arc, arc);
211   }
212   ENDALL_LOOP;
213 
214   if (PCB->ViaOn)
215     VIA_LOOP (PCB->Data);
216   {
217     if (TEST_FLAG (FOUNDFLAG, via) && !TEST_FLAG (LOCKFLAG, via))
218       RemoveObject (VIA_TYPE, via, via, via);
219   }
220   END_LOOP;
221 }
222 
223 static void
netnode_browse(Widget w,XtPointer v,XmListCallbackStruct * cbs)224 netnode_browse (Widget w, XtPointer v, XmListCallbackStruct * cbs)
225 {
226   LibraryMenuType *menu = PCB->NetlistLib.Menu + last_pick;
227   char *name = menu->Entry[cbs->item_position - 1].ListEntry;
228   char *ename, *pname;
229 
230   ename = strdup (name);
231   pname = strchr (ename, '-');
232   if (! pname)
233     {
234       free (ename);
235       return;
236     }
237   *pname++ = 0;
238 
239   ELEMENT_LOOP (PCB->Data);
240   {
241     char *es = element->Name[NAMEONPCB_INDEX].TextString;
242     if (es && strcmp (es, ename) == 0)
243       {
244 	PIN_LOOP (element);
245 	{
246 	  if (strcmp (pin->Number, pname) == 0)
247 	    {
248 	      MoveCrosshairAbsolute (pin->X, pin->Y);
249 	      free (ename);
250 	      return;
251 	    }
252 	}
253 	END_LOOP;
254 	PAD_LOOP (element);
255 	{
256 	  if (strcmp (pad->Number, pname) == 0)
257 	    {
258 	      int x = (pad->Point1.X + pad->Point2.X) / 2;
259 	      int y = (pad->Point1.Y + pad->Point2.Y) / 2;
260 	      gui->set_crosshair (x, y, HID_SC_PAN_VIEWPORT);
261 	      free (ename);
262 	      return;
263 	    }
264 	}
265 	END_LOOP;
266       }
267   }
268   END_LOOP;
269   free (ename);
270 }
271 
272 #define NLB_FORM ((Widget)(~0))
273 static Widget
netlist_button(Widget parent,char * name,char * string,Widget top,Widget bottom,Widget left,Widget right,XtCallbackProc callback,void * user_data)274 netlist_button (Widget parent, char *name, char *string,
275 		Widget top, Widget bottom, Widget left, Widget right,
276 		XtCallbackProc callback, void *user_data)
277 {
278   Widget rv;
279   XmString str;
280 
281 #define NLB_W(w) if (w == NLB_FORM) { stdarg(XmN ## w ## Attachment, XmATTACH_FORM); } \
282   else if (w) { stdarg(XmN ## w ## Attachment, XmATTACH_WIDGET); \
283     stdarg (XmN ## w ## Widget, w); }
284 
285   NLB_W (top);
286   NLB_W (bottom);
287   NLB_W (left);
288   NLB_W (right);
289   str = XmStringCreatePCB (string);
290   stdarg(XmNlabelString, str);
291   rv = XmCreatePushButton (parent, name, args, n);
292   XtManageChild (rv);
293   if (callback)
294     XtAddCallback (rv, XmNactivateCallback, callback, (XtPointer)user_data);
295   XmStringFree(str);
296   return rv;
297 }
298 
299 static int
build_netlist_dialog()300 build_netlist_dialog ()
301 {
302   Widget b_sel, b_unsel, b_find, b_rat_on, l_ops;
303   XmString ops_str;
304 
305   if (!mainwind)
306     return 1;
307   if (netlist_dialog)
308     return 0;
309 
310   n = 0;
311   stdarg (XmNresizePolicy, XmRESIZE_GROW);
312   stdarg (XmNtitle, "Netlists");
313   stdarg (XmNautoUnmanage, False);
314   netlist_dialog = XmCreateFormDialog (mainwind, "netlist", args, n);
315 
316   n = 0;
317   b_rat_on = netlist_button (netlist_dialog, "rat_on", "Enable for rats",
318 			     0, NLB_FORM, NLB_FORM, 0,
319 			     (XtCallbackProc)nbcb_std_callback, (void *)nbcb_rat_on);
320 
321   n = 0;
322   netlist_button (netlist_dialog, "rat_off", "Disable for rats",
323                   0, NLB_FORM, b_rat_on, 0,
324                   (XtCallbackProc)nbcb_std_callback, (void *)nbcb_rat_off);
325 
326   n = 0;
327   b_sel = netlist_button (netlist_dialog, "select", "Select",
328 			  0, b_rat_on, NLB_FORM, 0,
329 			      (XtCallbackProc)nbcb_std_callback, (void *)nbcb_select);
330 
331   n = 0;
332   b_unsel = netlist_button (netlist_dialog, "deselect", "Deselect",
333 			    0, b_rat_on, b_sel, 0,
334 			      (XtCallbackProc)nbcb_std_callback, (void *)nbcb_deselect);
335 
336   n = 0;
337   b_find = netlist_button (netlist_dialog, "find", "Find",
338 			   0, b_rat_on, b_unsel, 0,
339 			   (XtCallbackProc)nbcb_std_callback, (void *)nbcb_find);
340 
341 
342   n = 0;
343   netlist_button (netlist_dialog, "ripup", "Rip Up",
344                   0, b_rat_on, b_find, 0,
345                   (XtCallbackProc)nbcb_ripup, 0);
346 
347   n = 0;
348   stdarg (XmNbottomAttachment, XmATTACH_WIDGET);
349   stdarg (XmNbottomWidget, b_sel);
350   stdarg (XmNleftAttachment, XmATTACH_FORM);
351   ops_str = XmStringCreatePCB ("Operations on selected net names:");
352   stdarg (XmNlabelString, ops_str);
353   l_ops = XmCreateLabel (netlist_dialog, "ops", args, n);
354   XtManageChild (l_ops);
355 
356   n = 0;
357   stdarg (XmNtopAttachment, XmATTACH_FORM);
358   stdarg (XmNbottomAttachment, XmATTACH_WIDGET);
359   stdarg (XmNbottomWidget, l_ops);
360   stdarg (XmNleftAttachment, XmATTACH_FORM);
361   stdarg (XmNrightAttachment, XmATTACH_POSITION);
362   stdarg (XmNrightPosition, 50);
363   stdarg (XmNvisibleItemCount, 10);
364   stdarg (XmNselectionPolicy, XmEXTENDED_SELECT);
365   netlist_list = XmCreateScrolledList (netlist_dialog, "nets", args, n);
366   XtManageChild (netlist_list);
367   XtAddCallback (netlist_list, XmNdefaultActionCallback, (XtCallbackProc)netlist_select, 0);
368   XtAddCallback (netlist_list, XmNextendedSelectionCallback, (XtCallbackProc)netlist_extend, 0);
369 
370   n = 0;
371   stdarg (XmNtopAttachment, XmATTACH_FORM);
372   stdarg (XmNbottomAttachment, XmATTACH_WIDGET);
373   stdarg (XmNbottomWidget, l_ops);
374   stdarg (XmNrightAttachment, XmATTACH_FORM);
375   stdarg (XmNleftAttachment, XmATTACH_POSITION);
376   stdarg (XmNleftPosition, 50);
377   netnode_list = XmCreateScrolledList (netlist_dialog, "nodes", args, n);
378   XtManageChild (netnode_list);
379   XtAddCallback (netnode_list, XmNbrowseSelectionCallback, (XtCallbackProc)netnode_browse, 0);
380 
381   return 0;
382 }
383 
384 static int
LesstifNetlistChanged(int argc,char ** argv,Coord x,Coord y)385 LesstifNetlistChanged (int argc, char **argv, Coord x, Coord y)
386 {
387   int i;
388   if (!PCB->NetlistLib.MenuN)
389     return 0;
390   if (build_netlist_dialog ())
391     return 0;
392   last_pick = -1;
393   if (netlist_strings)
394     free (netlist_strings);
395   netlist_strings =
396     (XmString *) malloc (PCB->NetlistLib.MenuN * sizeof (XmString));
397   for (i = 0; i < PCB->NetlistLib.MenuN; i++)
398     netlist_strings[i] =
399       XmStringCreatePCB (PCB->NetlistLib.Menu[i].Name);
400   n = 0;
401   stdarg (XmNitems, netlist_strings);
402   stdarg (XmNitemCount, PCB->NetlistLib.MenuN);
403   XtSetValues (netlist_list, args, n);
404   pick_net (0);
405   return 0;
406 }
407 
408 static const char netlistshow_syntax[] =
409 "NetlistShow(pinname|netname)";
410 
411 static const char netlistshow_help[] =
412 "Selects the given pinname or netname in the netlist window.";
413 
414 /* %start-doc actions NetlistShow
415 
416 %end-doc */
417 
418 static int
LesstifNetlistShow(int argc,char ** argv,Coord x,Coord y)419 LesstifNetlistShow (int argc, char **argv, Coord x, Coord y)
420 {
421   if (build_netlist_dialog ())
422     return 0;
423 
424   if (argc == 1)
425     {
426       LibraryMenuType *net;
427 
428       net = netnode_to_netname(argv[0]);
429       if (net)
430 	{
431 	  XmString item;
432 	  int vis = 0;
433 
434 	  /* Select net first, 'True' causes pick_net() to be invoked */
435 	  item = XmStringCreatePCB (net->Name);
436 	  XmListSelectItem (netlist_list, item, True);
437 	  XmListSetItem (netlist_list, item);
438 	  XmStringFree (item);
439 
440 	  /* Now the netnode_list has the right contents */
441 	  item = XmStringCreatePCB (argv[0]);
442 	  XmListSelectItem (netnode_list, item, False);
443 
444 	  /*
445 	   * Only force the item to the top if there are enough to scroll.
446 	   * A bug (?) in lesstif will cause the window to get ever wider
447 	   * if an XmList that doesn't require a scrollbar is forced to
448 	   * have one (when the top item is not the first item).
449 	   */
450 	  n = 0;
451 	  stdarg (XmNvisibleItemCount, &vis);
452 	  XtGetValues (netnode_list, args, n);
453 	  if (n_netnode_strings > vis)
454 	    {
455 	      XmListSetItem (netnode_list, item);
456 	    }
457 	  XmStringFree (item);
458 	}
459       else
460 	{
461 	  /* Try the argument as a netname */
462 	  net = netname_to_netname(argv[0]);
463 	  if (net)
464 	    {
465 	      XmString item;
466 
467 	      item = XmStringCreatePCB (net->Name);
468 	      XmListSetItem (netlist_list, item);
469 	      XmListSelectItem (netlist_list, item, True);
470 	      XmStringFree (item);
471 	    }
472 	}
473     }
474   return 0;
475 }
476 
477 void
lesstif_show_netlist()478 lesstif_show_netlist ()
479 {
480   build_netlist_dialog ();
481   XtManageChild (netlist_dialog);
482 }
483 
484 HID_Action lesstif_netlist_action_list[] = {
485   {"NetlistChanged", 0, LesstifNetlistChanged,
486    netlistchanged_help, netlistchanged_syntax},
487   {"NetlistShow", 0, LesstifNetlistShow,
488    netlistshow_help, netlistshow_syntax}
489 };
490 
491 REGISTER_ACTIONS (lesstif_netlist_action_list)
492