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