pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00009 #include <glib.h> 00010 #include <glib-object.h> 00011 #include <gdk/gdkkeysyms.h> 00012 #include <gtk/gtk.h> 00013 00014 #include "gtkhid.h" 00015 #include "gui.h" 00016 #include "pcb-printf.h" 00017 00018 #include "ghid-layer-selector.h" 00019 #include "ghid-cell-renderer-visibility.h" 00020 00021 #define INITIAL_ACTION_MAX 40 00022 00023 /* Forward dec'ls */ 00024 struct _layer; 00025 static void ghid_layer_selector_finalize (GObject *object); 00026 static void menu_pick_cb (GtkRadioAction *action, struct _layer *ldata); 00027 00029 enum { 00030 SELECT_LAYER_SIGNAL, 00031 TOGGLE_LAYER_SIGNAL, 00032 RENAME_LAYER_SIGNAL, 00033 LAST_SIGNAL 00034 }; 00035 00037 enum { 00038 STRUCT_COL, 00039 USER_ID_COL, 00040 VISIBLE_COL, 00041 COLOR_COL, 00042 TEXT_COL, 00043 FONT_COL, 00044 EDITABLE_COL, 00045 SELECTABLE_COL, 00046 SEPARATOR_COL, 00047 N_COLS 00048 }; 00049 00050 static GtkTreeView *ghid_layer_selector_parent_class; 00051 static guint ghid_layer_selector_signals[LAST_SIGNAL] = { 0 }; 00052 00053 struct _GHidLayerSelector 00054 { 00055 GtkTreeView parent; 00056 00057 GtkListStore *list_store; 00058 GtkTreeSelection *selection; 00059 GtkTreeViewColumn *visibility_column; 00060 00061 GtkActionGroup *action_group; 00062 GtkAccelGroup *accel_group; 00063 00064 GSList *radio_group; 00065 int n_actions; 00066 00067 gboolean accel_available[20]; 00068 00069 gulong selection_changed_sig_id; 00070 }; 00071 00072 struct _GHidLayerSelectorClass 00073 { 00074 GtkTreeViewClass parent_class; 00075 00076 void (* select_layer) (GHidLayerSelector *, gint); 00077 void (* toggle_layer) (GHidLayerSelector *, gint); 00078 void (* rename_layer) (GHidLayerSelector *, gint, gchar *); 00079 }; 00080 00081 struct _layer 00082 { 00083 gint accel_index; /* Index into ls->accel_available */ 00084 GtkWidget *pick_item; 00085 GtkWidget *view_item; 00086 GtkToggleAction *view_action; 00087 GtkRadioAction *pick_action; 00088 GtkTreeRowReference *rref; 00089 }; 00090 00091 static void 00092 g_cclosure_user_marshal_VOID__INT_STRING (GClosure *closure, 00093 GValue *return_value G_GNUC_UNUSED, 00094 guint n_param_values, 00095 const GValue *param_values, 00096 gpointer invocation_hint G_GNUC_UNUSED, 00097 gpointer marshal_data) 00098 { 00099 typedef void (*GMarshalFunc_VOID__INT_STRING) (gpointer data1, 00100 gint arg_1, 00101 gpointer arg_2, 00102 gpointer data2); 00103 register GMarshalFunc_VOID__INT_STRING callback; 00104 register GCClosure *cc = (GCClosure*) closure; 00105 register gpointer data1, data2; 00106 00107 g_return_if_fail (n_param_values == 3); 00108 00109 if (G_CCLOSURE_SWAP_DATA (closure)) 00110 { 00111 data1 = closure->data; 00112 data2 = g_value_peek_pointer (param_values + 0); 00113 } 00114 else 00115 { 00116 data1 = g_value_peek_pointer (param_values + 0); 00117 data2 = closure->data; 00118 } 00119 callback = (GMarshalFunc_VOID__INT_STRING) (marshal_data ? marshal_data : cc->callback); 00120 00121 callback (data1, 00122 g_value_get_int (param_values + 1), 00123 (char *)g_value_get_string (param_values + 2), 00124 data2); 00125 } 00126 00128 static void 00129 free_ldata (GHidLayerSelector *ls, struct _layer *ldata) 00130 { 00131 if (ldata->pick_action) 00132 { 00133 gtk_action_disconnect_accelerator 00134 (GTK_ACTION (ldata->pick_action)); 00135 gtk_action_group_remove_action (ls->action_group, 00136 GTK_ACTION (ldata->pick_action)); 00137 /* TODO: make this work without wrecking the radio action group 00138 * g_object_unref (G_OBJECT (ldata->pick_action)); 00139 * */ 00140 } 00141 if (ldata->view_action) 00142 { 00143 gtk_action_disconnect_accelerator 00144 (GTK_ACTION (ldata->view_action)); 00145 gtk_action_group_remove_action (ls->action_group, 00146 GTK_ACTION (ldata->view_action)); 00147 g_object_unref (G_OBJECT (ldata->view_action)); 00148 } 00149 gtk_tree_row_reference_free (ldata->rref); 00150 if (ldata->accel_index >= 0) 00151 ls->accel_available[ldata->accel_index] = TRUE; 00152 g_free (ldata); 00153 00154 } 00155 00157 static void 00158 set_visibility (GHidLayerSelector *ls, GtkTreeIter *iter, 00159 struct _layer *ldata, gboolean state) 00160 { 00161 gtk_list_store_set (ls->list_store, iter, VISIBLE_COL, state, -1); 00162 00163 if (ldata) 00164 { 00165 gtk_action_block_activate (GTK_ACTION (ldata->view_action)); 00166 gtk_check_menu_item_set_active 00167 (GTK_CHECK_MENU_ITEM (ldata->view_item), state); 00168 gtk_action_unblock_activate (GTK_ACTION (ldata->view_action)); 00169 } 00170 } 00171 00181 static void 00182 toggle_visibility (GHidLayerSelector *ls, GtkTreeIter *iter, gboolean emit) 00183 { 00184 gint user_id; 00185 struct _layer *ldata; 00186 gboolean toggle; 00187 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), iter, 00188 USER_ID_COL, &user_id, VISIBLE_COL, &toggle, 00189 STRUCT_COL, &ldata, -1); 00190 set_visibility (ls, iter, ldata, !toggle); 00191 if (emit) 00192 g_signal_emit (ls, ghid_layer_selector_signals[TOGGLE_LAYER_SIGNAL], 00193 0, user_id); 00194 } 00195 00197 static gboolean 00198 tree_view_separator_func (GtkTreeModel *model, GtkTreeIter *iter, 00199 gpointer data) 00200 { 00201 gboolean ret_val; 00202 gtk_tree_model_get (model, iter, SEPARATOR_COL, &ret_val, -1); 00203 return ret_val; 00204 } 00205 00207 static gboolean 00208 tree_selection_func (GtkTreeSelection *selection, GtkTreeModel *model, 00209 GtkTreePath *path, gboolean selected, gpointer data) 00210 { 00211 GtkTreeIter iter; 00212 00213 if (gtk_tree_model_get_iter (model, &iter, path)) 00214 { 00215 gboolean selectable; 00216 gtk_tree_model_get (model, &iter, SELECTABLE_COL, &selectable, -1); 00217 return selectable; 00218 } 00219 00220 return FALSE; 00221 } 00222 00223 /* SIGNAL HANDLERS */ 00225 static gboolean 00226 button_press_cb (GHidLayerSelector *ls, GdkEventButton *event) 00227 { 00228 /* Handle visibility independently to prevent changing the active 00229 * layer, which will happen if we let this event propagate. */ 00230 GtkTreeViewColumn *column; 00231 GtkTreePath *path; 00232 00233 /* Ignore the synthetic presses caused by double and tripple clicks, and 00234 * also ignore all but left-clicks 00235 */ 00236 if (event->type != GDK_BUTTON_PRESS || 00237 event->button != 1) 00238 return TRUE; 00239 00240 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (ls), 00241 event->x, event->y, 00242 &path, &column, NULL, NULL)) 00243 { 00244 GtkTreeIter iter; 00245 gboolean selectable; 00246 gboolean separator; 00247 gtk_tree_model_get_iter (GTK_TREE_MODEL (ls->list_store), &iter, path); 00248 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), &iter, 00249 SELECTABLE_COL, &selectable, 00250 SEPARATOR_COL, &separator, -1); 00251 /* Toggle visibility for non-selectable layers no matter 00252 * where you click. */ 00253 if (!separator && (column == ls->visibility_column || !selectable)) 00254 { 00255 toggle_visibility (ls, &iter, TRUE); 00256 return TRUE; 00257 } 00258 } 00259 return FALSE; 00260 } 00261 00263 static void 00264 selection_changed_cb (GtkTreeSelection *selection, GHidLayerSelector *ls) 00265 { 00266 GtkTreeIter iter; 00267 if (gtk_tree_selection_get_selected (selection, NULL, &iter)) 00268 { 00269 gint user_id; 00270 struct _layer *ldata; 00271 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), &iter, 00272 STRUCT_COL, &ldata, USER_ID_COL, &user_id, -1); 00273 00274 if (ldata && ldata->pick_action) 00275 { 00276 gtk_action_block_activate (GTK_ACTION (ldata->pick_action)); 00277 gtk_radio_action_set_current_value (ldata->pick_action, user_id); 00278 gtk_action_unblock_activate (GTK_ACTION (ldata->pick_action)); 00279 } 00280 g_signal_emit (ls, ghid_layer_selector_signals[SELECT_LAYER_SIGNAL], 00281 0, user_id); 00282 } 00283 } 00284 00286 static void 00287 layer_name_editing_started_cb (GtkCellRenderer *renderer, 00288 GtkCellEditable *editable, 00289 gchar *path, 00290 gpointer user_data) 00291 { 00292 /* When editing begins, we need to detach PCB's accelerators 00293 * so they don't steal all the user's keystrokes. 00294 * 00295 * XXX: We should not have to do this within a simple widget, 00296 * 00297 * and this quick hack workaround breaks the widget's 00298 * abstraction from the rest of the application :( 00299 */ 00300 ghid_remove_accel_groups (GTK_WINDOW (gport->top_window), ghidgui); 00301 } 00302 00304 static void 00305 layer_name_editing_canceled_cb (GtkCellRenderer *renderer, 00306 gpointer user_data) 00307 { 00308 /* Put PCB's accelerators back. 00309 * 00310 * XXX: We should not have to do this within a simple widget, 00311 * and this quick hack workaround breaks the widget's 00312 * abstraction from the rest of the application :( 00313 */ 00314 ghid_install_accel_groups (GTK_WINDOW (gport->top_window), ghidgui); 00315 } 00316 00318 static void 00319 layer_name_edited_cb (GtkCellRendererText *renderer, 00320 gchar *path, 00321 gchar *new_text, 00322 gpointer user_data) 00323 { 00324 GHidLayerSelector *ls = user_data; 00325 GtkTreeIter iter; 00326 int user_id; 00327 00328 /* Put PCB's accelerators back. 00329 * 00330 * XXX: We should not have to do this within a simple widget, 00331 * and this quick hack workaround breaks the widget's 00332 * abstraction from the rest of the application :( 00333 */ 00334 ghid_install_accel_groups (GTK_WINDOW (gport->top_window), ghidgui); 00335 00336 if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (ls->list_store), &iter, path)) 00337 return; 00338 00339 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), 00340 &iter, 00341 USER_ID_COL, &user_id, 00342 -1); 00343 00344 g_signal_emit (ls, ghid_layer_selector_signals[RENAME_LAYER_SIGNAL], 00345 0, user_id, new_text); 00346 } 00347 00348 00350 static void 00351 menu_view_cb (GtkToggleAction *action, struct _layer *ldata) 00352 { 00353 GHidLayerSelector *ls; 00354 GtkTreeModel *model = gtk_tree_row_reference_get_model (ldata->rref); 00355 GtkTreePath *path = gtk_tree_row_reference_get_path (ldata->rref); 00356 gboolean state = gtk_toggle_action_get_active (action); 00357 GtkTreeIter iter; 00358 gint user_id; 00359 00360 gtk_tree_model_get_iter (model, &iter, path); 00361 gtk_list_store_set (GTK_LIST_STORE (model), &iter, VISIBLE_COL, state, -1); 00362 gtk_tree_model_get (model, &iter, USER_ID_COL, &user_id, -1); 00363 00364 ls = g_object_get_data (G_OBJECT (model), "layer-selector"); 00365 g_signal_emit (ls, ghid_layer_selector_signals[TOGGLE_LAYER_SIGNAL], 00366 0, user_id); 00367 } 00368 00370 static void 00371 menu_pick_cb (GtkRadioAction *action, struct _layer *ldata) 00372 { 00373 /* We only care about the activation signal (as opposed to deactivation). 00374 * A row we are /deactivating/ might not even exist anymore! */ 00375 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) 00376 { 00377 GHidLayerSelector *ls; 00378 GtkTreeModel *model = gtk_tree_row_reference_get_model (ldata->rref); 00379 GtkTreePath *path = gtk_tree_row_reference_get_path (ldata->rref); 00380 GtkTreeIter iter; 00381 gint user_id; 00382 00383 gtk_tree_model_get_iter (model, &iter, path); 00384 gtk_tree_model_get (model, &iter, USER_ID_COL, &user_id, -1); 00385 00386 ls = g_object_get_data (G_OBJECT (model), "layer-selector"); 00387 g_signal_handler_block (ls->selection, ls->selection_changed_sig_id); 00388 gtk_tree_selection_select_path (ls->selection, path); 00389 g_signal_handler_unblock (ls->selection, ls->selection_changed_sig_id); 00390 g_signal_emit (ls, ghid_layer_selector_signals[SELECT_LAYER_SIGNAL], 00391 0, user_id); 00392 } 00393 } 00394 00395 static void 00396 ghid_layer_selector_init (GHidLayerSelector *ls) 00397 { 00398 int i; 00399 GtkCellRenderer *renderer1; 00400 GtkCellRenderer *renderer2; 00401 GtkTreeViewColumn *opacity_col; 00402 GtkTreeViewColumn *name_col; 00403 00404 renderer1 = ghid_cell_renderer_visibility_new (); 00405 renderer2 = gtk_cell_renderer_text_new (); 00406 g_object_set (renderer2, "editable-set", TRUE, NULL); 00407 g_signal_connect (renderer2, "editing-started", 00408 G_CALLBACK (layer_name_editing_started_cb), ls); 00409 g_signal_connect (renderer2, "editing-canceled", 00410 G_CALLBACK (layer_name_editing_canceled_cb), ls); 00411 g_signal_connect (renderer2, "edited", 00412 G_CALLBACK (layer_name_edited_cb), ls); 00413 00414 opacity_col = gtk_tree_view_column_new_with_attributes ("", 00415 renderer1, 00416 "active", VISIBLE_COL, 00417 "color", COLOR_COL, 00418 NULL); 00419 name_col = gtk_tree_view_column_new_with_attributes ("", 00420 renderer2, 00421 "text", TEXT_COL, 00422 "font", FONT_COL, 00423 "editable", EDITABLE_COL, 00424 NULL); 00425 00426 ls->list_store = gtk_list_store_new (N_COLS, 00427 /* STRUCT_COL */ G_TYPE_POINTER, 00428 /* USER_ID_COL */ G_TYPE_INT, 00429 /* VISIBLE_COL */ G_TYPE_BOOLEAN, 00430 /* COLOR_COL */ G_TYPE_STRING, 00431 /* TEXT_COL */ G_TYPE_STRING, 00432 /* FONT_COL */ G_TYPE_STRING, 00433 /* EDITABLE_COL */ G_TYPE_BOOLEAN, 00434 /* ACTIVATABLE_COL */ G_TYPE_BOOLEAN, 00435 /* SEPARATOR_COL */ G_TYPE_BOOLEAN); 00436 00437 gtk_tree_view_insert_column (GTK_TREE_VIEW (ls), opacity_col, -1); 00438 gtk_tree_view_insert_column (GTK_TREE_VIEW (ls), name_col, -1); 00439 gtk_tree_view_set_model (GTK_TREE_VIEW (ls), GTK_TREE_MODEL (ls->list_store)); 00440 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ls), FALSE); 00441 00442 ls->visibility_column = opacity_col; 00443 ls->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ls)); 00444 ls->accel_group = gtk_accel_group_new (); 00445 ls->action_group = gtk_action_group_new ("LayerSelector"); 00446 ls->n_actions = 0; 00447 00448 for (i = 0; i < 20; ++i) 00449 ls->accel_available[i] = TRUE; 00450 00451 gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (ls), 00452 tree_view_separator_func, 00453 NULL, NULL); 00454 gtk_tree_selection_set_select_function (ls->selection, tree_selection_func, 00455 NULL, NULL); 00456 gtk_tree_selection_set_mode (ls->selection, GTK_SELECTION_BROWSE); 00457 00458 g_object_set_data (G_OBJECT (ls->list_store), "layer-selector", ls); 00459 g_signal_connect (ls, "button_press_event", 00460 G_CALLBACK (button_press_cb), NULL); 00461 ls->selection_changed_sig_id = 00462 g_signal_connect (ls->selection, "changed", 00463 G_CALLBACK (selection_changed_cb), ls); 00464 } 00465 00466 static void 00467 ghid_layer_selector_class_init (GHidLayerSelectorClass *klass) 00468 { 00469 GObjectClass *object_class = (GObjectClass *) klass; 00470 00471 ghid_layer_selector_signals[SELECT_LAYER_SIGNAL] = 00472 g_signal_new ("select-layer", 00473 G_TYPE_FROM_CLASS (klass), 00474 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, 00475 G_STRUCT_OFFSET (GHidLayerSelectorClass, select_layer), 00476 NULL, NULL, 00477 g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 00478 1, G_TYPE_INT); 00479 ghid_layer_selector_signals[TOGGLE_LAYER_SIGNAL] = 00480 g_signal_new ("toggle-layer", 00481 G_TYPE_FROM_CLASS (klass), 00482 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, 00483 G_STRUCT_OFFSET (GHidLayerSelectorClass, toggle_layer), 00484 NULL, NULL, 00485 g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 00486 1, G_TYPE_INT); 00487 ghid_layer_selector_signals[RENAME_LAYER_SIGNAL] = 00488 g_signal_new ("rename-layer", 00489 G_TYPE_FROM_CLASS (klass), 00490 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, 00491 G_STRUCT_OFFSET (GHidLayerSelectorClass, rename_layer), 00492 NULL, NULL, 00493 g_cclosure_user_marshal_VOID__INT_STRING, G_TYPE_NONE, 00494 2, G_TYPE_INT, G_TYPE_STRING); 00495 00496 object_class->finalize = ghid_layer_selector_finalize; 00497 } 00498 00501 static void 00502 ghid_layer_selector_finalize (GObject *object) 00503 { 00504 GtkTreeIter iter; 00505 GHidLayerSelector *ls = (GHidLayerSelector *) object; 00506 00507 g_object_unref (ls->accel_group); 00508 g_object_unref (ls->action_group); 00509 00510 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls->list_store), &iter); 00511 do 00512 { 00513 struct _layer *ldata; 00514 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), 00515 &iter, STRUCT_COL, &ldata, -1); 00516 free_ldata (ls, ldata); 00517 } 00518 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter)); 00519 00520 G_OBJECT_CLASS (ghid_layer_selector_parent_class)->finalize (object); 00521 } 00522 00523 /* PUBLIC FUNCTIONS */ 00524 GType 00525 ghid_layer_selector_get_type (void) 00526 { 00527 static GType ls_type = 0; 00528 00529 if (!ls_type) 00530 { 00531 const GTypeInfo ls_info = 00532 { 00533 sizeof (GHidLayerSelectorClass), 00534 NULL, /* base_init */ 00535 NULL, /* base_finalize */ 00536 (GClassInitFunc) ghid_layer_selector_class_init, 00537 NULL, /* class_finalize */ 00538 NULL, /* class_data */ 00539 sizeof (GHidLayerSelector), 00540 0, /* n_preallocs */ 00541 (GInstanceInitFunc) ghid_layer_selector_init, 00542 }; 00543 00544 ls_type = g_type_register_static (GTK_TYPE_TREE_VIEW, 00545 "GHidLayerSelector", 00546 &ls_info, 00547 0); 00548 } 00549 00550 return ls_type; 00551 } 00552 00557 GtkWidget * 00558 ghid_layer_selector_new (void) 00559 { 00560 return GTK_WIDGET (g_object_new (GHID_LAYER_SELECTOR_TYPE, NULL)); 00561 } 00562 00581 void 00582 ghid_layer_selector_add_layer (GHidLayerSelector *ls, 00583 gint user_id, 00584 const gchar *name, 00585 const gchar *color_string, 00586 gboolean visible, 00587 gboolean selectable, 00588 gboolean renameable) 00589 { 00590 struct _layer *new_layer = NULL; 00591 gchar *pname, *vname; 00592 gboolean new_iter = TRUE; 00593 gboolean last_selectable = TRUE; 00594 GtkTreePath *path; 00595 GtkTreeIter iter; 00596 int i; 00597 00598 /* Look for existing layer with this ID */ 00599 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls->list_store), &iter)) 00600 do 00601 { 00602 gboolean is_sep; 00603 gboolean this_selectable; 00604 gint read_id; 00605 00606 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), 00607 &iter, USER_ID_COL, &read_id, 00608 SEPARATOR_COL, &is_sep, 00609 SELECTABLE_COL, &this_selectable, -1); 00610 00611 if (is_sep) 00612 continue; 00613 00614 last_selectable = this_selectable; 00615 if (read_id == user_id) 00616 { 00617 new_iter = FALSE; 00618 break; 00619 } 00620 } 00621 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter)); 00622 00623 /* Handle separator addition */ 00624 if (new_iter) 00625 { 00626 if (selectable != last_selectable) 00627 { 00628 /* Add separator between selectable / non-selectable boundaries */ 00629 gtk_list_store_append (ls->list_store, &iter); 00630 gtk_list_store_set (ls->list_store, &iter, 00631 STRUCT_COL, NULL, 00632 SEPARATOR_COL, TRUE, -1); 00633 } 00634 /* Create new layer */ 00635 gtk_list_store_append (ls->list_store, &iter); 00636 } 00637 else 00638 { 00639 /* If the row exists, we clear out its ldata to create 00640 * a new action, accelerator and menu item. */ 00641 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), &iter, 00642 STRUCT_COL, &new_layer, -1); 00643 free_ldata (ls, new_layer); 00644 } 00645 00646 new_layer = g_malloc (sizeof (*new_layer)); 00647 00648 gtk_list_store_set (ls->list_store, 00649 &iter, 00650 STRUCT_COL, new_layer, 00651 USER_ID_COL, user_id, 00652 VISIBLE_COL, visible, 00653 COLOR_COL, color_string, 00654 TEXT_COL, name, 00655 FONT_COL, selectable ? NULL : "Italic", 00656 EDITABLE_COL, renameable, 00657 SELECTABLE_COL, selectable, 00658 SEPARATOR_COL, FALSE, 00659 -1); 00660 00661 /* -- Setup new actions -- */ 00662 vname = g_strdup_printf ("LayerView%d", ls->n_actions); 00663 pname = g_strdup_printf ("LayerPick%d", ls->n_actions); 00664 00665 /* Create row reference for actions */ 00666 path = gtk_tree_model_get_path (GTK_TREE_MODEL (ls->list_store), &iter); 00667 new_layer->rref = gtk_tree_row_reference_new 00668 (GTK_TREE_MODEL (ls->list_store), path); 00669 gtk_tree_path_free (path); 00670 00671 /* Create selection action */ 00672 if (selectable) 00673 { 00674 new_layer->pick_action 00675 = gtk_radio_action_new (pname, name, NULL, NULL, user_id); 00676 gtk_radio_action_set_group (new_layer->pick_action, ls->radio_group); 00677 ls->radio_group = gtk_radio_action_get_group (new_layer->pick_action); 00678 } 00679 else 00680 new_layer->pick_action = NULL; 00681 00682 /* Create visibility action */ 00683 new_layer->view_action = gtk_toggle_action_new (vname, name, NULL, NULL); 00684 gtk_toggle_action_set_active (new_layer->view_action, visible); 00685 00686 /* Determine keyboard accelerators */ 00687 for (i = 0; i < 20; ++i) 00688 if (ls->accel_available[i]) 00689 break; 00690 if (i < 20) 00691 { 00692 /* Map 1-0 to actions 1-10 (with '0' meaning 10) */ 00693 gchar *accel1 = g_strdup_printf ("%s%d", 00694 i < 10 ? "" : "<Alt>", 00695 (i + 1) % 10); 00696 gchar *accel2 = g_strdup_printf ("<Ctrl>%s%d", 00697 i < 10 ? "" : "<Alt>", 00698 (i + 1) % 10); 00699 00700 if (selectable) 00701 { 00702 GtkAction *action = GTK_ACTION (new_layer->pick_action); 00703 gtk_action_set_accel_group (action, ls->accel_group); 00704 gtk_action_group_add_action_with_accel (ls->action_group, 00705 action, 00706 accel1); 00707 gtk_action_connect_accelerator (action); 00708 g_signal_connect (G_OBJECT (action), "activate", 00709 G_CALLBACK (menu_pick_cb), new_layer); 00710 } 00711 gtk_action_set_accel_group (GTK_ACTION (new_layer->view_action), 00712 ls->accel_group); 00713 gtk_action_group_add_action_with_accel 00714 (ls->action_group, GTK_ACTION (new_layer->view_action), accel2); 00715 gtk_action_connect_accelerator (GTK_ACTION (new_layer->view_action)); 00716 g_signal_connect (G_OBJECT (new_layer->view_action), "activate", 00717 G_CALLBACK (menu_view_cb), new_layer); 00718 00719 ls->accel_available[i] = FALSE; 00720 new_layer->accel_index = i; 00721 g_free (accel2); 00722 g_free (accel1); 00723 } 00724 else 00725 { 00726 new_layer->accel_index = -1; 00727 } 00728 /* finalize new layer struct */ 00729 new_layer->pick_item = new_layer->view_item = NULL; 00730 00731 /* cleanup */ 00732 g_free (vname); 00733 g_free (pname); 00734 00735 ls->n_actions++; 00736 } 00737 00749 gint 00750 ghid_layer_selector_install_pick_items (GHidLayerSelector *ls, 00751 GtkMenuShell *shell, gint pos) 00752 { 00753 GtkTreeIter iter; 00754 int n = 0; 00755 00756 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls->list_store), &iter); 00757 do 00758 { 00759 struct _layer *ldata; 00760 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), 00761 &iter, STRUCT_COL, &ldata, -1); 00762 if (ldata && ldata->pick_action) 00763 { 00764 GtkAction *action = GTK_ACTION (ldata->pick_action); 00765 ldata->pick_item = gtk_action_create_menu_item (action); 00766 gtk_menu_shell_insert (shell, ldata->pick_item, pos + n); 00767 ++n; 00768 } 00769 } 00770 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter)); 00771 00772 return n; 00773 } 00774 00786 gint 00787 ghid_layer_selector_install_view_items (GHidLayerSelector *ls, 00788 GtkMenuShell *shell, gint pos) 00789 { 00790 GtkTreeIter iter; 00791 int n = 0; 00792 00793 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls->list_store), &iter); 00794 do 00795 { 00796 struct _layer *ldata; 00797 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), 00798 &iter, STRUCT_COL, &ldata, -1); 00799 if (ldata && ldata->view_action) 00800 { 00801 GtkAction *action = GTK_ACTION (ldata->view_action); 00802 ldata->view_item = gtk_action_create_menu_item (action); 00803 gtk_menu_shell_insert (shell, ldata->view_item, pos + n); 00804 ++n; 00805 } 00806 } 00807 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter)); 00808 00809 return n; 00810 } 00811 00819 GtkAccelGroup * 00820 ghid_layer_selector_get_accel_group (GHidLayerSelector *ls) 00821 { 00822 return ls->accel_group; 00823 } 00824 00825 struct layer_data { 00826 GHidLayerSelector *ls; 00827 gint user_id; 00828 }; 00829 00831 static gboolean 00832 toggle_foreach_func (GtkTreeModel *model, GtkTreePath *path, 00833 GtkTreeIter *iter, gpointer user_data) 00834 { 00835 struct layer_data *data = (struct layer_data *) user_data; 00836 gint id; 00837 00838 gtk_tree_model_get (model, iter, USER_ID_COL, &id, -1); 00839 if (id == data->user_id) 00840 { 00841 toggle_visibility (data->ls, iter, TRUE); 00842 return TRUE; 00843 } 00844 return FALSE; 00845 } 00846 00854 void 00855 ghid_layer_selector_toggle_layer (GHidLayerSelector *ls, gint user_id) 00856 { 00857 struct layer_data data; 00858 00859 data.ls = ls; 00860 data.user_id = user_id; 00861 00862 gtk_tree_model_foreach (GTK_TREE_MODEL (ls->list_store), 00863 toggle_foreach_func, &data); 00864 } 00865 00867 static gboolean 00868 select_foreach_func (GtkTreeModel *model, GtkTreePath *path, 00869 GtkTreeIter *iter, gpointer user_data) 00870 { 00871 struct layer_data *data = (struct layer_data *) user_data; 00872 gint id; 00873 00874 gtk_tree_model_get (model, iter, USER_ID_COL, &id, -1); 00875 if (id == data->user_id) 00876 { 00877 gtk_tree_selection_select_path (data->ls->selection, path); 00878 return TRUE; 00879 } 00880 return FALSE; 00881 } 00882 00890 void 00891 ghid_layer_selector_select_layer (GHidLayerSelector *ls, gint user_id) 00892 { 00893 struct layer_data data; 00894 00895 data.ls = ls; 00896 data.user_id = user_id; 00897 00898 gtk_tree_model_foreach (GTK_TREE_MODEL (ls->list_store), 00899 select_foreach_func, &data); 00900 } 00901 00913 gboolean 00914 ghid_layer_selector_select_next_visible (GHidLayerSelector *ls) 00915 { 00916 GtkTreeIter iter; 00917 if (gtk_tree_selection_get_selected (ls->selection, NULL, &iter)) 00918 { 00919 /* Scan forward, looking for selectable iter */ 00920 do 00921 { 00922 gboolean visible; 00923 gboolean selectable; 00924 00925 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), 00926 &iter, VISIBLE_COL, &visible, 00927 SELECTABLE_COL, &selectable, -1); 00928 if (visible && selectable) 00929 { 00930 gtk_tree_selection_select_iter (ls->selection, &iter); 00931 return TRUE; 00932 } 00933 } 00934 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter)); 00935 /* Move iter to start, and repeat. */ 00936 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls->list_store), &iter); 00937 do 00938 { 00939 gboolean visible; 00940 gboolean selectable; 00941 00942 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), 00943 &iter, VISIBLE_COL, &visible, 00944 SELECTABLE_COL, &selectable, -1); 00945 if (visible && selectable) 00946 { 00947 gtk_tree_selection_select_iter (ls->selection, &iter); 00948 return TRUE; 00949 } 00950 } 00951 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter)); 00952 /* Failing this, just emit a selected signal on the original layer. */ 00953 selection_changed_cb (ls->selection, ls); 00954 } 00955 /* If we get here, nothing is selectable, so fail. */ 00956 return FALSE; 00957 } 00958 00966 void 00967 ghid_layer_selector_make_selected_visible (GHidLayerSelector *ls) 00968 { 00969 GtkTreeIter iter; 00970 if (gtk_tree_selection_get_selected (ls->selection, NULL, &iter)) 00971 { 00972 gboolean visible; 00973 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), 00974 &iter, VISIBLE_COL, &visible, -1); 00975 if (!visible) 00976 toggle_visibility (ls, &iter, FALSE); 00977 } 00978 } 00979 00990 void 00991 ghid_layer_selector_update_colors (GHidLayerSelector *ls, 00992 const gchar *(*callback)(int user_id)) 00993 { 00994 GtkTreeIter iter; 00995 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls->list_store), &iter); 00996 do 00997 { 00998 gint user_id; 00999 const gchar *new_color; 01000 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), 01001 &iter, USER_ID_COL, &user_id, -1); 01002 new_color = callback (user_id); 01003 if (new_color != NULL) 01004 gtk_list_store_set (ls->list_store, &iter, COLOR_COL, new_color, -1); 01005 } 01006 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter)); 01007 } 01008 01021 void 01022 ghid_layer_selector_delete_layers (GHidLayerSelector *ls, 01023 gboolean (*callback)(int user_id)) 01024 { 01025 GtkTreeIter iter, last_iter; 01026 01027 gboolean iter_valid = 01028 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls->list_store), &iter); 01029 while (iter_valid) 01030 { 01031 struct _layer *ldata; 01032 gboolean sep, was_sep = FALSE; 01033 gint user_id; 01034 01035 /* Find next iter to delete */ 01036 while (iter_valid) 01037 { 01038 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), 01039 &iter, USER_ID_COL, &user_id, 01040 STRUCT_COL, &ldata, SEPARATOR_COL, &sep, -1); 01041 if (!sep && callback (user_id)) 01042 break; 01043 01044 /* save iter in case it's a bad separator */ 01045 was_sep = sep; 01046 last_iter = iter; 01047 /* iterate */ 01048 iter_valid = 01049 gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter); 01050 } 01051 01052 if (iter_valid) 01053 { 01054 /* remove preceeding separator */ 01055 if (was_sep) 01056 gtk_list_store_remove (ls->list_store, &last_iter); 01057 01058 /*** remove row ***/ 01059 iter_valid = gtk_list_store_remove (ls->list_store, &iter); 01060 free_ldata (ls, ldata); 01061 } 01062 last_iter = iter; 01063 } 01064 } 01065 01074 void 01075 ghid_layer_selector_show_layers (GHidLayerSelector *ls, 01076 gboolean (*callback)(int user_id)) 01077 { 01078 GtkTreeIter iter; 01079 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls->list_store), &iter); 01080 do 01081 { 01082 struct _layer *ldata; 01083 gboolean sep; 01084 gint user_id; 01085 01086 gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), 01087 &iter, USER_ID_COL, &user_id, 01088 STRUCT_COL, &ldata, 01089 SEPARATOR_COL, &sep, -1); 01090 if (!sep) 01091 set_visibility (ls, &iter, ldata, callback (user_id)); 01092 } 01093 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter)); 01094 } 01095