4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996,1997,1998 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
28 * This file written by Bill Wilson for the PCB Gtk port
59 #ifdef HAVE_LIBDMALLOC
63 #define NET_HIERARCHY_SEPARATOR "/"
65 static GtkWidget
*netlist_window
;
66 static GtkWidget
*disable_all_button
;
68 static GtkTreeModel
*node_model
;
69 static GtkTreeView
*node_treeview
;
71 static gboolean selection_holdoff
;
73 static LibraryMenuType
*selected_net
;
74 static LibraryMenuType
*node_selected_net
;
77 /* The Netlist window displays all the layout nets in a left treeview
78 | When one of the nets is selected, all of its nodes (or connections)
79 | will be displayed in a right treeview. If a "Select on layout" button
80 | is pressed, the net that is selected in the left treeview will be
81 | drawn selected on the layout.
83 | Gtk separates the data model from the view in its treeview widgets so
84 | here we maintain two data models. The net data model has pointers to
85 | all the nets in the layout and the node data model keeps pointers to all
86 | the nodes for the currently selected net. By updating the data models
87 | the net and node gtk treeviews handle displaying the results.
89 | The netlist window code has a public interface providing hooks so PCB
90 | code can control the net and node treeviews:
92 | ghid_get_net_from_node_name gchar *node_name, gboolean enabled_only)
93 | Given a node name (eg C101-1), walk through the nets in the net
94 | data model and search each net for the given node_name. If found
95 | and enabled_only is true, make the net treeview scroll to and
96 | highlight (select) the found net. Return the found net.
98 | ghid_netlist_highlight_node()
99 | Given some PCB internal pointers (not really a good gui api here)
100 | look up a node name determined by the pointers and highlight the node
101 | in the node treeview. By using ghid_get_net_from_node_name() to
102 | look up the node, the net the node belongs to will also be
103 | highlighted in the net treeview.
105 | ghid_netlist_window_update(gboolean init_nodes)
106 | PCB calls this to tell the gui netlist code the layout net has
107 | changed and the gui data structures (net and optionally node data
108 | models) should be rebuilt.
112 /* -------- The netlist nodes (LibraryEntryType) data model ----------
113 | Each time a net is selected in the left treeview, this node model
114 | is recreated containing all the nodes (pins/pads) that are connected
115 | to the net. Loading the new model will update the right treeview with
116 | all the new node names (C100-1, R100-1, etc).
118 | The terminology is a bit confusing because the PCB netlist data
119 | structures are generic structures used for library elements, netlist
120 | data, and possibly other things also. The mapping is that
121 | the layout netlist data structure is a LibraryType which
122 | contains an allocated array of LibraryMenuType structs. Each of these
123 | structs represents a net in the netlist and contains an array
124 | of LibraryEntryType structs which represent the nodes connecting to
125 | the net. So we have:
128 | LibraryType LibraryMenuType LibraryEntryType
129 | -------------------------------------------------------
130 | PCB->NetlistLib------Menu[0]-----------Entry[0]
134 | --Menu[1]-----------Entry[0]
140 | Where for example Menu[] names would be nets GND, Vcc, etc and Entry[]
141 | names would be nodes C101-1, R101-2, etc
144 LibraryEntryType
*node_get_node_from_name (gchar
* node_name
,
145 LibraryMenuType
** node_net
);
149 NODE_NAME_COLUMN
, /* Name to show in the treeview */
150 NODE_LIBRARY_COLUMN
, /* Pointer to this node (LibraryEntryType) */
154 /* Given a net in the netlist (a LibraryMenuType) put all the Entry[]
155 | names (the nodes) into a newly created node tree model.
157 static GtkTreeModel
*
158 node_model_create (LibraryMenuType
* menu
)
163 store
= gtk_list_store_new (N_NODE_COLUMNS
, G_TYPE_STRING
, G_TYPE_POINTER
);
166 return GTK_TREE_MODEL (store
);
170 if (!entry
->ListEntry
)
172 gtk_list_store_append (store
, &iter
);
173 gtk_list_store_set (store
, &iter
,
174 NODE_NAME_COLUMN
, entry
->ListEntry
,
175 NODE_LIBRARY_COLUMN
, entry
, -1);
179 return GTK_TREE_MODEL (store
);
182 /* When there's a new node to display in the node treeview, call this.
183 | Create a new model containing the nodes of the given net, insert
184 | the model into the treeview and unref the old model.
187 node_model_update (LibraryMenuType
* menu
)
192 node_model
= node_model_create (menu
);
193 gtk_tree_view_set_model (node_treeview
, node_model
);
195 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (node_model
),
196 NODE_NAME_COLUMN
, GTK_SORT_ASCENDING
);
198 /* We could be using gtk_list_store_clear() on the same model, but it's
199 | just as easy that we've created a new one and here unref the old one.
202 g_object_unref (G_OBJECT (model
));
206 toggle_pin_selected (LibraryEntryType
*entry
)
210 if (!SeekPad (entry
, &conn
, false))
213 AddObjectToFlagUndoList (conn
.type
, conn
.ptr1
, conn
.ptr2
, conn
.ptr2
);
214 TOGGLE_FLAG (SELECTEDFLAG
, (AnyObjectType
*)conn
.ptr2
);
215 DrawObject (conn
.type
, conn
.ptr1
, conn
.ptr2
);
219 /* Callback when the user clicks on a PCB node in the right node treeview.
222 node_selection_changed_cb (GtkTreeSelection
* selection
, gpointer data
)
226 LibraryMenuType
*node_net
;
227 LibraryEntryType
*node
;
230 static gchar
*node_name
;
232 if (selection_holdoff
) /* PCB is highlighting, user is not selecting */
235 /* Toggle off the previous selection. Look up node_name to make sure
236 | it still exists. This toggling can get out of sync if a node is
237 | toggled selected, then the net that includes the node is selected
240 if ((node
= node_get_node_from_name (node_name
, &node_net
)) != NULL
)
242 /* If net node belongs to has been highlighted/unhighighed, toggling
243 | if off here will get our on/off toggling out of sync.
245 if (node_net
== node_selected_net
)
247 toggle_pin_selected (node
);
248 ghid_cancel_lead_user ();
254 /* Get the selected treeview row.
256 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
259 ghid_invalidate_all ();
263 /* From the treeview row, extract the node pointer stored there and
264 | we've got a pointer to the LibraryEntryType (node) the row
267 gtk_tree_model_get (model
, &iter
, NODE_LIBRARY_COLUMN
, &node
, -1);
269 dup_string (&node_name
, node
->ListEntry
);
270 node_selected_net
= selected_net
;
272 /* Now just toggle a select of the node on the layout
274 toggle_pin_selected (node
);
275 IncrementUndoSerialNumber ();
277 /* And lead the user to the location */
278 if (SeekPad (node
, &conn
, false))
282 PinType
*pin
= (PinType
*) conn
.ptr2
;
285 gui
->set_crosshair (x
, y
, 0);
286 ghid_lead_user_to_location (x
, y
);
291 PadType
*pad
= (PadType
*) conn
.ptr2
;
292 x
= pad
->Point1
.X
+ (pad
->Point2
.X
- pad
->Point1
.X
) / 2;
293 y
= pad
->Point1
.Y
+ (pad
->Point2
.Y
- pad
->Point1
.Y
) / 2;
294 gui
->set_crosshair (x
, y
, 0);
295 ghid_lead_user_to_location (x
, y
);
302 /* -------- The net (LibraryMenuType) data model ----------
304 /* TODO: the enable and disable all nets. Can't seem to get how that's
305 | supposed to work, but it'll take updating the NET_ENABLED_COLUMN in
306 | the net_model. Probably it should be made into a gpointer and make
307 | a text renderer for it and just write a '*' or a ' ' similar to the
308 | the Xt PCB scheme. Or better, since it's an "all nets" function, just
309 | have a "Disable all nets" toggle button and don't mess with the
310 | model/treeview at all.
314 NET_ENABLED_COLUMN
, /* If enabled will be ' ', if disable '*' */
315 NET_NAME_COLUMN
, /* Name to show in the treeview */
316 NET_LIBRARY_COLUMN
, /* Pointer to this net (LibraryMenuType) */
320 static GtkTreeModel
*net_model
= NULL
;
321 static GtkTreeView
*net_treeview
;
323 static gboolean loading_new_netlist
;
325 static GtkTreeModel
*
326 net_model_create (void)
330 GtkTreeIter new_iter
;
331 GtkTreeIter parent_iter
;
332 GtkTreeIter
*parent_ptr
;
334 GtkTreeRowReference
*row_ref
;
335 GHashTable
*prefix_hash
;
339 char **path_segments
;
343 store
= gtk_tree_store_new (N_NET_COLUMNS
,
344 G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_POINTER
);
346 model
= GTK_TREE_MODEL (store
);
348 /* Hash table stores GtkTreeRowReference for given path prefixes */
349 prefix_hash
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
,
351 gtk_tree_row_reference_free
);
353 MENU_LOOP (&PCB
->NetlistLib
);
358 if (loading_new_netlist
)
363 path_segments
= g_strsplit (menu
->Name
, NET_HIERARCHY_SEPARATOR
, 0);
364 path_depth
= g_strv_length (path_segments
);
366 for (try_depth
= path_depth
- 1; try_depth
> 0; try_depth
--)
368 join_array
= g_new0 (char *, try_depth
+ 1);
369 memcpy (join_array
, path_segments
, sizeof (char *) * try_depth
);
371 /* See if this net's parent node is in the hash table */
372 hash_string
= g_strjoinv (NET_HIERARCHY_SEPARATOR
, join_array
);
375 row_ref
= (GtkTreeRowReference
*)g_hash_table_lookup (prefix_hash
, hash_string
);
376 g_free (hash_string
);
378 /* If we didn't find the path at this level, keep looping */
382 path
= gtk_tree_row_reference_get_path (row_ref
);
383 gtk_tree_model_get_iter (model
, &parent_iter
, path
);
384 parent_ptr
= &parent_iter
;
388 /* NB: parent_ptr may still be NULL if we reached the toplevel */
390 /* Now walk up the desired path, adding the nodes */
392 for (; try_depth
< path_depth
- 1; try_depth
++)
394 display_name
= g_strconcat (path_segments
[try_depth
],
395 NET_HIERARCHY_SEPARATOR
, NULL
);
396 gtk_tree_store_append (store
, &new_iter
, parent_ptr
);
397 gtk_tree_store_set (store
, &new_iter
,
398 NET_ENABLED_COLUMN
, "",
399 NET_NAME_COLUMN
, display_name
,
400 NET_LIBRARY_COLUMN
, NULL
, -1);
401 g_free (display_name
);
403 path
= gtk_tree_model_get_path (model
, &new_iter
);
404 row_ref
= gtk_tree_row_reference_new (model
, path
);
405 parent_iter
= new_iter
;
406 parent_ptr
= &parent_iter
;
408 join_array
= g_new0 (char *, try_depth
+ 2);
409 memcpy (join_array
, path_segments
, sizeof (char *) * (try_depth
+ 1));
411 hash_string
= g_strjoinv (NET_HIERARCHY_SEPARATOR
, join_array
);
414 /* Insert those node in the hash table */
415 g_hash_table_insert (prefix_hash
, hash_string
, row_ref
);
416 /* Don't free hash_string, it is now oened by the hash table */
419 gtk_tree_store_append (store
, &new_iter
, parent_ptr
);
420 gtk_tree_store_set (store
, &new_iter
,
421 NET_ENABLED_COLUMN
, menu
->flag
? "" : "*",
422 NET_NAME_COLUMN
, path_segments
[path_depth
- 1],
423 NET_LIBRARY_COLUMN
, menu
, -1);
424 g_strfreev (path_segments
);
428 g_hash_table_destroy (prefix_hash
);
434 /* Called when the user double clicks on a net in the left treeview.
437 net_selection_double_click_cb (GtkTreeView
* treeview
, GtkTreePath
* path
,
438 GtkTreeViewColumn
* col
, gpointer data
)
443 LibraryMenuType
*menu
;
445 model
= gtk_tree_view_get_model (treeview
);
446 if (gtk_tree_model_get_iter (model
, &iter
, path
))
449 /* Expand / contract nodes with children */
450 if (gtk_tree_model_iter_has_child (model
, &iter
))
452 if (gtk_tree_view_row_expanded (treeview
, path
))
453 gtk_tree_view_collapse_row (treeview
, path
);
455 gtk_tree_view_expand_row (treeview
, path
, FALSE
);
459 /* Get the current enabled string and toggle it between "" and "*"
461 gtk_tree_model_get (model
, &iter
, NET_ENABLED_COLUMN
, &str
, -1);
462 gtk_tree_store_set (GTK_TREE_STORE (model
), &iter
,
463 NET_ENABLED_COLUMN
, !strcmp (str
, "*") ? "" : "*",
465 /* set/clear the flag which says the net is enabled or disabled */
466 gtk_tree_model_get (model
, &iter
, NET_LIBRARY_COLUMN
, &menu
, -1);
467 menu
->flag
= strcmp (str
, "*") == 0 ? 1 : 0;
472 /* Called when the user clicks on a net in the left treeview.
475 net_selection_changed_cb (GtkTreeSelection
* selection
, gpointer data
)
479 LibraryMenuType
*net
;
481 if (selection_holdoff
) /* PCB is highlighting, user is not selecting */
484 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
491 /* Get a pointer, net, to the LibraryMenuType of the newly selected
492 | netlist row, and create a new node model from the net entries
493 | and insert that model into the node view. Delete old entry model.
495 gtk_tree_model_get (model
, &iter
, NET_LIBRARY_COLUMN
, &net
, -1);
496 node_model_update (net
);
502 netlist_disable_all_cb (GtkToggleButton
* button
, gpointer data
)
505 gboolean active
= gtk_toggle_button_get_active (button
);
506 LibraryMenuType
*menu
;
508 /* Get each net iter and change the NET_ENABLED_COLUMN to a "*" or ""
509 | to flag it as disabled or enabled based on toggle button state.
511 if (gtk_tree_model_get_iter_first (net_model
, &iter
))
514 gtk_tree_store_set (GTK_TREE_STORE (net_model
), &iter
,
515 NET_ENABLED_COLUMN
, active
? "*" : "", -1);
516 /* set/clear the flag which says the net is enabled or disabled */
517 gtk_tree_model_get (net_model
, &iter
, NET_LIBRARY_COLUMN
, &menu
, -1);
518 menu
->flag
= active
? 0 : 1;
520 while (gtk_tree_model_iter_next (net_model
, &iter
));
523 /* Select on the layout the current net treeview selection
526 netlist_select_cb (GtkWidget
* widget
, gpointer data
)
528 LibraryEntryType
*entry
;
531 gboolean select_flag
= GPOINTER_TO_INT (data
);
535 if (selected_net
== node_selected_net
)
536 node_selected_net
= NULL
;
538 InitConnectionLookup ();
539 ResetConnections (true, FOUNDFLAG
);
541 for (i
= selected_net
->EntryN
, entry
= selected_net
->Entry
; i
; i
--, entry
++)
542 if (SeekPad (entry
, &conn
, false))
543 RatFindHook (conn
.type
, conn
.ptr1
, conn
.ptr2
, conn
.ptr2
, true, FOUNDFLAG
, true);
545 SelectByFlag (FOUNDFLAG
, select_flag
);
546 ResetConnections (false, FOUNDFLAG
);
547 FreeConnectionLookupMemory ();
548 IncrementUndoSerialNumber ();
553 netlist_find_cb (GtkWidget
* widget
, gpointer data
)
560 name
= selected_net
->Name
+ 2;
561 hid_actionl ("connection", "reset", NULL
);
562 hid_actionl ("netlist", "find", name
, NULL
);
566 netlist_rip_up_cb (GtkWidget
* widget
, gpointer data
)
571 netlist_find_cb(widget
, data
);
573 VISIBLELINE_LOOP (PCB
->Data
);
575 if (TEST_FLAG (FOUNDFLAG
, line
) && !TEST_FLAG (LOCKFLAG
, line
))
576 RemoveObject (LINE_TYPE
, layer
, line
, line
);
580 VISIBLEARC_LOOP (PCB
->Data
);
582 if (TEST_FLAG (FOUNDFLAG
, arc
) && !TEST_FLAG (LOCKFLAG
, arc
))
583 RemoveObject (ARC_TYPE
, layer
, arc
, arc
);
588 VIA_LOOP (PCB
->Data
);
590 if (TEST_FLAG (FOUNDFLAG
, via
) && !TEST_FLAG (LOCKFLAG
, via
))
591 RemoveObject (VIA_TYPE
, via
, via
, via
);
599 LibraryEntryType
*ret_val
;
600 LibraryMenuType
*node_net
;
601 const gchar
*node_name
;
603 } node_get_node_from_name_state
;
606 node_get_node_from_name_helper (GtkTreeModel
*model
, GtkTreePath
*path
,
607 GtkTreeIter
*iter
, gpointer data
)
609 LibraryMenuType
*net
;
610 LibraryEntryType
*node
;
611 node_get_node_from_name_state
*state
= data
;
613 gtk_tree_model_get (net_model
, iter
, NET_LIBRARY_COLUMN
, &net
, -1);
614 /* Ignore non-nets (category headers) */
618 /* Look for the node name in this net. */
619 for (node
= net
->Entry
; node
- net
->Entry
< net
->EntryN
; node
++)
620 if (node
->ListEntry
&& !strcmp (state
->node_name
, node
->ListEntry
))
622 state
->node_net
= net
;
623 state
->ret_val
= node
;
632 node_get_node_from_name (gchar
* node_name
, LibraryMenuType
** node_net
)
634 node_get_node_from_name_state state
;
639 /* Have to force the netlist window created because we need the treeview
640 | models constructed to do the search.
642 ghid_netlist_window_create (gport
);
644 /* Now walk through node entries of each net in the net model looking for
648 state
.node_name
= node_name
;
649 gtk_tree_model_foreach (net_model
, node_get_node_from_name_helper
, &state
);
653 *node_net
= state
.node_net
;
654 return state
.ret_val
;
660 /* ---------- Manage the GUI treeview of the data models -----------
663 netlist_window_configure_event_cb (GtkWidget
* widget
, GdkEventConfigure
* ev
,
666 GtkAllocation allocation
;
668 gtk_widget_get_allocation (widget
, &allocation
);
669 ghidgui
->netlist_window_height
= allocation
.height
;
670 ghidgui
->config_modified
= TRUE
;
675 netlist_close_cb (GtkWidget
* widget
, gpointer data
)
677 gtk_widget_destroy (netlist_window
);
679 netlist_window
= NULL
;
681 /* For now, we are the only consumer of this API, so we can just do this */
682 ghid_cancel_lead_user ();
687 netlist_destroy_cb (GtkWidget
* widget
, GHidPort
* out
)
690 netlist_window
= NULL
;
694 ghid_netlist_window_create (GHidPort
* out
)
696 GtkWidget
*vbox
, *hbox
, *button
, *label
, *sep
;
697 GtkTreeView
*treeview
;
699 GtkCellRenderer
*renderer
;
700 GtkTreeViewColumn
*column
;
705 netlist_window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
706 g_signal_connect (G_OBJECT (netlist_window
), "destroy",
707 G_CALLBACK (netlist_destroy_cb
), out
);
708 gtk_window_set_title (GTK_WINDOW (netlist_window
), _("PCB Netlist"));
709 gtk_window_set_wmclass (GTK_WINDOW (netlist_window
), "PCB_Netlist", "PCB");
710 g_signal_connect (G_OBJECT (netlist_window
), "configure_event",
711 G_CALLBACK (netlist_window_configure_event_cb
), NULL
);
712 gtk_window_set_default_size (GTK_WINDOW (netlist_window
),
713 -1, ghidgui
->netlist_window_height
);
715 gtk_container_set_border_width (GTK_CONTAINER (netlist_window
), 2);
717 vbox
= gtk_vbox_new (FALSE
, 4);
718 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 6);
719 gtk_container_add (GTK_CONTAINER (netlist_window
), vbox
);
720 hbox
= gtk_hbox_new (FALSE
, 8);
721 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, TRUE
, TRUE
, 4);
724 model
= net_model_create ();
725 treeview
= GTK_TREE_VIEW (gtk_tree_view_new_with_model (model
));
727 net_treeview
= treeview
;
728 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (net_model
),
729 NET_NAME_COLUMN
, GTK_SORT_ASCENDING
);
731 gtk_tree_view_set_rules_hint (treeview
, FALSE
);
732 g_object_set (treeview
, "enable-tree-lines", TRUE
, NULL
);
734 renderer
= gtk_cell_renderer_text_new ();
735 gtk_tree_view_insert_column_with_attributes (treeview
, -1, _(" "),
737 "text", NET_ENABLED_COLUMN
,
740 renderer
= gtk_cell_renderer_text_new ();
741 column
= gtk_tree_view_column_new_with_attributes (_("Net Name"),
743 "text", NET_NAME_COLUMN
, NULL
);
744 gtk_tree_view_insert_column (treeview
, column
, -1);
745 gtk_tree_view_set_expander_column (treeview
, column
);
747 /* TODO: dont expand all, but record expanded states when window is
748 | destroyed and restore state here.
750 gtk_tree_view_expand_all (treeview
);
752 ghid_scrolled_selection (treeview
, hbox
,
753 GTK_SELECTION_SINGLE
,
754 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
,
755 net_selection_changed_cb
, NULL
);
757 /* Connect to the double click event.
759 g_signal_connect (G_OBJECT (treeview
), "row-activated",
760 G_CALLBACK (net_selection_double_click_cb
), NULL
);
764 /* Create the elements treeview and wait for a callback to populate it.
766 treeview
= GTK_TREE_VIEW (gtk_tree_view_new ());
767 node_treeview
= treeview
;
769 gtk_tree_view_set_rules_hint (treeview
, FALSE
);
771 renderer
= gtk_cell_renderer_text_new ();
772 gtk_tree_view_insert_column_with_attributes (treeview
, -1, _("Nodes"),
774 "text", NODE_NAME_COLUMN
,
777 ghid_scrolled_selection (treeview
, hbox
,
778 GTK_SELECTION_SINGLE
,
779 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
,
780 node_selection_changed_cb
, NULL
);
782 hbox
= gtk_hbox_new (FALSE
, 0);
783 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 0);
784 label
= gtk_label_new (_("Operations on selected 'Net Name':"));
785 gtk_box_pack_start (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 4);
786 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
788 hbox
= gtk_hbox_new (FALSE
, 0);
789 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 4);
791 button
= gtk_button_new_with_label (_("Select"));
792 gtk_box_pack_start (GTK_BOX (hbox
), button
, FALSE
, FALSE
, 0);
793 g_signal_connect (G_OBJECT (button
), "clicked",
794 G_CALLBACK (netlist_select_cb
), GINT_TO_POINTER (1));
796 button
= gtk_button_new_with_label (_("Unselect"));
797 gtk_box_pack_start (GTK_BOX (hbox
), button
, FALSE
, FALSE
, 0);
798 g_signal_connect (G_OBJECT (button
), "clicked",
799 G_CALLBACK (netlist_select_cb
), GINT_TO_POINTER (0));
801 button
= gtk_button_new_with_label (_("Find"));
802 gtk_box_pack_start (GTK_BOX (hbox
), button
, FALSE
, FALSE
, 0);
803 g_signal_connect (G_OBJECT (button
), "clicked",
804 G_CALLBACK (netlist_find_cb
), GINT_TO_POINTER (0));
806 button
= gtk_button_new_with_label (_("Rip Up"));
807 gtk_box_pack_start (GTK_BOX (hbox
), button
, FALSE
, FALSE
, 0);
808 g_signal_connect (G_OBJECT (button
), "clicked",
809 G_CALLBACK (netlist_rip_up_cb
), GINT_TO_POINTER (0));
811 ghid_check_button_connected (vbox
, &disable_all_button
, FALSE
, TRUE
, FALSE
,
812 FALSE
, 0, netlist_disable_all_cb
, NULL
,
813 _("Disable all nets for adding rats"));
815 sep
= gtk_hseparator_new ();
816 gtk_box_pack_start (GTK_BOX (vbox
), sep
, FALSE
, FALSE
, 3);
818 hbox
= gtk_hbutton_box_new ();
819 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox
), GTK_BUTTONBOX_END
);
820 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 4);
821 button
= gtk_button_new_from_stock (GTK_STOCK_CLOSE
);
822 g_signal_connect (G_OBJECT (button
), "clicked",
823 G_CALLBACK (netlist_close_cb
), NULL
);
824 gtk_box_pack_start (GTK_BOX (hbox
), button
, TRUE
, TRUE
, 0);
827 gtk_widget_realize (netlist_window
);
828 if (Settings
.AutoPlace
)
829 gtk_window_move (GTK_WINDOW (netlist_window
), 10, 10);
834 ghid_netlist_window_show (GHidPort
* out
, gboolean raise
)
836 ghid_netlist_window_create (out
);
837 gtk_widget_show_all (netlist_window
);
838 ghid_netlist_window_update (TRUE
);
840 gtk_window_present(GTK_WINDOW(netlist_window
));
844 gboolean enabled_only
;
846 LibraryMenuType
*found_net
;
851 hunt_named_node (GtkTreeModel
*model
, GtkTreePath
*path
,
852 GtkTreeIter
*iter
, gpointer data
)
854 struct ggnfnn_task
*task
= (struct ggnfnn_task
*)data
;
855 LibraryMenuType
*net
;
856 LibraryEntryType
*node
;
859 gboolean is_disabled
;
861 /* We only want to inspect leaf nodes in the tree */
862 if (gtk_tree_model_iter_has_child (model
, iter
))
865 gtk_tree_model_get (model
, iter
, NET_LIBRARY_COLUMN
, &net
, -1);
866 gtk_tree_model_get (model
, iter
, NET_ENABLED_COLUMN
, &str
, -1);
867 is_disabled
= !strcmp (str
, "*");
870 /* Don't check net nodes of disabled nets. */
871 if (task
->enabled_only
&& is_disabled
)
874 /* Look for the node name in this net. */
875 for (j
= net
->EntryN
, node
= net
->Entry
; j
; j
--, node
++)
876 if (node
->ListEntry
&& !strcmp (task
->node_name
, node
->ListEntry
))
878 task
->found_net
= net
;
887 ghid_get_net_from_node_name (gchar
* node_name
, gboolean enabled_only
)
890 struct ggnfnn_task task
;
895 /* Have to force the netlist window created because we need the treeview
896 | models constructed so we can find the LibraryMenuType pointer the
899 ghid_netlist_window_create (gport
);
901 /* If no netlist is loaded the window doesn't appear. */
902 if (netlist_window
== NULL
)
905 task
.enabled_only
= enabled_only
;
906 task
.node_name
= node_name
;
907 task
.found_net
= NULL
;
909 /* Now walk through node entries of each net in the net model looking for
912 gtk_tree_model_foreach (net_model
, hunt_named_node
, &task
);
914 /* We are asked to highlight the found net if enabled_only is TRUE.
915 | Set holdoff TRUE since this is just a highlight and user is not
916 | expecting normal select action to happen? Or should the node
917 | treeview also get updated? Original PCB code just tries to highlight.
919 if (task
.found_net
&& enabled_only
)
921 selection_holdoff
= TRUE
;
922 path
= gtk_tree_model_get_path (net_model
, &task
.iter
);
923 gtk_tree_view_scroll_to_cell (net_treeview
, path
, NULL
, TRUE
, 0.5, 0.5);
924 gtk_tree_selection_select_path (gtk_tree_view_get_selection
925 (net_treeview
), path
);
926 selection_holdoff
= FALSE
;
928 return task
.found_net
;
931 /* PCB LookupConnection code in find.c calls this if it wants a node
932 | and its net highlighted.
935 ghid_netlist_highlight_node (gchar
* node_name
)
939 LibraryMenuType
*net
;
945 if ((net
= ghid_get_net_from_node_name (node_name
, TRUE
)) == NULL
)
948 /* We've found the net containing the node, so update the node treeview
949 | to contain the nodes from the net. Then we have to find the node
950 | in the new node model so we can highlight it.
952 node_model_update (net
);
954 if (gtk_tree_model_get_iter_first (node_model
, &iter
))
957 gtk_tree_model_get (node_model
, &iter
, NODE_NAME_COLUMN
, &name
, -1);
959 if (!strcmp (node_name
, name
))
960 { /* found it, so highlight it */
961 selection_holdoff
= TRUE
;
963 path
= gtk_tree_model_get_path (node_model
, &iter
);
964 gtk_tree_view_scroll_to_cell (node_treeview
, path
, NULL
,
966 gtk_tree_selection_select_path (gtk_tree_view_get_selection
967 (node_treeview
), path
);
968 selection_holdoff
= FALSE
;
972 while (gtk_tree_model_iter_next (node_model
, &iter
));
975 /* If code in PCB should change the netlist, call this to update
976 | what's in the netlist window.
979 ghid_netlist_window_update (gboolean init_nodes
)
983 /* Make sure there is something to update */
984 ghid_netlist_window_create (gport
);
987 net_model
= net_model_create ();
988 gtk_tree_view_set_model (net_treeview
, net_model
);
989 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (net_model
),
990 NET_NAME_COLUMN
, GTK_SORT_ASCENDING
);
993 gtk_tree_store_clear (GTK_TREE_STORE (model
));
994 g_object_unref (model
);
999 /* XXX Check if the select callback does this for us */
1001 node_model_update ((&PCB
->NetlistLib
)->Menu
);
1005 GhidNetlistChanged (int argc
, char **argv
, Coord x
, Coord y
)
1007 /* XXX: We get called before the GUI is up when
1008 * exporting from the command-line. */
1009 if (ghidgui
== NULL
|| !ghidgui
->is_up
)
1012 /* There is no need to update if the netlist window isn't open */
1013 if (netlist_window
== NULL
)
1016 loading_new_netlist
= TRUE
;
1017 ghid_netlist_window_update (TRUE
);
1018 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (disable_all_button
),
1020 loading_new_netlist
= FALSE
;
1024 static const char netlistshow_syntax
[] =
1025 "NetlistShow(pinname|netname)";
1027 static const char netlistshow_help
[] =
1028 "Selects the given pinname or netname in the netlist window. Does not \
1029 show the window if it isn't already shown.";
1032 GhidNetlistShow (int argc
, char **argv
, Coord x
, Coord y
)
1034 ghid_netlist_window_create (gport
);
1036 ghid_netlist_highlight_node(argv
[0]);
1040 static const char netlistpresent_syntax
[] =
1043 static const char netlistpresent_help
[] =
1044 "Presents the netlist window.";
1047 GhidNetlistPresent (int argc
, char **argv
, Coord x
, Coord y
)
1049 ghid_netlist_window_show (gport
, TRUE
);
1053 HID_Action ghid_netlist_action_list
[] = {
1054 {"NetlistChanged", 0, GhidNetlistChanged
,
1055 netlistchanged_help
, netlistchanged_syntax
},
1056 {"NetlistShow", 0, GhidNetlistShow
,
1057 netlistshow_help
, netlistshow_syntax
},
1058 {"NetlistPresent", 0, GhidNetlistPresent
,
1059 netlistpresent_help
, netlistpresent_syntax
}
1063 REGISTER_ACTIONS (ghid_netlist_action_list
)