1 /*! \file <gtk-pcb-layer-selector.c>
2 * \brief Implementation of GHidLayerSelector widget
4 * This widget is the layer selector on the left side of the Gtk
5 * GUI. It also builds the relevant sections of the menu for layer
6 * selection and visibility toggling, and keeps these in sync.
10 #include <glib-object.h>
11 #include <gdk/gdkkeysyms.h>
16 #include "pcb-printf.h"
18 #include "ghid-layer-selector.h"
19 #include "ghid-cell-renderer-visibility.h"
21 #define INITIAL_ACTION_MAX 40
25 static void ghid_layer_selector_finalize (GObject
*object
);
26 static void menu_pick_cb (GtkRadioAction
*action
, struct _layer
*ldata
);
28 /*! \brief Signals exposed by the widget */
36 /*! \brief Columns used for internal data store */
50 static GtkTreeView
*ghid_layer_selector_parent_class
;
51 static guint ghid_layer_selector_signals
[LAST_SIGNAL
] = { 0 };
53 struct _GHidLayerSelector
57 GtkListStore
*list_store
;
58 GtkTreeSelection
*selection
;
59 GtkTreeViewColumn
*visibility_column
;
61 GtkActionGroup
*action_group
;
62 GtkAccelGroup
*accel_group
;
67 gboolean accel_available
[20];
69 gulong selection_changed_sig_id
;
72 struct _GHidLayerSelectorClass
74 GtkTreeViewClass parent_class
;
76 void (* select_layer
) (GHidLayerSelector
*, gint
);
77 void (* toggle_layer
) (GHidLayerSelector
*, gint
);
78 void (* rename_layer
) (GHidLayerSelector
*, gint
, gchar
*);
83 gint accel_index
; /* Index into ls->accel_available */
86 GtkToggleAction
*view_action
;
87 GtkRadioAction
*pick_action
;
88 GtkTreeRowReference
*rref
;
92 g_cclosure_user_marshal_VOID__INT_STRING (GClosure
*closure
,
93 GValue
*return_value G_GNUC_UNUSED
,
95 const GValue
*param_values
,
96 gpointer invocation_hint G_GNUC_UNUSED
,
97 gpointer marshal_data
)
99 typedef void (*GMarshalFunc_VOID__INT_STRING
) (gpointer data1
,
103 register GMarshalFunc_VOID__INT_STRING callback
;
104 register GCClosure
*cc
= (GCClosure
*) closure
;
105 register gpointer data1
, data2
;
107 g_return_if_fail (n_param_values
== 3);
109 if (G_CCLOSURE_SWAP_DATA (closure
))
111 data1
= closure
->data
;
112 data2
= g_value_peek_pointer (param_values
+ 0);
116 data1
= g_value_peek_pointer (param_values
+ 0);
117 data2
= closure
->data
;
119 callback
= (GMarshalFunc_VOID__INT_STRING
) (marshal_data
? marshal_data
: cc
->callback
);
122 g_value_get_int (param_values
+ 1),
123 (char *)g_value_get_string (param_values
+ 2),
127 /*! \brief Deletes the action and accelerator from a layer */
129 free_ldata (GHidLayerSelector
*ls
, struct _layer
*ldata
)
131 if (ldata
->pick_action
)
133 gtk_action_disconnect_accelerator
134 (GTK_ACTION (ldata
->pick_action
));
135 gtk_action_group_remove_action (ls
->action_group
,
136 GTK_ACTION (ldata
->pick_action
));
137 /* TODO: make this work without wrecking the radio action group
138 * g_object_unref (G_OBJECT (ldata->pick_action));
141 if (ldata
->view_action
)
143 gtk_action_disconnect_accelerator
144 (GTK_ACTION (ldata
->view_action
));
145 gtk_action_group_remove_action (ls
->action_group
,
146 GTK_ACTION (ldata
->view_action
));
147 g_object_unref (G_OBJECT (ldata
->view_action
));
149 gtk_tree_row_reference_free (ldata
->rref
);
150 if (ldata
->accel_index
>= 0)
151 ls
->accel_available
[ldata
->accel_index
] = TRUE
;
156 /*! \brief internal set-visibility function -- emits no signals */
158 set_visibility (GHidLayerSelector
*ls
, GtkTreeIter
*iter
,
159 struct _layer
*ldata
, gboolean state
)
161 gtk_list_store_set (ls
->list_store
, iter
, VISIBLE_COL
, state
, -1);
165 gtk_action_block_activate (GTK_ACTION (ldata
->view_action
));
166 gtk_check_menu_item_set_active
167 (GTK_CHECK_MENU_ITEM (ldata
->view_item
), state
);
168 gtk_action_unblock_activate (GTK_ACTION (ldata
->view_action
));
172 /*! \brief Flip the visibility state of a given layer
173 * \par Function Description
174 * Changes the internal toggle state and menu checkbox state
175 * of the layer pointed to by iter. Emits a toggle-layer signal.
177 * \param [in] ls The selector to be acted on
178 * \param [in] iter A GtkTreeIter pointed at the relevant layer
179 * \param [in] emit Whether or not to emit a signal
182 toggle_visibility (GHidLayerSelector
*ls
, GtkTreeIter
*iter
, gboolean emit
)
185 struct _layer
*ldata
;
187 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
), iter
,
188 USER_ID_COL
, &user_id
, VISIBLE_COL
, &toggle
,
189 STRUCT_COL
, &ldata
, -1);
190 set_visibility (ls
, iter
, ldata
, !toggle
);
192 g_signal_emit (ls
, ghid_layer_selector_signals
[TOGGLE_LAYER_SIGNAL
],
196 /*! \brief Decide if a GtkListStore entry is a layer or separator */
198 tree_view_separator_func (GtkTreeModel
*model
, GtkTreeIter
*iter
,
202 gtk_tree_model_get (model
, iter
, SEPARATOR_COL
, &ret_val
, -1);
206 /*! \brief Decide if a GtkListStore entry may be selected */
208 tree_selection_func (GtkTreeSelection
*selection
, GtkTreeModel
*model
,
209 GtkTreePath
*path
, gboolean selected
, gpointer data
)
213 if (gtk_tree_model_get_iter (model
, &iter
, path
))
216 gtk_tree_model_get (model
, &iter
, SELECTABLE_COL
, &selectable
, -1);
223 /* SIGNAL HANDLERS */
224 /*! \brief Callback for mouse-click: toggle visibility */
226 button_press_cb (GHidLayerSelector
*ls
, GdkEventButton
*event
)
228 /* Handle visibility independently to prevent changing the active
229 * layer, which will happen if we let this event propagate. */
230 GtkTreeViewColumn
*column
;
233 /* Ignore the synthetic presses caused by double and tripple clicks, and
234 * also ignore all but left-clicks
236 if (event
->type
!= GDK_BUTTON_PRESS
||
240 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (ls
),
242 &path
, &column
, NULL
, NULL
))
247 gtk_tree_model_get_iter (GTK_TREE_MODEL (ls
->list_store
), &iter
, path
);
248 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
), &iter
,
249 SELECTABLE_COL
, &selectable
,
250 SEPARATOR_COL
, &separator
, -1);
251 /* Toggle visibility for non-selectable layers no matter
252 * where you click. */
253 if (!separator
&& (column
== ls
->visibility_column
|| !selectable
))
255 toggle_visibility (ls
, &iter
, TRUE
);
262 /*! \brief Callback for layer selection change: sync menu, emit signal */
264 selection_changed_cb (GtkTreeSelection
*selection
, GHidLayerSelector
*ls
)
267 if (gtk_tree_selection_get_selected (selection
, NULL
, &iter
))
270 struct _layer
*ldata
;
271 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
), &iter
,
272 STRUCT_COL
, &ldata
, USER_ID_COL
, &user_id
, -1);
274 if (ldata
&& ldata
->pick_action
)
276 gtk_action_block_activate (GTK_ACTION (ldata
->pick_action
));
277 gtk_radio_action_set_current_value (ldata
->pick_action
, user_id
);
278 gtk_action_unblock_activate (GTK_ACTION (ldata
->pick_action
));
280 g_signal_emit (ls
, ghid_layer_selector_signals
[SELECT_LAYER_SIGNAL
],
285 /*! \brief Callback for when a layer name has been edited */
287 layer_name_editing_started_cb (GtkCellRenderer
*renderer
,
288 GtkCellEditable
*editable
,
292 /* When editing begins, we need to detach PCB's accelerators
293 * so they don't steal all the user's keystrokes.
295 * XXX: We should not have to do this within a simple widget,
297 * and this quick hack workaround breaks the widget's
298 * abstraction from the rest of the application :(
300 ghid_remove_accel_groups (GTK_WINDOW (gport
->top_window
), ghidgui
);
303 /*! \brief Callback for when layer name editing has been canceled */
305 layer_name_editing_canceled_cb (GtkCellRenderer
*renderer
,
308 /* Put PCB's accelerators back.
310 * XXX: We should not have to do this within a simple widget,
311 * and this quick hack workaround breaks the widget's
312 * abstraction from the rest of the application :(
314 ghid_install_accel_groups (GTK_WINDOW (gport
->top_window
), ghidgui
);
317 /*! \brief Callback for when a layer name has been edited */
319 layer_name_edited_cb (GtkCellRendererText
*renderer
,
324 GHidLayerSelector
*ls
= user_data
;
328 /* Put PCB's accelerators back.
330 * XXX: We should not have to do this within a simple widget,
331 * and this quick hack workaround breaks the widget's
332 * abstraction from the rest of the application :(
334 ghid_install_accel_groups (GTK_WINDOW (gport
->top_window
), ghidgui
);
336 if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (ls
->list_store
), &iter
, path
))
339 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
),
341 USER_ID_COL
, &user_id
,
344 g_signal_emit (ls
, ghid_layer_selector_signals
[RENAME_LAYER_SIGNAL
],
345 0, user_id
, new_text
);
349 /*! \brief Callback for menu actions: sync layer selection list, emit signal */
351 menu_view_cb (GtkToggleAction
*action
, struct _layer
*ldata
)
353 GHidLayerSelector
*ls
;
354 GtkTreeModel
*model
= gtk_tree_row_reference_get_model (ldata
->rref
);
355 GtkTreePath
*path
= gtk_tree_row_reference_get_path (ldata
->rref
);
356 gboolean state
= gtk_toggle_action_get_active (action
);
360 gtk_tree_model_get_iter (model
, &iter
, path
);
361 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
, VISIBLE_COL
, state
, -1);
362 gtk_tree_model_get (model
, &iter
, USER_ID_COL
, &user_id
, -1);
364 ls
= g_object_get_data (G_OBJECT (model
), "layer-selector");
365 g_signal_emit (ls
, ghid_layer_selector_signals
[TOGGLE_LAYER_SIGNAL
],
369 /*! \brief Callback for menu actions: sync layer selection list, emit signal */
371 menu_pick_cb (GtkRadioAction
*action
, struct _layer
*ldata
)
373 /* We only care about the activation signal (as opposed to deactivation).
374 * A row we are /deactivating/ might not even exist anymore! */
375 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action
)))
377 GHidLayerSelector
*ls
;
378 GtkTreeModel
*model
= gtk_tree_row_reference_get_model (ldata
->rref
);
379 GtkTreePath
*path
= gtk_tree_row_reference_get_path (ldata
->rref
);
383 gtk_tree_model_get_iter (model
, &iter
, path
);
384 gtk_tree_model_get (model
, &iter
, USER_ID_COL
, &user_id
, -1);
386 ls
= g_object_get_data (G_OBJECT (model
), "layer-selector");
387 g_signal_handler_block (ls
->selection
, ls
->selection_changed_sig_id
);
388 gtk_tree_selection_select_path (ls
->selection
, path
);
389 g_signal_handler_unblock (ls
->selection
, ls
->selection_changed_sig_id
);
390 g_signal_emit (ls
, ghid_layer_selector_signals
[SELECT_LAYER_SIGNAL
],
396 ghid_layer_selector_init (GHidLayerSelector
*ls
)
399 GtkCellRenderer
*renderer1
;
400 GtkCellRenderer
*renderer2
;
401 GtkTreeViewColumn
*opacity_col
;
402 GtkTreeViewColumn
*name_col
;
404 renderer1
= ghid_cell_renderer_visibility_new ();
405 renderer2
= gtk_cell_renderer_text_new ();
406 g_object_set (renderer2
, "editable-set", TRUE
, NULL
);
407 g_signal_connect (renderer2
, "editing-started",
408 G_CALLBACK (layer_name_editing_started_cb
), ls
);
409 g_signal_connect (renderer2
, "editing-canceled",
410 G_CALLBACK (layer_name_editing_canceled_cb
), ls
);
411 g_signal_connect (renderer2
, "edited",
412 G_CALLBACK (layer_name_edited_cb
), ls
);
414 opacity_col
= gtk_tree_view_column_new_with_attributes ("",
416 "active", VISIBLE_COL
,
419 name_col
= gtk_tree_view_column_new_with_attributes ("",
423 "editable", EDITABLE_COL
,
426 ls
->list_store
= gtk_list_store_new (N_COLS
,
427 /* STRUCT_COL */ G_TYPE_POINTER
,
428 /* USER_ID_COL */ G_TYPE_INT
,
429 /* VISIBLE_COL */ G_TYPE_BOOLEAN
,
430 /* COLOR_COL */ G_TYPE_STRING
,
431 /* TEXT_COL */ G_TYPE_STRING
,
432 /* FONT_COL */ G_TYPE_STRING
,
433 /* EDITABLE_COL */ G_TYPE_BOOLEAN
,
434 /* ACTIVATABLE_COL */ G_TYPE_BOOLEAN
,
435 /* SEPARATOR_COL */ G_TYPE_BOOLEAN
);
437 gtk_tree_view_insert_column (GTK_TREE_VIEW (ls
), opacity_col
, -1);
438 gtk_tree_view_insert_column (GTK_TREE_VIEW (ls
), name_col
, -1);
439 gtk_tree_view_set_model (GTK_TREE_VIEW (ls
), GTK_TREE_MODEL (ls
->list_store
));
440 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ls
), FALSE
);
442 ls
->visibility_column
= opacity_col
;
443 ls
->selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (ls
));
444 ls
->accel_group
= gtk_accel_group_new ();
445 ls
->action_group
= gtk_action_group_new ("LayerSelector");
448 for (i
= 0; i
< 20; ++i
)
449 ls
->accel_available
[i
] = TRUE
;
451 gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (ls
),
452 tree_view_separator_func
,
454 gtk_tree_selection_set_select_function (ls
->selection
, tree_selection_func
,
456 gtk_tree_selection_set_mode (ls
->selection
, GTK_SELECTION_BROWSE
);
458 g_object_set_data (G_OBJECT (ls
->list_store
), "layer-selector", ls
);
459 g_signal_connect (ls
, "button_press_event",
460 G_CALLBACK (button_press_cb
), NULL
);
461 ls
->selection_changed_sig_id
=
462 g_signal_connect (ls
->selection
, "changed",
463 G_CALLBACK (selection_changed_cb
), ls
);
467 ghid_layer_selector_class_init (GHidLayerSelectorClass
*klass
)
469 GObjectClass
*object_class
= (GObjectClass
*) klass
;
471 ghid_layer_selector_signals
[SELECT_LAYER_SIGNAL
] =
472 g_signal_new ("select-layer",
473 G_TYPE_FROM_CLASS (klass
),
474 G_SIGNAL_RUN_FIRST
| G_SIGNAL_ACTION
,
475 G_STRUCT_OFFSET (GHidLayerSelectorClass
, select_layer
),
477 g_cclosure_marshal_VOID__INT
, G_TYPE_NONE
,
479 ghid_layer_selector_signals
[TOGGLE_LAYER_SIGNAL
] =
480 g_signal_new ("toggle-layer",
481 G_TYPE_FROM_CLASS (klass
),
482 G_SIGNAL_RUN_FIRST
| G_SIGNAL_ACTION
,
483 G_STRUCT_OFFSET (GHidLayerSelectorClass
, toggle_layer
),
485 g_cclosure_marshal_VOID__INT
, G_TYPE_NONE
,
487 ghid_layer_selector_signals
[RENAME_LAYER_SIGNAL
] =
488 g_signal_new ("rename-layer",
489 G_TYPE_FROM_CLASS (klass
),
490 G_SIGNAL_RUN_FIRST
| G_SIGNAL_ACTION
,
491 G_STRUCT_OFFSET (GHidLayerSelectorClass
, rename_layer
),
493 g_cclosure_user_marshal_VOID__INT_STRING
, G_TYPE_NONE
,
494 2, G_TYPE_INT
, G_TYPE_STRING
);
496 object_class
->finalize
= ghid_layer_selector_finalize
;
499 /*! \brief Clean up object before garbage collection
502 ghid_layer_selector_finalize (GObject
*object
)
505 GHidLayerSelector
*ls
= (GHidLayerSelector
*) object
;
507 g_object_unref (ls
->accel_group
);
508 g_object_unref (ls
->action_group
);
510 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls
->list_store
), &iter
);
513 struct _layer
*ldata
;
514 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
),
515 &iter
, STRUCT_COL
, &ldata
, -1);
516 free_ldata (ls
, ldata
);
518 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls
->list_store
), &iter
));
520 G_OBJECT_CLASS (ghid_layer_selector_parent_class
)->finalize (object
);
523 /* PUBLIC FUNCTIONS */
525 ghid_layer_selector_get_type (void)
527 static GType ls_type
= 0;
531 const GTypeInfo ls_info
=
533 sizeof (GHidLayerSelectorClass
),
534 NULL
, /* base_init */
535 NULL
, /* base_finalize */
536 (GClassInitFunc
) ghid_layer_selector_class_init
,
537 NULL
, /* class_finalize */
538 NULL
, /* class_data */
539 sizeof (GHidLayerSelector
),
541 (GInstanceInitFunc
) ghid_layer_selector_init
,
544 ls_type
= g_type_register_static (GTK_TYPE_TREE_VIEW
,
553 /*! \brief Create a new GHidLayerSelector
555 * \return a freshly-allocated GHidLayerSelector.
558 ghid_layer_selector_new (void)
560 return GTK_WIDGET (g_object_new (GHID_LAYER_SELECTOR_TYPE
, NULL
));
563 /*! \brief Add a layer to a GHidLayerSelector.
564 * \par Function Description
565 * This function adds an entry to a GHidLayerSelector, which will
566 * appear in the layer-selection list as well as visibility and selection
567 * menus (assuming this is a selectable layer). For the first 20 layers,
568 * keyboard accelerators will be added for selection/visibility toggling.
570 * If the user_id passed already exists in the layer selector, that layer
571 * will have its data overwritten with the new stuff.
573 * \param [in] ls The selector to be acted on
574 * \param [in] user_id An ID used to identify the layer; will be passed to selection/visibility callbacks
575 * \param [in] name The name of the layer; will be used on selector and menus
576 * \param [in] color_string The color of the layer on selector
577 * \param [in] visibile Whether the layer is visible
578 * \param [in] selectable Whether the layer appears in menus and can be selected
579 * \param [in] renameable Whether the layer is renameable
582 ghid_layer_selector_add_layer (GHidLayerSelector
*ls
,
585 const gchar
*color_string
,
590 struct _layer
*new_layer
= NULL
;
591 gchar
*pname
, *vname
;
592 gboolean new_iter
= TRUE
;
593 gboolean last_selectable
= TRUE
;
598 /* Look for existing layer with this ID */
599 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls
->list_store
), &iter
))
603 gboolean this_selectable
;
606 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
),
607 &iter
, USER_ID_COL
, &read_id
,
608 SEPARATOR_COL
, &is_sep
,
609 SELECTABLE_COL
, &this_selectable
, -1);
614 last_selectable
= this_selectable
;
615 if (read_id
== user_id
)
621 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls
->list_store
), &iter
));
623 /* Handle separator addition */
626 if (selectable
!= last_selectable
)
628 /* Add separator between selectable / non-selectable boundaries */
629 gtk_list_store_append (ls
->list_store
, &iter
);
630 gtk_list_store_set (ls
->list_store
, &iter
,
632 SEPARATOR_COL
, TRUE
, -1);
634 /* Create new layer */
635 gtk_list_store_append (ls
->list_store
, &iter
);
639 /* If the row exists, we clear out its ldata to create
640 * a new action, accelerator and menu item. */
641 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
), &iter
,
642 STRUCT_COL
, &new_layer
, -1);
643 free_ldata (ls
, new_layer
);
646 new_layer
= malloc (sizeof (*new_layer
));
648 gtk_list_store_set (ls
->list_store
,
650 STRUCT_COL
, new_layer
,
651 USER_ID_COL
, user_id
,
652 VISIBLE_COL
, visible
,
653 COLOR_COL
, color_string
,
655 FONT_COL
, selectable
? NULL
: "Italic",
656 EDITABLE_COL
, renameable
,
657 SELECTABLE_COL
, selectable
,
658 SEPARATOR_COL
, FALSE
,
661 /* -- Setup new actions -- */
662 vname
= g_strdup_printf ("LayerView%d", ls
->n_actions
);
663 pname
= g_strdup_printf ("LayerPick%d", ls
->n_actions
);
665 /* Create row reference for actions */
666 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (ls
->list_store
), &iter
);
667 new_layer
->rref
= gtk_tree_row_reference_new
668 (GTK_TREE_MODEL (ls
->list_store
), path
);
669 gtk_tree_path_free (path
);
671 /* Create selection action */
674 new_layer
->pick_action
675 = gtk_radio_action_new (pname
, name
, NULL
, NULL
, user_id
);
676 gtk_radio_action_set_group (new_layer
->pick_action
, ls
->radio_group
);
677 ls
->radio_group
= gtk_radio_action_get_group (new_layer
->pick_action
);
680 new_layer
->pick_action
= NULL
;
682 /* Create visibility action */
683 new_layer
->view_action
= gtk_toggle_action_new (vname
, name
, NULL
, NULL
);
684 gtk_toggle_action_set_active (new_layer
->view_action
, visible
);
686 /* Determine keyboard accelerators */
687 for (i
= 0; i
< 20; ++i
)
688 if (ls
->accel_available
[i
])
692 /* Map 1-0 to actions 1-10 (with '0' meaning 10) */
693 gchar
*accel1
= g_strdup_printf ("%s%d",
694 i
< 10 ? "" : "<Alt>",
696 gchar
*accel2
= g_strdup_printf ("<Ctrl>%s%d",
697 i
< 10 ? "" : "<Alt>",
702 GtkAction
*action
= GTK_ACTION (new_layer
->pick_action
);
703 gtk_action_set_accel_group (action
, ls
->accel_group
);
704 gtk_action_group_add_action_with_accel (ls
->action_group
,
707 gtk_action_connect_accelerator (action
);
708 g_signal_connect (G_OBJECT (action
), "activate",
709 G_CALLBACK (menu_pick_cb
), new_layer
);
711 gtk_action_set_accel_group (GTK_ACTION (new_layer
->view_action
),
713 gtk_action_group_add_action_with_accel
714 (ls
->action_group
, GTK_ACTION (new_layer
->view_action
), accel2
);
715 gtk_action_connect_accelerator (GTK_ACTION (new_layer
->view_action
));
716 g_signal_connect (G_OBJECT (new_layer
->view_action
), "activate",
717 G_CALLBACK (menu_view_cb
), new_layer
);
719 ls
->accel_available
[i
] = FALSE
;
720 new_layer
->accel_index
= i
;
726 new_layer
->accel_index
= -1;
728 /* finalize new layer struct */
729 new_layer
->pick_item
= new_layer
->view_item
= NULL
;
738 /*! \brief Install the "Current Layer" menu items for a layer selector
739 * \par Function Description
740 * Takes a menu shell and installs menu items for layer selection in
741 * the shell, at the given position.
743 * \param [in] ls The selector to be acted on
744 * \param [in] shell The menu to install the items in
745 * \param [in] pos The position in the menu to install items
747 * \return the number of items installed
750 ghid_layer_selector_install_pick_items (GHidLayerSelector
*ls
,
751 GtkMenuShell
*shell
, gint pos
)
756 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls
->list_store
), &iter
);
759 struct _layer
*ldata
;
760 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
),
761 &iter
, STRUCT_COL
, &ldata
, -1);
762 if (ldata
&& ldata
->pick_action
)
764 GtkAction
*action
= GTK_ACTION (ldata
->pick_action
);
765 ldata
->pick_item
= gtk_action_create_menu_item (action
);
766 gtk_menu_shell_insert (shell
, ldata
->pick_item
, pos
+ n
);
770 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls
->list_store
), &iter
));
775 /*! \brief Install the "Shown Layers" menu items for a layer selector
776 * \par Function Description
777 * Takes a menu shell and installs menu items for layer selection in
778 * the shell, at the given position.
780 * \param [in] ls The selector to be acted on
781 * \param [in] shell The menu to install the items in
782 * \param [in] pos The position in the menu to install items
784 * \return the number of items installed
787 ghid_layer_selector_install_view_items (GHidLayerSelector
*ls
,
788 GtkMenuShell
*shell
, gint pos
)
793 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls
->list_store
), &iter
);
796 struct _layer
*ldata
;
797 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
),
798 &iter
, STRUCT_COL
, &ldata
, -1);
799 if (ldata
&& ldata
->view_action
)
801 GtkAction
*action
= GTK_ACTION (ldata
->view_action
);
802 ldata
->view_item
= gtk_action_create_menu_item (action
);
803 gtk_menu_shell_insert (shell
, ldata
->view_item
, pos
+ n
);
807 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls
->list_store
), &iter
));
812 /*! \brief Returns the GtkAccelGroup of a layer selector
813 * \par Function Description
815 * \param [in] ls The selector to be acted on
817 * \return the accel group of the selector
820 ghid_layer_selector_get_accel_group (GHidLayerSelector
*ls
)
822 return ls
->accel_group
;
825 /*! \brief used internally */
827 toggle_foreach_func (GtkTreeModel
*model
, GtkTreePath
*path
,
828 GtkTreeIter
*iter
, gpointer data
)
831 GHidLayerSelector
*ls
= g_object_get_data (G_OBJECT (model
),
834 gtk_tree_model_get (model
, iter
, USER_ID_COL
, &id
, -1);
835 if (id
== *(gint
*) data
)
837 toggle_visibility (ls
, iter
, TRUE
);
843 /*! \brief Toggle a layer's visibility
844 * \par Function Description
845 * Toggle the layer indicated by user_id, emitting a layer-toggle signal.
847 * \param [in] ls The selector to be acted on
848 * \param [in] user_id The ID of the layer to be affected
851 ghid_layer_selector_toggle_layer (GHidLayerSelector
*ls
, gint user_id
)
853 gtk_tree_model_foreach (GTK_TREE_MODEL (ls
->list_store
),
854 toggle_foreach_func
, &user_id
);
857 /*! \brief used internally */
859 select_foreach_func (GtkTreeModel
*model
, GtkTreePath
*path
,
860 GtkTreeIter
*iter
, gpointer data
)
863 GHidLayerSelector
*ls
= g_object_get_data (G_OBJECT (model
),
866 gtk_tree_model_get (model
, iter
, USER_ID_COL
, &id
, -1);
867 if (id
== *(gint
*) data
)
869 gtk_tree_selection_select_path (ls
->selection
, path
);
875 /*! \brief Select a layer
876 * \par Function Description
877 * Select the layer indicated by user_id, emitting a layer-select signal.
879 * \param [in] ls The selector to be acted on
880 * \param [in] user_id The ID of the layer to be affected
883 ghid_layer_selector_select_layer (GHidLayerSelector
*ls
, gint user_id
)
885 gtk_tree_model_foreach (GTK_TREE_MODEL (ls
->list_store
),
886 select_foreach_func
, &user_id
);
889 /*! \brief Selects the next visible layer
890 * \par Function Description
891 * Used to ensure hidden layers are not active; if the active layer is
892 * visible, this function is a noop. Otherwise, it will look for the
893 * next layer that IS visible, and select that. Failing that, it will
896 * \param [in] ls The selector to be acted on
898 * \return TRUE on success, FALSE if all selectable layers are hidden
901 ghid_layer_selector_select_next_visible (GHidLayerSelector
*ls
)
904 if (gtk_tree_selection_get_selected (ls
->selection
, NULL
, &iter
))
906 /* Scan forward, looking for selectable iter */
912 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
),
913 &iter
, VISIBLE_COL
, &visible
,
914 SELECTABLE_COL
, &selectable
, -1);
915 if (visible
&& selectable
)
917 gtk_tree_selection_select_iter (ls
->selection
, &iter
);
921 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls
->list_store
), &iter
));
922 /* Move iter to start, and repeat. */
923 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls
->list_store
), &iter
);
929 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
),
930 &iter
, VISIBLE_COL
, &visible
,
931 SELECTABLE_COL
, &selectable
, -1);
932 if (visible
&& selectable
)
934 gtk_tree_selection_select_iter (ls
->selection
, &iter
);
938 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls
->list_store
), &iter
));
939 /* Failing this, just emit a selected signal on the original layer. */
940 selection_changed_cb (ls
->selection
, ls
);
942 /* If we get here, nothing is selectable, so fail. */
946 /*! \brief Makes the selected layer visible
947 * \par Function Description
948 * Used to ensure hidden layers are not active; un-hides the currently
951 * \param [in] ls The selector to be acted on
954 ghid_layer_selector_make_selected_visible (GHidLayerSelector
*ls
)
957 if (gtk_tree_selection_get_selected (ls
->selection
, NULL
, &iter
))
960 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
),
961 &iter
, VISIBLE_COL
, &visible
, -1);
963 toggle_visibility (ls
, &iter
, FALSE
);
967 /*! \brief Sets the colors of all layers in a layer-selector
968 * \par Function Description
969 * Updates the colors of a layer selector via a callback mechanism:
970 * the user_id of each layer is passed to the callback function,
971 * which returns a color string to update the layer's color, or NULL
974 * \param [in] ls The selector to be acted on
975 * \param [in] callback Takes the user_id of the layer and returns a color string
978 ghid_layer_selector_update_colors (GHidLayerSelector
*ls
,
979 const gchar
*(*callback
)(int user_id
))
982 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls
->list_store
), &iter
);
986 const gchar
*new_color
;
987 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
),
988 &iter
, USER_ID_COL
, &user_id
, -1);
989 new_color
= callback (user_id
);
990 if (new_color
!= NULL
)
991 gtk_list_store_set (ls
->list_store
, &iter
, COLOR_COL
, new_color
, -1);
993 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls
->list_store
), &iter
));
996 /*! \brief Deletes layers from a layer selector
997 * \par Function Description
998 * Deletes layers according to a callback function: a return value of TRUE
999 * means delete, FALSE means leave it alone. Do not try to delete all layers
1000 * using this function; with nothing left to select, pcb will likely go into
1001 * an infinite recursion between hid_action() and g_signal().
1003 * Separators will be deleted if the layer AFTER them is deleted.
1005 * \param [in] ls The selector to be acted on
1006 * \param [in] callback Takes the user_id of the layer and returns a boolean
1009 ghid_layer_selector_delete_layers (GHidLayerSelector
*ls
,
1010 gboolean (*callback
)(int user_id
))
1012 GtkTreeIter iter
, last_iter
;
1014 gboolean iter_valid
=
1015 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls
->list_store
), &iter
);
1018 struct _layer
*ldata
;
1019 gboolean sep
, was_sep
= FALSE
;
1022 /* Find next iter to delete */
1025 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
),
1026 &iter
, USER_ID_COL
, &user_id
,
1027 STRUCT_COL
, &ldata
, SEPARATOR_COL
, &sep
, -1);
1028 if (!sep
&& callback (user_id
))
1031 /* save iter in case it's a bad separator */
1036 gtk_tree_model_iter_next (GTK_TREE_MODEL (ls
->list_store
), &iter
);
1041 /* remove preceeding separator */
1043 gtk_list_store_remove (ls
->list_store
, &last_iter
);
1045 /*** remove row ***/
1046 iter_valid
= gtk_list_store_remove (ls
->list_store
, &iter
);
1047 free_ldata (ls
, ldata
);
1053 /*! \brief Sets the visibility toggle-state of all layers
1054 * \par Function Description
1055 * Shows layers according to a callback function: a return value of TRUE
1056 * means show, FALSE means hide.
1058 * \param [in] ls The selector to be acted on
1059 * \param [in] callback Takes the user_id of the layer and returns a boolean
1062 ghid_layer_selector_show_layers (GHidLayerSelector
*ls
,
1063 gboolean (*callback
)(int user_id
))
1066 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls
->list_store
), &iter
);
1069 struct _layer
*ldata
;
1073 gtk_tree_model_get (GTK_TREE_MODEL (ls
->list_store
),
1074 &iter
, USER_ID_COL
, &user_id
,
1076 SEPARATOR_COL
, &sep
, -1);
1078 set_visibility (ls
, &iter
, ldata
, callback (user_id
));
1080 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls
->list_store
), &iter
));