1 /*! \file <gtk-pcb-route-style-selector.c>
2  *  \brief Implementation of GHidRouteStyleSelector widget
3  *  \par Description
4  *  Please write description here.
5  */
6 
7 #include <glib.h>
8 #include <glib-object.h>
9 #include <gdk/gdkkeysyms.h>
10 #include <gtk/gtk.h>
11 
12 #include "global.h"
13 #include "gtkhid.h"
14 #include "gui.h"
15 #include "pcb-printf.h"
16 
17 #include "ghid-route-style-selector.h"
18 
19 /* Forward dec'ls */
20 struct _route_style;
21 struct _route_style *ghid_route_style_selector_real_add_route_style
22   (GHidRouteStyleSelector *, RouteStyleType *, gboolean temp);
23 static void ghid_route_style_selector_finalize (GObject *object);
24 
25 /*! \brief Global action creation counter */
26 static gint action_count;
27 
28 /*! \brief Signals exposed by the widget */
29 enum {
30   SELECT_STYLE_SIGNAL,
31   STYLE_EDITED_SIGNAL,
32   LAST_SIGNAL
33 };
34 
35 /*! \brief Columns used for internal data store */
36 enum {
37   TEXT_COL,
38   DATA_COL,
39   N_COLS
40 };
41 
42 static GtkVBox *ghid_route_style_selector_parent_class;
43 static guint ghid_route_style_selector_signals[LAST_SIGNAL] = { 0 };
44 
45 struct _GHidRouteStyleSelector
46 {
47   GtkVBox parent;
48 
49   GSList *button_radio_group;
50   GSList *action_radio_group;
51   GtkWidget *edit_button;
52 
53   GtkActionGroup *action_group;
54   GtkAccelGroup *accel_group;
55   GtkRadioAction *null_action;
56   GtkWidget *null_button;
57   gint shortcut_key_idx;
58 
59   GtkListStore *model;
60   struct _route_style *active_style;
61 };
62 
63 struct _GHidRouteStyleSelectorClass
64 {
65   GtkVBoxClass parent_class;
66 
67   void (* select_style) (GHidRouteStyleSelector *, RouteStyleType *);
68   void (* style_edited) (GHidRouteStyleSelector *, gboolean);
69 };
70 
71 struct _route_style
72 {
73   gboolean temporary;
74   GtkRadioAction *action;
75   GtkWidget *button;
76   GtkWidget *menu_item;
77   GtkTreeRowReference *rref;
78   RouteStyleType *rst;
79   gulong sig_id;
80 };
81 
82 static void
init_radio_groups(GHidRouteStyleSelector * rss)83 init_radio_groups (GHidRouteStyleSelector *rss)
84 {
85   gtk_radio_action_set_group (rss->null_action, rss->action_radio_group);
86   rss->action_radio_group = gtk_radio_action_get_group (rss->null_action);
87   gtk_radio_button_set_group (GTK_RADIO_BUTTON (rss->null_button),
88                               rss->button_radio_group);
89   rss->button_radio_group = gtk_radio_button_get_group
90                               (GTK_RADIO_BUTTON (rss->null_button));
91 }
92 
93 /* SIGNAL HANDLERS */
94 /*! \brief Callback for user selection of a route style */
95 static void
radio_select_cb(GtkToggleAction * action,GHidRouteStyleSelector * rss)96 radio_select_cb (GtkToggleAction *action, GHidRouteStyleSelector *rss)
97 {
98   rss->active_style = g_object_get_data (G_OBJECT (action), "route-style");
99   if (gtk_toggle_action_get_active (action))
100     g_signal_emit (rss, ghid_route_style_selector_signals[SELECT_STYLE_SIGNAL],
101                    0, rss->active_style->rst);
102 }
103 
104 /* EDIT DIALOG */
105 struct _dialog
106 {
107   GHidRouteStyleSelector *rss;
108   GtkWidget *name_entry;
109   GtkWidget *line_entry;
110   GtkWidget *via_hole_entry;
111   GtkWidget *via_size_entry;
112   GtkWidget *clearance_entry;
113   GtkWidget *mask_aperture_entry;
114 };
115 
116 /*! \brief Callback for dialog box's combobox being changed
117  *  \par Function Description
118  *  When a different layer is selected, this function loads
119  *  that layer's data into the dialog. Alternately, if the
120  *  "New layer" option is selected, this loads a new name
121  *  but no other data.
122  *
123  *  \param [in] combo   The combobox
124  *  \param [in] dialog  The rest of the widgets to be updated
125  */
126 static void
dialog_style_changed_cb(GtkComboBox * combo,struct _dialog * dialog)127 dialog_style_changed_cb (GtkComboBox *combo, struct _dialog *dialog)
128 {
129   struct _route_style *style;
130   GtkTreeIter iter;
131   gtk_combo_box_get_active_iter (combo, &iter);
132   gtk_tree_model_get (GTK_TREE_MODEL (dialog->rss->model),
133                       &iter, DATA_COL, &style, -1);
134 
135   if (style == NULL)
136     {
137       gtk_entry_set_text (GTK_ENTRY (dialog->name_entry),
138                           _("New Style"));
139       return;
140     }
141 
142   gtk_entry_set_text (GTK_ENTRY (dialog->name_entry), style->rst->Name);
143   ghid_coord_entry_set_value (GHID_COORD_ENTRY (dialog->line_entry),
144                               style->rst->Thick);
145   ghid_coord_entry_set_value (GHID_COORD_ENTRY (dialog->via_hole_entry),
146                               style->rst->Hole);
147   ghid_coord_entry_set_value (GHID_COORD_ENTRY (dialog->via_size_entry),
148                               style->rst->Diameter);
149   ghid_coord_entry_set_value (GHID_COORD_ENTRY (dialog->clearance_entry),
150                               style->rst->Keepaway);
151   ghid_coord_entry_set_value (GHID_COORD_ENTRY (dialog->mask_aperture_entry),
152                               style->rst->ViaMask);
153 
154 }
155 
156 /* \brief Helper for edit_button_cb */
157 static void
_table_attach(GtkWidget * table,gint row,const gchar * label,GtkWidget ** entry,Coord min,Coord max)158 _table_attach (GtkWidget *table, gint row, const gchar *label,
159                GtkWidget **entry, Coord min, Coord max)
160 {
161   GtkWidget *label_w = gtk_label_new (label);
162   gtk_misc_set_alignment (GTK_MISC (label_w), 1.0, 0.5);
163 
164   *entry = ghid_coord_entry_new (min, max, 0, Settings.grid_unit, CE_SMALL);
165   gtk_table_attach (GTK_TABLE (table), label_w, 0, 1, row, row + 1,
166                     GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
167   gtk_table_attach (GTK_TABLE (table), *entry, 1, 2, row, row + 1,
168                     GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
169 }
170 
171 /* \brief Builds and runs the "edit route styles" dialog */
172 void
ghid_route_style_selector_edit_dialog(GHidRouteStyleSelector * rss)173 ghid_route_style_selector_edit_dialog (GHidRouteStyleSelector *rss)
174 {
175   GtkTreePath *path;
176   GtkTreeIter iter, tmp_iter;
177   struct _dialog dialog_data;
178   GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
179   GtkWidget *window = gtk_widget_get_toplevel (GTK_WIDGET (rss));
180   GtkWidget *dialog;
181   GtkWidget *content_area;
182   GtkWidget *vbox, *hbox, *sub_vbox, *table;
183   GtkWidget *label, *select_box, *check_box;
184 
185   /* Build dialog */
186   dialog = gtk_dialog_new_with_buttons (_("Edit Route Styles"),
187                                         GTK_WINDOW (window),
188                                         GTK_DIALOG_DESTROY_WITH_PARENT,
189                                         GTK_STOCK_CANCEL, GTK_RESPONSE_NONE,
190                                         GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
191 
192   label = gtk_label_new (_("Edit Style:"));
193   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
194 
195   select_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (rss->model));
196   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (select_box), renderer, TRUE);
197   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(select_box), renderer,
198                                   "text", TEXT_COL, NULL);
199 
200   content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
201 
202   hbox = gtk_hbox_new (FALSE, 4);
203   gtk_box_pack_start (GTK_BOX (content_area), hbox, TRUE, TRUE, 4);
204   vbox = gtk_vbox_new (FALSE, 4);
205   gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 4);
206 
207   hbox = gtk_hbox_new (FALSE, 4);
208   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 4);
209   gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
210   gtk_box_pack_start (GTK_BOX (hbox), select_box, TRUE, TRUE, 0);
211 
212   sub_vbox = ghid_category_vbox (vbox, _("Route Style Data"),
213                                  4, 2, TRUE, TRUE);
214   table = gtk_table_new (6, 2, FALSE);
215   gtk_box_pack_start (GTK_BOX (sub_vbox), table, TRUE, TRUE, 4);
216   label = gtk_label_new (_("Name:"));
217   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
218   dialog_data.name_entry = gtk_entry_new ();
219   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
220                     GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
221   gtk_table_attach (GTK_TABLE (table), dialog_data.name_entry, 1, 2, 0, 1,
222                     GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
223 
224   _table_attach (table, 1, _("Line width:"),
225                  &dialog_data.line_entry,
226                  MIN_LINESIZE, MAX_LINESIZE);
227   _table_attach (table, 2, _("Via hole size:"),
228                  &dialog_data.via_hole_entry,
229                  MIN_PINORVIAHOLE, MAX_PINORVIASIZE);
230   _table_attach (table, 3, _("Via ring size:"),
231                  &dialog_data.via_size_entry,
232                  MIN_PINORVIAHOLE, MAX_PINORVIASIZE);
233   _table_attach (table, 4, _("Clearance:"),
234                  &dialog_data.clearance_entry,
235                  MIN_LINESIZE, MAX_LINESIZE);
236   _table_attach (table, 5, _("Mask aperture:"),
237                  &dialog_data.mask_aperture_entry,
238                  0, MAX_LINESIZE);
239 
240   sub_vbox = ghid_category_vbox (vbox, _("Set as Default"),
241                                  4, 2, TRUE, TRUE);
242   check_box = gtk_check_button_new_with_label
243                 (_("Save route style settings as default"));
244   gtk_box_pack_start (GTK_BOX (sub_vbox), check_box, TRUE, TRUE, 0);
245 
246   /* Add "new style" option to list */
247   gtk_list_store_append (rss->model, &tmp_iter);
248   gtk_list_store_set (rss->model, &tmp_iter, TEXT_COL,
249                       _("New (this session only)"), DATA_COL, NULL, -1);
250 
251   /* Display dialog */
252   dialog_data.rss = rss;
253   path = gtk_tree_row_reference_get_path (rss->active_style->rref);
254   gtk_tree_model_get_iter (GTK_TREE_MODEL (rss->model), &iter, path);
255   g_signal_connect (G_OBJECT (select_box), "changed",
256                     G_CALLBACK (dialog_style_changed_cb), &dialog_data);
257   gtk_combo_box_set_active_iter (GTK_COMBO_BOX (select_box), &iter);
258   gtk_widget_show_all (dialog);
259   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
260     {
261       RouteStyleType *rst;
262       struct _route_style *style;
263       gboolean save;
264       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (select_box), &iter);
265       gtk_tree_model_get (GTK_TREE_MODEL (rss->model),
266                           &iter, DATA_COL, &style, -1);
267       if (style == NULL)
268         rst = g_malloc (sizeof *rst);
269       else
270         {
271           rst = style->rst;
272           free (rst->Name);
273         }
274 
275       rst->Name = StripWhiteSpaceAndDup
276                     (gtk_entry_get_text (GTK_ENTRY (dialog_data.name_entry)));
277       rst->Thick = ghid_coord_entry_get_value
278                      (GHID_COORD_ENTRY (dialog_data.line_entry));
279       rst->Hole = ghid_coord_entry_get_value
280                     (GHID_COORD_ENTRY (dialog_data.via_hole_entry));
281       rst->Diameter = ghid_coord_entry_get_value
282                         (GHID_COORD_ENTRY (dialog_data.via_size_entry));
283       rst->Keepaway = ghid_coord_entry_get_value
284                         (GHID_COORD_ENTRY (dialog_data.clearance_entry));
285       rst->ViaMask = ghid_coord_entry_get_value
286                         (GHID_COORD_ENTRY (dialog_data.mask_aperture_entry));
287       save = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_box));
288 
289       if (style == NULL)
290         style = ghid_route_style_selector_real_add_route_style
291                   (rss, rst, TRUE);
292       else
293         {
294           gtk_action_set_label (GTK_ACTION (style->action), rst->Name);
295           gtk_list_store_set (rss->model, &iter, TEXT_COL, rst->Name, -1);
296         }
297 
298       /* Cleanup */
299       gtk_widget_destroy (dialog);
300       gtk_list_store_remove (rss->model, &tmp_iter);
301       /* Emit change signals */
302       ghid_route_style_selector_select_style (rss, rst);
303       g_signal_emit
304         (rss, ghid_route_style_selector_signals[STYLE_EDITED_SIGNAL],
305          0, save);
306     }
307   else
308     {
309       gtk_widget_destroy (dialog);
310       gtk_list_store_remove (rss->model, &tmp_iter);
311     }
312 }
313 /* end EDIT DIALOG */
314 
315 static void
edit_button_cb(GtkButton * btn,GHidRouteStyleSelector * rss)316 edit_button_cb (GtkButton *btn, GHidRouteStyleSelector *rss)
317 {
318   ghid_route_style_selector_edit_dialog (rss);
319 }
320 
321 /* CONSTRUCTOR */
322 static void
ghid_route_style_selector_init(GHidRouteStyleSelector * rss)323 ghid_route_style_selector_init (GHidRouteStyleSelector *rss)
324 {
325 }
326 
327 static void
ghid_route_style_selector_class_init(GHidRouteStyleSelectorClass * klass)328 ghid_route_style_selector_class_init (GHidRouteStyleSelectorClass *klass)
329 {
330   GObjectClass *object_class = (GObjectClass *) klass;
331 
332   ghid_route_style_selector_parent_class = g_type_class_peek_parent (klass);
333 
334   ghid_route_style_selector_signals[SELECT_STYLE_SIGNAL] =
335     g_signal_new ("select-style",
336                   G_TYPE_FROM_CLASS (klass),
337                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
338                   G_STRUCT_OFFSET (GHidRouteStyleSelectorClass, select_style),
339                   NULL, NULL,
340                   g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE,
341                   1, G_TYPE_POINTER);
342   ghid_route_style_selector_signals[STYLE_EDITED_SIGNAL] =
343     g_signal_new ("style-edited",
344                   G_TYPE_FROM_CLASS (klass),
345                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
346                   G_STRUCT_OFFSET (GHidRouteStyleSelectorClass, style_edited),
347                   NULL, NULL,
348                   g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE,
349                   1, G_TYPE_BOOLEAN);
350 
351   object_class->finalize = ghid_route_style_selector_finalize;
352 }
353 
354 /*! \brief Clean up object before garbage collection
355  */
356 static void
ghid_route_style_selector_finalize(GObject * object)357 ghid_route_style_selector_finalize (GObject *object)
358 {
359   GHidRouteStyleSelector *rss = (GHidRouteStyleSelector *) object;
360 
361   ghid_route_style_selector_empty (rss);
362 
363   g_object_unref (rss->accel_group);
364   g_object_unref (rss->action_group);
365 
366   G_OBJECT_CLASS (ghid_route_style_selector_parent_class)->finalize (object);
367 }
368 
369 /* PUBLIC FUNCTIONS */
370 GType
ghid_route_style_selector_get_type(void)371 ghid_route_style_selector_get_type (void)
372 {
373   static GType rss_type = 0;
374 
375   if (!rss_type)
376     {
377       const GTypeInfo rss_info =
378       {
379 	sizeof (GHidRouteStyleSelectorClass),
380 	NULL, /* base_init */
381 	NULL, /* base_finalize */
382 	(GClassInitFunc) ghid_route_style_selector_class_init,
383 	NULL, /* class_finalize */
384 	NULL, /* class_data */
385 	sizeof (GHidRouteStyleSelector),
386 	0,    /* n_preallocs */
387 	(GInstanceInitFunc) ghid_route_style_selector_init,
388       };
389 
390       rss_type = g_type_register_static (GTK_TYPE_VBOX,
391                                          "GHidRouteStyleSelector",
392                                          &rss_info,
393                                          0);
394     }
395 
396   return rss_type;
397 }
398 
399 /*! \brief Create a new GHidRouteStyleSelector
400  *
401  *  \return a freshly-allocated GHidRouteStyleSelector.
402  */
403 GtkWidget *
ghid_route_style_selector_new()404 ghid_route_style_selector_new ()
405 {
406   GHidRouteStyleSelector *rss =
407     g_object_new (GHID_ROUTE_STYLE_SELECTOR_TYPE, NULL);
408 
409   rss->active_style = NULL;
410   rss->action_radio_group = NULL;
411   rss->button_radio_group = NULL;
412   rss->model = gtk_list_store_new (N_COLS, G_TYPE_STRING, G_TYPE_POINTER);
413 
414   rss->accel_group = gtk_accel_group_new ();
415   rss->action_group = gtk_action_group_new ("RouteStyleSelector");
416   rss->null_action = gtk_radio_action_new ("RouteStyleXX", "",
417                                            NULL, NULL, -1);
418   rss->null_button = gtk_radio_button_new (rss->button_radio_group);
419   init_radio_groups (rss);
420   gtk_activatable_set_related_action (GTK_ACTIVATABLE (rss->null_button),
421                                       GTK_ACTION (rss->null_action));
422   rss->shortcut_key_idx = 1;
423 
424   /* Create edit button */
425   rss->edit_button = gtk_button_new_with_label (_("Route Styles"));
426   g_signal_connect (G_OBJECT (rss->edit_button), "clicked",
427                     G_CALLBACK (edit_button_cb), rss);
428   gtk_box_pack_start (GTK_BOX (rss), rss->edit_button, FALSE, FALSE, 0);
429 
430   return GTK_WIDGET (rss);
431 }
432 
433 /*! \brief Create a new GHidRouteStyleSelector
434  *
435  *  \param [in] rss     The selector to be acted on
436  *  \param [in] data    PCB's route style object that will be edited
437  *  \param [in] temp    Whether the style is "real" or session-only
438  */
439 struct _route_style *
ghid_route_style_selector_real_add_route_style(GHidRouteStyleSelector * rss,RouteStyleType * data,gboolean temp)440 ghid_route_style_selector_real_add_route_style (GHidRouteStyleSelector *rss,
441                                                 RouteStyleType *data,
442                                                 gboolean temp)
443 {
444   GtkTreeIter iter;
445   GtkTreePath *path;
446   gchar *action_name = g_strdup_printf ("RouteStyle%d", action_count);
447   struct _route_style *new_style = g_malloc (sizeof (*new_style));
448 
449   /* Key the route style data with the RouteStyleType it controls */
450   new_style->rst = data;
451   new_style->temporary = temp;
452   new_style->action = gtk_radio_action_new (action_name, data->Name,
453                                             NULL, NULL, action_count);
454   gtk_radio_action_set_group (new_style->action, rss->action_radio_group);
455   rss->action_radio_group = gtk_radio_action_get_group (new_style->action);
456   new_style->button = gtk_radio_button_new (rss->button_radio_group);
457   rss->button_radio_group = gtk_radio_button_get_group
458                               (GTK_RADIO_BUTTON (new_style->button));
459   gtk_activatable_set_related_action (GTK_ACTIVATABLE (new_style->button),
460                                       GTK_ACTION (new_style->action));
461 
462   gtk_list_store_append (rss->model, &iter);
463   gtk_list_store_set (rss->model, &iter, TEXT_COL, data->Name,
464                       DATA_COL, new_style, -1);
465   path = gtk_tree_model_get_path (GTK_TREE_MODEL (rss->model), &iter);
466   new_style->rref = gtk_tree_row_reference_new (GTK_TREE_MODEL (rss->model),
467                                                 path);
468   gtk_tree_path_free (path);
469 
470   /* Setup accelerator */
471   if (rss->shortcut_key_idx < 12)
472     {
473       gchar *accel = g_strdup_printf ("<Ctrl>F%d", rss->shortcut_key_idx);
474       gtk_action_set_accel_group (GTK_ACTION (new_style->action),
475                                   rss->accel_group);
476       gtk_action_group_add_action_with_accel (rss->action_group,
477                                               GTK_ACTION (new_style->action),
478                                               accel);
479       g_free (accel);
480       ++rss->shortcut_key_idx;
481     }
482 
483   /* Hookup and install radio button */
484   g_object_set_data (G_OBJECT (new_style->action), "route-style", new_style);
485   new_style->sig_id = g_signal_connect (G_OBJECT (new_style->action),
486                                         "activate",
487                                         G_CALLBACK (radio_select_cb), rss);
488   gtk_box_pack_start (GTK_BOX (rss), new_style->button, FALSE, FALSE, 0);
489 
490   g_free (action_name);
491   ++action_count;
492   return new_style;
493 }
494 
495 /*! \brief Adds a route style to a GHidRouteStyleSelector
496  *  \par Function Description
497  *  Adds a new route style to be managed by this selector. Note
498  *  that the route style object passed to this function will be
499  *  updated directly.
500  *
501  *  \param [in] rss     The selector to be acted on
502  *  \param [in] data    PCB's route style object describing the style
503  */
504 void
ghid_route_style_selector_add_route_style(GHidRouteStyleSelector * rss,RouteStyleType * data)505 ghid_route_style_selector_add_route_style (GHidRouteStyleSelector *rss,
506                                            RouteStyleType *data)
507 {
508   ghid_route_style_selector_real_add_route_style (rss, data, FALSE);
509 }
510 
511 
512 /*! \brief Install the "Route Style" menu items
513  *  \par Function Description
514  *  Takes a menu shell and installs menu items for route style selection in
515  *  the shell, at the given position. Note that we aren't really guaranteed
516  *  the ordering of these items, since our internal data structure is a hash
517  *  table. This shouldn't be a problem.
518  *
519  *  \param [in] rss     The selector to be acted on
520  *  \param [in] shell   The menu to install the items in
521  *  \param [in] pos     The position in the menu to install items
522  *
523  *  \return the number of items installed
524  */
525 gint
ghid_route_style_selector_install_items(GHidRouteStyleSelector * rss,GtkMenuShell * shell,gint pos)526 ghid_route_style_selector_install_items (GHidRouteStyleSelector *rss,
527                                          GtkMenuShell *shell, gint pos)
528 {
529   gint n = 0;
530   GtkTreeIter iter;
531 
532   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rss->model), &iter);
533   do
534     {
535       GtkAction *action;
536       struct _route_style *style;
537 
538       gtk_tree_model_get (GTK_TREE_MODEL (rss->model),
539                           &iter, DATA_COL, &style, -1);
540       action = GTK_ACTION (style->action);
541       style->menu_item = gtk_action_create_menu_item (action);
542       gtk_menu_shell_insert (shell, style->menu_item, pos + n);
543       ++n;
544     }
545   while (gtk_tree_model_iter_next (GTK_TREE_MODEL (rss->model), &iter));
546 
547   return n;
548 }
549 
550 /*! \brief Selects a route style and emits a select-style signal
551  *
552  *  \param [in] rss  The selector to be acted on
553  *  \param [in] rst  The style to select
554  *
555  *  \return TRUE if a style was selected, FALSE otherwise
556  */
557 gboolean
ghid_route_style_selector_select_style(GHidRouteStyleSelector * rss,RouteStyleType * rst)558 ghid_route_style_selector_select_style (GHidRouteStyleSelector *rss,
559                                         RouteStyleType *rst)
560 {
561   GtkTreeIter iter;
562   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rss->model), &iter);
563   do
564     {
565       struct _route_style *style;
566       gtk_tree_model_get (GTK_TREE_MODEL (rss->model),
567                           &iter, DATA_COL, &style, -1);
568       if (style->rst == rst)
569         {
570           g_signal_handler_block (G_OBJECT (style->action), style->sig_id);
571           gtk_toggle_action_set_active
572             (GTK_TOGGLE_ACTION (style->action), TRUE);
573           g_signal_handler_unblock (G_OBJECT (style->action), style->sig_id);
574           rss->active_style = style;
575           g_signal_emit
576             (rss, ghid_route_style_selector_signals[SELECT_STYLE_SIGNAL],
577              0, rss->active_style->rst);
578           return TRUE;
579         }
580     }
581   while (gtk_tree_model_iter_next (GTK_TREE_MODEL (rss->model), &iter));
582 
583   return FALSE;
584 }
585 
586 /*! \brief Returns the GtkAccelGroup of a route style selector
587  *  \par Function Description
588  *
589  *  \param [in] rss            The selector to be acted on
590  *
591  *  \return the accel group of the selector
592  */
593 GtkAccelGroup *
ghid_route_style_selector_get_accel_group(GHidRouteStyleSelector * rss)594 ghid_route_style_selector_get_accel_group (GHidRouteStyleSelector *rss)
595 {
596   return rss->accel_group;
597 }
598 
599 /*! \brief Sets a GHidRouteStyleSelector selection to given values
600  *  \par Function Description
601  *  Given the line thickness, via size and clearance values of a route
602  *  style, this function selects a route style with the given values.
603  *  If there is no such style registered with the selector, nothing
604  *  will happen. This function does not emit any signals.
605  *
606  *  \param [in] rss       The selector to be acted on
607  *  \param [in] Thick     Coord to match selection to
608  *  \param [in] Hole      Coord to match selection to
609  *  \param [in] Diameter  Coord to match selection to
610  *  \param [in] Keepaway  Coord to match selection to
611  *  \param [in] ViaMask   Coord to match selection to
612  */
613 void
ghid_route_style_selector_sync(GHidRouteStyleSelector * rss,Coord Thick,Coord Hole,Coord Diameter,Coord Keepaway,Coord ViaMask)614 ghid_route_style_selector_sync (GHidRouteStyleSelector *rss,
615                                 Coord Thick, Coord Hole,
616                                 Coord Diameter, Coord Keepaway, Coord ViaMask)
617 {
618   gboolean found_match = FALSE;
619   GtkTreeIter iter;
620   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rss->model), &iter);
621   do
622     {
623       struct _route_style *style;
624       gtk_tree_model_get (GTK_TREE_MODEL (rss->model),
625                           &iter, DATA_COL, &style, -1);
626       if (style->rst->Thick == Thick &&
627           style->rst->Hole == Hole &&
628           style->rst->Diameter == Diameter &&
629           style->rst->Keepaway == Keepaway &&
630           style->rst->ViaMask == ViaMask)
631         {
632           g_signal_handler_block (G_OBJECT (style->action), style->sig_id);
633           gtk_toggle_action_set_active
634             (GTK_TOGGLE_ACTION (style->action), TRUE);
635           g_signal_handler_unblock (G_OBJECT (style->action), style->sig_id);
636           rss->active_style = style;
637           found_match = TRUE;
638         }
639     }
640   while (gtk_tree_model_iter_next (GTK_TREE_MODEL (rss->model), &iter));
641 
642   if (!found_match)
643     gtk_radio_action_set_current_value (rss->null_action, -1);
644 }
645 
646 /*! \brief Removes all styles from a route style selector */
647 void
ghid_route_style_selector_empty(GHidRouteStyleSelector * rss)648 ghid_route_style_selector_empty (GHidRouteStyleSelector *rss)
649 {
650   GtkTreeIter iter;
651   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rss->model), &iter);
652   do
653     {
654       struct _route_style *rsdata;
655       gtk_tree_model_get (GTK_TREE_MODEL (rss->model),
656                           &iter, DATA_COL, &rsdata, -1);
657       if (rsdata->action)
658         {
659           gtk_action_group_remove_action (rss->action_group,
660                                 GTK_ACTION (rsdata->action));
661           g_object_unref (G_OBJECT (rsdata->action));
662         }
663       if (rsdata->button)
664         gtk_widget_destroy (GTK_WIDGET (rsdata->button));
665       if (rsdata->menu_item)
666         gtk_widget_destroy (GTK_WIDGET (rsdata->menu_item));
667       if (rsdata->temporary)
668         {
669           free (rsdata->rst->Name);
670           g_free (rsdata->rst);
671         }
672       gtk_tree_row_reference_free (rsdata->rref);
673       free (rsdata);
674     }
675   while (gtk_list_store_remove (rss->model, &iter));
676   rss->action_radio_group = NULL;
677   rss->button_radio_group = NULL;
678   rss->shortcut_key_idx = 1;
679   init_radio_groups (rss);
680 }
681 
682